"""Scores the product per target market (United Kingdom, Saudi Arabia).

Rating, review quality, shipping, competitive pricing and listing
completeness carry the most weight. Sales volume is scored on a saturating
(square-root) curve and given a small weight so that moderate sales do not
fail an otherwise strong product. Metrics with no data are skipped and the
remaining weights renormalized. If the payload carries extra demand signals
(orders, wishlist count) they feed the popularity component.
"""
from __future__ import annotations

from dataclasses import dataclass, field

from ...constants import constants as C
from ...utils.helpers import (
    clamp,
    linear_score,
    saturating_score,
    weighted_average,
)

from .product_analyzer import ProductAnalysis
from .store_analyzer import StoreAnalysis
from .sku.sku_decision_engine import SkuDecision


@dataclass
class MarketScore:
    market: str
    score: float
    recommend: bool
    reasons: list[str] = field(default_factory=list)

    def to_dict(self) -> dict:
        return {
            "score": round(self.score, 2),
            "recommend": self.recommend,
            "reasons": self.reasons,
        }


@dataclass
class MarketAnalysis:
    uk: MarketScore
    saudi: MarketScore

    def to_dict(self) -> dict:
        return {"uk": self.uk.to_dict(), "saudi": self.saudi.to_dict()}

    @property
    def best_score(self) -> float:
        return max(self.uk.score, self.saudi.score)


class MarketAnalyzer:
    """Single responsibility: judge market fit for the UK and Saudi Arabia."""

    def analyze(
        self,
        product: ProductAnalysis,
        store: StoreAnalysis,
        sku_decisions: list[SkuDecision],
    ) -> MarketAnalysis:
        return MarketAnalysis(
            uk=self._score_market(C.MARKET_UK, product, store, sku_decisions),
            saudi=self._score_market(C.MARKET_SAUDI, product, store, sku_decisions),
        )

    # ------------------------------------------------------------------ #
    def _score_market(
        self,
        market: str,
        product: ProductAnalysis,
        store: StoreAnalysis,
        sku_decisions: list[SkuDecision],
    ) -> MarketScore:
        best = self._best_sku(sku_decisions)
        weights = C.MARKET_SCORE_WEIGHTS

        rating = product.average_rating or store.average_rating
        # None components are unavailable metrics: skipped + renormalized.
        components: dict[str, float | None] = {
            "ratings": clamp((rating / 5.0) * 100.0) if rating > 0 else None,
            "shipping": best.shipping.score if best and best.freight.has_data else None,
            "store": store.score if store.score > 0 else None,
            "price": (best.profit.price_competitiveness if best else None),
            "reviews": (
                saturating_score(product.review_count, C.REVIEWS_FOR_FULL_POPULARITY)
                if product.review_count > 0 else None
            ),
            "delivery": self._delivery_score(market, best),
            "completeness": (
                (product.quality_score + product.completeness_score) / 2
                if product.completeness_score > 0 else None
            ),
            "popularity": (
                saturating_score(product.sales_count, C.SALES_FOR_FULL_POPULARITY)
                if product.sales_count > 0 else None
            ),
            "inventory": best.inventory.score if best else None,
        }

        score = weighted_average(
            [(components[name], weight) for name, weight in weights.items()]
        )
        score = clamp(score + self._local_warehouse_bonus(market, sku_decisions))

        return MarketScore(
            market=market,
            score=score,
            recommend=score >= C.MARKET_RECOMMEND_THRESHOLD,
            reasons=self._reasons(components, product, best),
        )

    # ------------------------------------------------------------------ #
    @staticmethod
    def _best_sku(sku_decisions: list[SkuDecision]) -> SkuDecision | None:
        if not sku_decisions:
            return None
        return max(sku_decisions, key=lambda d: d.result.score)

    @staticmethod
    def _delivery_score(market: str, best: SkuDecision | None) -> float | None:
        if best is None or best.freight.delivery_days_avg is None:
            return None
        return linear_score(
            best.freight.delivery_days_avg,
            C.MARKET_DELIVERY_FAST[market],
            C.MARKET_DELIVERY_SLOW[market],
        )

    @staticmethod
    def _local_warehouse_bonus(market: str, sku_decisions: list[SkuDecision]) -> float:
        local = C.MARKET_LOCAL_WAREHOUSES[market]
        for decision in sku_decisions:
            warehouse = (decision.freight.warehouse_country or "").upper()
            if warehouse in local:
                return C.MARKET_LOCAL_WAREHOUSE_BONUS
        return 0.0

    @staticmethod
    def _reasons(
        components: dict, product: ProductAnalysis, best: SkuDecision | None
    ) -> list[str]:
        """Concise, human-readable justification of the market score."""
        reasons: list[str] = []
        if (components.get("ratings") or 0) >= 75:
            reasons.append("Positive customer rating")
        if components.get("popularity") is not None:
            if components["popularity"] >= 60:
                reasons.append("Strong sales history")
            else:
                reasons.append("Moderate sales history")
        if (components.get("price") or 0) >= 60:
            reasons.append("Competitive pricing")
        if (components.get("completeness") or 0) >= 80:
            reasons.append("Complete, high-quality listing")
        if (components.get("delivery") or 0) >= 70 and best is not None:
            reasons.append(
                f"Fast delivery ({best.freight.delivery_days_min}-"
                f"{best.freight.delivery_days_max} days)"
            )
        if components.get("reviews") is None or (components.get("reviews") or 0) < 30:
            reasons.append("Limited review history")
        return reasons
