from abc import abstractmethod
from typing import List, Optional

from maps_adv.adv_store.v2.lib.data_managers import sqls
from maps_adv.adv_store.v2.lib.data_managers.base import BaseDataManager
from maps_adv.adv_store.v2.lib.db import db_enum_converter
from maps_adv.adv_store.api.schemas.enums import (
    CampaignDirectModerationStatusEnum,
    CampaignDirectModerationWorkflowEnum,
    PlatformEnum,
)
from maps_adv.common.helpers.enums import CampaignTypeEnum


class BaseModerationDataManager(BaseDataManager):
    __slots__ = ()

    @abstractmethod
    async def list_campaigns(self) -> List[dict]:
        raise NotImplementedError()

    @abstractmethod
    async def create_direct_moderation_for_campaign(
        self,
        campaign_id: int,
        reviewer_uid: Optional[int] = None,
        workflow: Optional[
            CampaignDirectModerationWorkflowEnum
        ] = CampaignDirectModerationWorkflowEnum.COMMON,
    ) -> int:
        raise NotImplementedError()

    @abstractmethod
    async def retrieve_direct_moderations_by_status(
        self, status: CampaignDirectModerationStatusEnum
    ) -> List[dict]:
        raise NotImplementedError()

    @abstractmethod
    async def update_direct_moderation(
        self,
        moderation_id: int,
        status: CampaignDirectModerationStatusEnum,
        verdicts: Optional[List[int]] = None,
    ) -> None:
        raise NotImplementedError()

    @abstractmethod
    async def retrieve_direct_moderation(self, moderation_id: int) -> dict:
        raise NotImplementedError()


class ModerationDataManager(BaseModerationDataManager):
    __slots__ = ()

    async def list_campaigns(self) -> List[dict]:
        async with self.connection() as con:
            got = await con.fetch(sqls.list_moderation_campaigns)

        result = [dict(row) for row in got]

        for el in result:
            el["platforms"] = [PlatformEnum[e] for e in el["platforms"]]
            el["campaign_type"] = CampaignTypeEnum[el["campaign_type"]]
            for key in "order_id", "manul_order_id":
                if not el[key]:
                    el.pop(key)

        return result

    async def create_direct_moderation_for_campaign(
        self,
        campaign_id: int,
        reviewer_uid: int,
        workflow: Optional[
            CampaignDirectModerationWorkflowEnum
        ] = CampaignDirectModerationWorkflowEnum.COMMON,
        verdicts: Optional[List[int]] = None,
    ) -> int:

        async with self.connection() as con:
            moderation_id = await con.fetchval(
                sqls.create_direct_moderation_for_campaign,
                campaign_id,
                reviewer_uid,
                db_enum_converter.from_enum(workflow),
                verdicts or [],
            )
            return moderation_id

    async def retrieve_direct_moderations_by_status(
        self, status: CampaignDirectModerationStatusEnum
    ) -> List[dict]:

        async with self.connection() as con:
            rows = await con.fetch(
                sqls.list_direct_moderations_with_status,
                db_enum_converter.from_enum(status),
            )

        rows = [dict(row) for row in rows]
        for row in rows:
            row["status"] = db_enum_converter.to_enum(
                CampaignDirectModerationStatusEnum, row["status"]
            )
            row["workflow"] = db_enum_converter.to_enum(
                CampaignDirectModerationWorkflowEnum, row["workflow"]
            )

        return rows

    async def update_direct_moderation(
        self,
        moderation_id: int,
        status: CampaignDirectModerationStatusEnum,
        verdicts: Optional[List[int]] = None,
    ) -> None:

        async with self.connection() as con:
            await con.execute(
                sqls.update_direct_moderation_status,
                moderation_id,
                db_enum_converter.from_enum(status),
                verdicts or [],
            )

    async def retrieve_direct_moderation(self, moderation_id: int) -> dict:
        async with self.connection() as con:
            row = await con.fetchrow(
                sqls.retrieve_direct_moderation_by_id, moderation_id
            )

        moderation = dict(row)

        moderation["status"] = db_enum_converter.to_enum(
            CampaignDirectModerationStatusEnum, moderation["status"]
        )
        moderation["workflow"] = db_enum_converter.to_enum(
            CampaignDirectModerationWorkflowEnum, moderation["workflow"]
        )
        return moderation
