import json
from collections import OrderedDict
from typing import Callable, Iterable, Optional
from urllib.parse import quote

from maps_adv.adv_store.api.schemas.enums import (
    ActionTypeEnum,
    ResolveUriTargetEnum,
)
from maps_adv.export.lib.core.enum import ActionType
from maps_adv.export.lib.core.exception import UnsupportedCampaignAction
from maps_adv.export.lib.core.url_signer import ActionUrlSigner


async def pin_data_transform(campaign: dict) -> dict:
    raise NotImplementedError()


def _action_search(action: dict) -> dict:
    if "query" in action and action["query"]:
        query = action["query"]

    else:
        query = json.dumps(
            OrderedDict(
                [
                    ("ad", OrderedDict([("advert_tag_id", action["search_tag_id"])])),
                    ("text", ""),
                ]
            )
        )

    return dict(
        type="Search",
        fields=dict(searchTitle=action["history_text"], searchQuery=query),
    )


action_type_to_event_name = {ActionTypeEnum.OPEN_SITE: "geoadv.bb.action.openSite"}


def _transform_uri(uri: str, navi_signer: ActionUrlSigner) -> str:
    return navi_signer.sign_url(
        "yandexnavi://show_web_view?link=" + quote(uri, safe="")
    )


def _action_resolve_uri(navi_signer: ActionUrlSigner) -> Callable:
    def wrapped(action: dict) -> dict:
        if action["target"] == ResolveUriTargetEnum.BROWSER:
            return dict(
                type="ResolveUri",
                fields=dict(
                    uri=action["uri"],
                    eventName=action_type_to_event_name[action["action_type"]],
                    dialogContent=action["dialog"]["content"],
                    dialogTitle=action["dialog"]["title"],
                    dialogOk=action["dialog"]["ok"],
                    dialogCancel=action["dialog"]["cancel"],
                    dialogEventOk=action["dialog"]["event_ok"],
                    dialogEventCancel=action["dialog"]["event_cancel"],
                ),
            )
        else:
            return dict(
                type="ResolveUri",
                fields=dict(
                    uri=_transform_uri(action["uri"], navi_signer),
                    eventName=action_type_to_event_name[action["action_type"]],
                ),
            )

    return wrapped


def _simple_action_transformer(action_name: str, fields: Iterable[str]) -> Callable:
    def wrapped(action: dict) -> dict:
        return dict(type=action_name, fields={key: action.get(key) for key in fields})

    return wrapped


def _action_phone(action: dict) -> dict:
    return {
        "type": "Call",
        "fields": {
            "phone": action.get("phone", "").translate({ord(c): None for c in " ()-\t"})
        },
    }


def action_transform(
    action: dict, navi_signer: Optional[ActionUrlSigner] = None
) -> dict:
    transform = {
        ActionType.PHONE_CALL: _action_phone,
        ActionType.SEARCH: _action_search,
        ActionType.OPEN_SITE: _simple_action_transformer("OpenSite", ["url", "title"]),
        ActionType.PROMOCODE: _simple_action_transformer("Promocode", ["promocode"]),
        ActionType.RESOLVE_URI: _action_resolve_uri(navi_signer),
        ActionType.ADD_POINT_TO_ROUTE: _simple_action_transformer(
            "AddPointToRoute", ["latitude", "longitude"]
        ),
    }.get(action["type"])

    if not transform:
        raise UnsupportedCampaignAction()

    transformed_action = transform(action)

    if action.get("main", False):
        transformed_action["fields"]["main"] = 1

    return transformed_action
