from marshmallow import fields, post_load, pre_dump

from maps_adv.adv_store.api.proto import action_pb2
from maps_adv.adv_store.api.schemas.enums_map import ENUMS_MAP
from maps_adv.adv_store.api.schemas.enums import ActionTypeEnum, ResolveUriTargetEnum
from maps_adv.common.protomallow import PbEnumField, ProtobufSchema


class OpenSiteSchema(ProtobufSchema):
    class Meta:
        pb_message_class = action_pb2.OpenSite

    url = fields.String()


class SearchSchema(ProtobufSchema):
    class Meta:
        pb_message_class = action_pb2.Search

    organizations = fields.List(fields.Integer())
    history_text = fields.String()


class PhoneCallSchema(ProtobufSchema):
    class Meta:
        pb_message_class = action_pb2.PhoneCall

    phone = fields.String()


class DownloadAppSchema(ProtobufSchema):
    class Meta:
        pb_message_class = action_pb2.DownloadApp

    google_play_id = fields.String(required=False, missing=None)
    app_store_id = fields.String(required=False, missing=None)
    url = fields.String()


class PromocodeSchema(ProtobufSchema):
    class Meta:
        pb_message_class = action_pb2.Promocode

    promocode = fields.String()


class DialogSchema(ProtobufSchema):
    class Meta:
        pb_message_class = action_pb2.Dialog

    title = fields.String()
    content = fields.String()
    ok = fields.String()
    cancel = fields.String()
    event_ok = fields.String()
    event_cancel = fields.String()


class ResolveUriSchema(ProtobufSchema):
    class Meta:
        pb_message_class = action_pb2.ResolveUri

    uri = fields.String()
    action_type = PbEnumField(
        enum=ActionTypeEnum,
        pb_enum=action_pb2.ActionType.Enum,
        values_map=ENUMS_MAP["action_type"],
    )
    target = PbEnumField(
        enum=ResolveUriTargetEnum,
        pb_enum=action_pb2.ResolveUri.Target,
        values_map=ENUMS_MAP["resolve_uri_target"],
        missing=action_pb2.ResolveUri.Target.WEB_VIEW,
    )
    dialog = fields.Nested(DialogSchema(), missing=None)


class AddPointToRouteSchema(ProtobufSchema):
    class Meta:
        pb_message_class = action_pb2.AddPointToRoute

    latitude = fields.Float()
    longitude = fields.Float()


class ActionSchema(ProtobufSchema):
    class Meta:
        pb_message_class = action_pb2.Action

    open_site = fields.Nested(OpenSiteSchema(), required=False)
    search = fields.Nested(SearchSchema(), required=False)
    phone_call = fields.Nested(PhoneCallSchema(), required=False)
    download_app = fields.Nested(DownloadAppSchema(), required=False)
    promocode = fields.Nested(PromocodeSchema(), required=False)
    resolve_uri = fields.Nested(ResolveUriSchema(), required=False)
    add_point_to_route = fields.Nested(AddPointToRouteSchema(), required=False)
    title = fields.String(required=False)
    main = fields.Boolean(missing=False)

    @post_load
    def move_fields_into_action(self, data):
        fields = {field: data.pop(field, None) for field in ("title", "main")}
        action_type, action_data = list(data.items())[0]

        if action_type in ("open_site", "phone_call", "search", "download_app"):
            action_data["title"] = fields["title"]
        action_data["main"] = fields["main"]

        return dict(type_=action_type, **action_data)

    @pre_dump
    def move_fields_from_action(self, data):
        fields = {
            field: data.pop(field)
            for field in ("title", "main")
            if data.get(field) is not None
        }
        transformed_data = {data.pop("type_"): data}
        transformed_data.update(fields)

        return transformed_data
