import urllib.parse

from abc import ABC, abstractmethod

from maps_adv.adv_store.api.schemas.enums import ResolveUriTargetEnum
from maps_adv.export.lib.core.enum import (
    ActionType,
    CampaignType,
    CreativeType,
)


class BaseFeature(ABC):
    def __init__(
        self,
        min_version: int = 1,
        for_testing_only: bool = False,
    ):
        self.min_version = min_version
        self.for_testing_only = for_testing_only

    @abstractmethod
    def validate(self, campaign) -> bool:
        raise NotImplementedError()

    def invalidate(self, campaign) -> bool:
        return False


class Init(BaseFeature):
    def validate(self, campaign) -> bool:
        return True


class Terminator(BaseFeature):
    def validate(self, campaign) -> bool:
        return False

    def invalidate(self, campaign) -> bool:
        return True


class WithCampaignType(BaseFeature):
    def __init__(self, campaign_type: CampaignType, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._campaign_type = campaign_type

    def validate(self, campaign) -> bool:
        return campaign["campaign_type"] == self._campaign_type


class WithActionType(BaseFeature):
    def __init__(self, action_type: ActionType, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._action_type = action_type

    def validate(self, campaign: dict) -> bool:
        return any(
            map(lambda action: action["type"] == self._action_type, campaign["actions"])
        )


class WithCreativeType(BaseFeature):
    def __init__(self, creative_type: CreativeType, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._creative_type = creative_type

    def validate(self, campaign: dict) -> bool:
        return self._creative_type in campaign["creatives"]


class UserDisplayLimits(BaseFeature):
    def validate(self, campaign) -> bool:
        return bool(
            campaign.get("user_display_limit") is not None
            or campaign.get("user_daily_display_limit") is not None
        )


class HideAdvLabel(BaseFeature):
    def validate(self, campaign) -> bool:
        creatives = campaign["creatives"]
        if CreativeType.BANNER in creatives:
            return not creatives[CreativeType.BANNER]["show_ads_label"]
        return False


class ResolveUriBrowserTarget(BaseFeature):
    def validate(self, campaign: dict) -> bool:
        return any(
            (
                action["type"] == ActionType.RESOLVE_URI
                and action["target"] == ResolveUriTargetEnum.BROWSER
            )
            for action in campaign["actions"]
        )


class MainAction(BaseFeature):
    def validate(self, campaign: dict) -> bool:
        return any(action.get("main", False) for action in campaign["actions"])


class WithAuditPixel(BaseFeature):
    def __init__(self, *args, at_least=1, **kwargs):
        super().__init__(*args, **kwargs)
        self._at_least = at_least

    def validate(self, campaign) -> bool:
        return (
            len(campaign.get("settings", {}).get("verification_data", []))
            >= self._at_least
        )


class WithTemplatelessDcm(BaseFeature):
    def validate(self, campaign) -> bool:
        is_dcm = lambda d: d.get("platform") == "dcm"
        data = campaign.get("settings", {}).get("verification_data", {})
        if not any(map(is_dcm, data)):
            return False
        for url in map(
            lambda d: urllib.parse.unquote(d.get("params", {}).get("url", "")),
            filter(is_dcm, data),
        ):
            if any(
                map(
                    lambda t: t in url,
                    ("[rdid]", "[timestamp]"),
                )
            ):
                return False
        return True


class WithBigBillboard(BaseFeature):
    def validate(self, campaign) -> bool:
        return bool(
            campaign["creatives"].get(CreativeType.BILLBOARD, {}).get("images_v2", [])
        )

    def invalidate(self, campaign) -> bool:
        billboard = campaign["creatives"].get(CreativeType.BILLBOARD, {})
        return billboard.get("split", False) and billboard.get("images", [])
