from collections import defaultdict
from typing import Collection, Dict, List, Tuple

from maps_adv.export.lib.core import utils
from maps_adv.export.lib.core.enum import CampaignType, CreativeType


class CrossPermalinkException(Exception):
    pass


class CrossPermalinkValidator:
    def __call__(self, campaigns: list):
        permalinks_stat = self._collect_permalinks_usage(campaigns)
        self._validate_permalinks(permalinks_stat)

    @staticmethod
    def _collect_permalinks_usage(campaigns: List[dict]) -> Dict[int, List[int]]:
        permalinks_stat = defaultdict(list)

        for campaign in campaigns:
            if campaign["campaign_type"] == CampaignType.CATEGORY_SEARCH:
                for creative in campaign["creatives"].get(CreativeType.PIN_SEARCH, []):
                    for permalink in creative["organizations"].keys():
                        permalinks_stat[permalink].append(campaign["id"])

        return permalinks_stat

    @classmethod
    def _validate_permalinks(cls, permalinks_stat: Dict[int, List[int]]):
        duplicated_campaigns = set()
        for campaign_ids in permalinks_stat.values():
            if len(campaign_ids) != len(set(campaign_ids)):
                duplicated_campaigns.update(cls._retrieve_duplicate(campaign_ids))

        if duplicated_campaigns:
            raise CrossPermalinkException(
                "Campaigns with duplicated permalinks detected. Campaign ids: "
                f"{utils.printable(sorted(duplicated_campaigns))}"
            )

    @staticmethod
    def _retrieve_duplicate(collection: Collection) -> Tuple:
        id_list = list(collection)
        for item in set(id_list):
            id_list.remove(item)
        return tuple(sorted(set(id_list)))
