from decimal import Decimal
from typing import List

from maps_adv.adv_store.client import Client as AdvStoreClient
from maps_adv.config_loader import Config

from .analyzer import get_campaigns_not_spending_budget
from .campaign_charged_stat import CampaignChargedStat


class NotSpendingBudgetTask:
    __slots__ = ("adv_store_url", "stat_collector")

    def __init__(self, config: Config):
        self.adv_store_url = config.ADV_STORE_URL

        db_config = {
            "database": config.CH_STORAGE_DB,
            "host": config.CH_STORAGE_HOST,
            "port": config.CH_STORAGE_PORT,
            "user": config.CH_STORAGE_USER,
            "password": config.CH_STORAGE_PASSWORD,
            "charged_table": config.CH_STORAGE_ACCEPTED_TABLE,
        }
        if config.CH_STORAGE_USE_SSL:
            db_config["secure"] = True
            db_config["ca_certs"] = config.SSL_CERT_FILE

        self.stat_collector = CampaignChargedStat(**db_config)

    async def __call__(self):

        campaign_data = await self.collect_campaign_data()
        campaign_ids_to_report = get_campaigns_not_spending_budget(campaign_data)
        if campaign_ids_to_report:
            async with AdvStoreClient(self.adv_store_url) as adv_store_client:
                await adv_store_client.create_campaign_not_spending_budget_events(
                    campaign_ids_to_report
                )

    async def collect_campaign_data(self) -> List[dict]:

        async with AdvStoreClient(self.adv_store_url) as adv_store_client:
            campaigns_data = await adv_store_client.list_campaigns_for_budget_analysis()

        campaign_ids = list(map(lambda c: c["campaign_id"], campaigns_data))
        event_stat = await self.stat_collector(campaign_ids)

        return self._compose_campaign_data(
            adv_store_data=campaigns_data, events_stat=event_stat
        )

    @staticmethod
    def _compose_campaign_data(adv_store_data, events_stat) -> List[dict]:
        campaigns = []

        for adv_store_camp in adv_store_data:
            stat = [s for s in events_stat if s[0] == adv_store_camp["campaign_id"]]
            stat = stat[0] if stat else []

            campaign = {
                "campaign_id": adv_store_camp["campaign_id"],
                "daily_budget": Decimal(adv_store_camp.get("daily_budget", "Inf")),
                "days_left": adv_store_camp.get("days_left"),
                "budget": Decimal(adv_store_camp.get("budget", "Inf")),
                "charged": stat[1] if stat else Decimal(0),
            }
            campaigns.append(campaign)

        return campaigns
