import logging
from typing import List

from maps_adv.geosmb.clients.market import (
    BaseHttpClientException,
    MarketIntClient,
    ServiceStatus,
)
from maps_adv.geosmb.landlord.server.lib.data_manager import BaseDataManager
from maps_adv.geosmb.landlord.server.lib.enums import Feature, ServiceItemType


class ServiceProvider:
    _market_client: MarketIntClient
    _dm: BaseDataManager
    _disable_promoted_services: bool

    def __init__(
        self,
        market_client: MarketIntClient,
        dm: BaseDataManager,
        disable_promoted_services: bool,
    ):
        self._market_client = market_client
        self._dm = dm
        self._disable_promoted_services = disable_promoted_services

    async def fetch_services_info(self, biz_id: int) -> List[dict]:
        if not self._disable_promoted_services:
            services = await self._dm.fetch_org_promoted_services(biz_id=biz_id)
            if services:
                return services
        else:
            services = []
        if (
            await self._dm.fetch_cached_landing_config_feature(
                Feature.USE_LOADED_MARKET_INT_DATA
            )
            == "enabled"
        ):
            services += await self._dm.fetch_org_market_int_services(biz_id=biz_id)
        else:

            try:
                service_items = await self._market_client.fetch_services(
                    biz_id=biz_id, filtering=dict(statuses=[ServiceStatus.PUBLISHED])
                )
            except BaseHttpClientException as exc:
                logging.getLogger(__name__).exception(
                    f"Failed to get services for biz_id {biz_id}", exc_info=exc
                )
                return services

            if not service_items:
                return services

            try:
                service_categories = await self._market_client.fetch_service_categories(
                    biz_id=biz_id
                )
            except BaseHttpClientException as exc:
                logging.getLogger(__name__).exception(
                    f"Failed to get service categories for biz_id {biz_id}",
                    exc_info=exc,
                )
                service_categories = {}

            for service_item in service_items:
                services.append(
                    self._compose_service_item_data(
                        service_item=service_item, service_categories=service_categories
                    )
                )

        return services

    def _compose_service_item_data(
        self,
        service_item: dict,
        service_categories: dict,
    ) -> dict:
        service_item_data = {
            "type": ServiceItemType.MARKET,
            "id": service_item["item_id"],
            "name": service_item["name"],
        }
        if "client_action" in service_item:
            service_item_data["action_type"] = service_item["client_action"]

        if "client_action_settings" in service_item:
            service_item_data["service_action_type_settings"] = service_item[
                "client_action_settings"
            ]

        service_item_data.update(self._compose_service_price_and_duration(service_item))

        if service_item.get("main_image_url_template"):
            service_item_data["image"] = service_item["main_image_url_template"]

        if service_item.get("description"):
            service_item_data["description"] = service_item["description"]

        service_item_data["categories"] = self._compose_service_categories(
            service_item=service_item, service_categories=service_categories
        )

        return service_item_data

    def _compose_service_price_and_duration(self, service_item: dict) -> dict:
        if len(service_item["service_prices"]) == 1:
            return dict(
                cost=service_item["service_prices"][0]["price"]["value"],
                duration=service_item["service_prices"][0].get("duration_minutes"),
            )

        result = dict()

        if "min_price" in service_item:
            result["min_cost"] = service_item["min_price"]["value"]

        if len(service_item["service_prices"]) > 1:
            result["min_duration"] = min(
                filter(
                    lambda p: p is not None,
                    [
                        price.get("duration_minutes")
                        for price in service_item["service_prices"]
                    ],
                )
            )

        return result

    def _compose_service_categories(
        self,
        service_item: dict,
        service_categories: dict,
    ) -> List[str]:
        categories = []
        for category in service_item["category_ids"]:
            if category in service_categories:
                categories.append(service_categories[category])

        return categories
