from dateutil import parser
from pytz import timezone
from yql.client.parameter_value_builder import YqlParameterValueBuilder

from maps_adv.common.yt_utils import BaseImportWithYqlTask, BaseYtExportTask
from maps_adv.config_loader import Config
from maps_adv.geosmb.doorman.server.lib.data_managers import BaseDataManager
from maps_adv.geosmb.doorman.server.lib.domain import Domain

europe_moscow_timezone = timezone("Europe/Moscow")


class ClientsYtExportTask(BaseYtExportTask):
    TABLE_SCHEMA = [
        dict(name="biz_id", type="uint64", required=True),
        dict(name="doorman_id", type="uint64", required=True),
        dict(name="first_name", type="string", required=False),
        dict(name="last_name", type="string", required=False),
        dict(name="passport_uid", type="uint64", required=False),
        dict(name="gender", type="string", required=False),
        dict(name="phone", type="string", required=False),
        dict(name="email", type="string", required=False),
        dict(name="segments", type_v3={"type_name": "list", "item": "string"}),
        dict(name="labels", type_v3={"type_name": "list", "item": "string"}),
    ]

    ITER_SIZE: int = 500000
    CHUNKED_ITERATOR_METHOD_NAME: str = "iter_clients_for_export"

    TIMEOUT: int = 1200

    def __init__(self, *args, config: Config, dm: BaseDataManager, **kwargs):
        super().__init__(
            cluster=config["YT_CLUSTER"],
            table=config["CLIENT_YT_EXPORT_TABLE"],
            token=config["CLIENT_YT_EXPORT_TOKEN"],
            data_producer=dm,
        )


class CallEventsImportTask(BaseImportWithYqlTask):
    TIMEOUT: int = 1200

    CHUNKED_WRITER_METHOD_NAME = "import_call_events"
    YQL = """
        DECLARE $last_imported_id AS Int64;

        $campaigns = (
            SELECT campaign_organization.campaign_id as campaign_id
            FROM {yt_cluster}.`{campaign_organization_table}` AS campaign_organization
            JOIN {yt_cluster}.`{campaign_table}` AS campaign
                ON campaign.id=campaign_organization.campaign_id
            where campaign.chain_permalink IS NULL
            GROUP BY campaign_organization.campaign_id
            HAVING count(*) = 1
        );

        SELECT
            calls_stat.id AS geoproduct_id,
            advert_orgs.permalink,
            calls_stat.source_number AS client_phone,
            calls_stat.time AS event_timestamp,
            calls_stat.await_duration,
            calls_stat.talk_duration,
            calls_stat.call_result,
            calls_stat.session_id,
            calls_stat.record_url
        FROM {yt_cluster}.`{calls_stat_table}` AS calls_stat
        JOIN {yt_cluster}.`{calls_tracking_table}` AS calls_tracking
            ON calls_tracking.tracking_number=calls_stat.masked_number
            AND calls_tracking.original_number=calls_stat.original_number
        JOIN {yt_cluster}.`{advert_orgs_table}` AS advert_orgs
            ON advert_orgs.advert_id=calls_tracking.external_id
        JOIN {yt_cluster}.`{advert_table}` AS advert
            ON advert.id=calls_tracking.external_id
        JOIN $campaigns AS camp ON camp.campaign_id = advert.campaign_id
        WHERE calls_stat.id > $last_imported_id
    """

    def __init__(
        self, *args, config: Config, dm: BaseDataManager, domain: Domain, **kwargs
    ):
        super().__init__(
            yql_token=config["YQL_TOKEN"],
            yql_format_kwargs=dict(
                yt_cluster=config["YT_CLUSTER"],
                calls_stat_table=config["CALLS_STAT_YT_TABLE"],
                calls_tracking_table=config["CALLS_TRACKING_YT_TABLE"],
                advert_orgs_table=config["ADVERT_ORGS_YT_TABLE"],
                advert_table=config["ADVERT_YT_TABLE"],
                campaign_organization_table=config["CAMPAIGN_ORGANIZATION_YT_TABLE"],
                campaign_table=config["CAMPAIGN_YT_TABLE"],
            ),
            data_consumer=domain,
        )
        self.dm = dm

    async def fetch_yql_query_params(self) -> dict:
        last_imported_id = await self.dm.fetch_max_geoproduct_id_for_call_events()
        return {
            "$last_imported_id": YqlParameterValueBuilder.make_int64(
                last_imported_id if last_imported_id else 0
            )
        }

    @classmethod
    def _yt_row_decode(cls, row: tuple) -> tuple:
        return (
            row[0],
            row[1],
            row[2],
            # Import data says "I'm UTC" (with "Z" in timezone), but in lies
            europe_moscow_timezone.localize(
                parser.isoparse(row[3]).replace(tzinfo=None)
            ),
            row[4],
            row[5],
            row[6],
            row[7],
            row[8],
        )

    def __reduce__(self):
        reduced = super().__reduce__()

        state_dict = reduced[2].copy()
        # This property is not picklable, but not needed in subprocess
        del state_dict["dm"]

        return reduced[0], reduced[1], state_dict
