import uuid
from typing import Any, Dict, List, Callable, Type, Optional, get_args, get_origin
from pydantic import (
    UUID4,
    InstanceOf,
    BaseModel,
    ConfigDict,
    Field,
    create_model,
    field_validator,
    model_validator,
)
from pydantic_core import PydanticCustomError


class ProductProvider(BaseModel):
    """
    Store the minimal client information.
    `data_pipeline` and `destinations` are for composio plug-in.
    (!REFINEME) Create an Enum list for the options.
    (!REFINEME) Create an Enum list for regions.
    """

    id: UUID4 = Field(default_factory=uuid.uuid4, frozen=True)
    name: Optional[str] = Field(default=None, description="client name")
    region: Optional[str] = Field(
        default=None, description="region of client's main business operation"
    )
    data_pipeline: Optional[List[str]] = Field(
        default=None, description="store the data pipelines that the client is using"
    )
    destinations: Optional[List[str]] = Field(
        default=None,
        description="store the destination services that the client is using",
    )

    @field_validator("id", mode="before")
    @classmethod
    def _deny_user_set_id(cls, v: Optional[UUID4]) -> None:
        if v:
            raise PydanticCustomError(
                "may_not_set_field", "This field is not to be set by the user.", {}
            )


class Product(BaseModel):
    """
    Store the product information necessary to the outbound effrots and connect it to the `ProductProvider` instance.
    """

    id: UUID4 = Field(default_factory=uuid.uuid4, frozen=True)
    name: Optional[str] = Field(default=None, description="product name")
    description: Optional[str] = Field(
        default=None,
        max_length=256,
        description="product description scraped from landing url or client input. cascade to the agent",
    )
    provider: Optional[ProductProvider] = Field(default=None)
    audience: Optional[str] = Field(default=None, description="target audience")
    usp: Optional[str] = Field(default=None)
    landing_url: Optional[str] = Field(
        default=None, description="marketing url of the product if any"
    )
    cohort_timeframe: Optional[int] = Field(
        default=30, description="ideal cohort timeframe of the product in days"
    )

    @field_validator("id", mode="before")
    @classmethod
    def _deny_user_set_id(cls, v: Optional[UUID4]) -> None:
        if v:
            raise PydanticCustomError(
                "may_not_set_field", "This field is not to be set by the user.", {}
            )
