from typing import ClassVar
from typing import Any
from uuid import UUID

from ninja import ModelSchema, Schema
from pydantic import field_validator
from pydantic.types import NonNegativeInt, PositiveInt

from apps.campaign.models import Campaign


class CampaignTargeting(ModelSchema):
    class Meta:
        model = Campaign
        fields: ClassVar[tuple[str]] = (
            Campaign.gender.field.name,
            Campaign.age_from.field.name,
            Campaign.age_to.field.name,
            Campaign.location.field.name,
        )
        fields_optional = "__all__"


class CampaignOut(ModelSchema):
    campaign_id: UUID
    advertiser_id: UUID
    targeting: CampaignTargeting = None

    class Meta:
        model = Campaign
        fields: ClassVar[tuple[str]] = (
            Campaign.ad_title.field.name,
            Campaign.ad_text.field.name,
            Campaign.ad_image.field.name,
            Campaign.impressions_limit.field.name,
            Campaign.clicks_limit.field.name,
            Campaign.cost_per_impression.field.name,
            Campaign.cost_per_click.field.name,
            Campaign.start_date.field.name,
            Campaign.end_date.field.name,
        )


class CampaignCreateIn(ModelSchema):
    targeting: CampaignTargeting = None

    class Meta:
        model = Campaign
        fields: ClassVar[tuple[str]] = (
            Campaign.ad_title.field.name,
            Campaign.ad_text.field.name,
            Campaign.impressions_limit.field.name,
            Campaign.clicks_limit.field.name,
            Campaign.cost_per_impression.field.name,
            Campaign.cost_per_click.field.name,
            Campaign.start_date.field.name,
            Campaign.end_date.field.name,
        )

    @field_validator("targeting", mode="before")
    @classmethod
    def validate_targeting(cls, value: Any) -> Any:
        if (
            not isinstance(value, dict)
            and not isinstance(
                value,
                CampaignTargeting,
            )
            and value
        ):
            err = "The 'targeting' field must be a valid object or null."
            raise ValueError(err)
        return value


class CampaignUpdateIn(ModelSchema):
    targeting: CampaignTargeting = None

    class Meta:
        model = Campaign
        fields: ClassVar[tuple[str]] = (
            Campaign.impressions_limit.field.name,
            Campaign.clicks_limit.field.name,
            Campaign.ad_title.field.name,
            Campaign.ad_text.field.name,
            Campaign.cost_per_impression.field.name,
            Campaign.cost_per_click.field.name,
            Campaign.start_date.field.name,
            Campaign.end_date.field.name,
        )

    @field_validator("targeting", mode="before")
    @classmethod
    def validate_targeting(cls, value: Any) -> Any:
        if (
            not isinstance(value, dict)
            and not isinstance(
                value,
                CampaignTargeting,
            )
            and value
        ):
            err = "The 'targeting' field must be a valid object or null."
            raise ValueError(err)
        return value


class CampaignListFilters(Schema):
    page: PositiveInt = 1
    size: NonNegativeInt = 100
