"""Scores the shipping offer of a SKU."""
from __future__ import annotations

from dataclasses import dataclass

from ....constants import constants as C
from ....utils.helpers import clamp, linear_score

from .freight_analyzer import FreightAnalysis


@dataclass
class ShippingAnalysis:
    score: float  # 0-100
    grade: str
    delivery_score: float
    cost_score: float

    def to_dict(self) -> dict:
        return {
            "score": round(self.score, 2),
            "grade": self.grade,
            "deliveryScore": round(self.delivery_score, 2),
            "costScore": round(self.cost_score, 2),
        }


class ShippingAnalyzer:
    """Single responsibility: turn a freight analysis into a shipping score.

    Score = weighted blend of delivery speed, shipping cost and service
    extras (tracking, trusted carrier, favorable warehouse).
    """

    def analyze(self, freight: FreightAnalysis) -> ShippingAnalysis:
        delivery_score = self._delivery_score(freight)
        cost_score = linear_score(
            freight.shipping_cost, C.SHIPPING_COST_CHEAP, C.SHIPPING_COST_EXPENSIVE
        )
        extras_score = self._extras_score(freight)

        weights = C.SHIPPING_SCORE_WEIGHTS
        score = clamp(
            delivery_score * weights["delivery_time"]
            + cost_score * weights["cost"]
            + extras_score * weights["extras"]
        )
        if not freight.has_data:
            score = 0.0

        return ShippingAnalysis(
            score=score,
            grade=self._grade(score),
            delivery_score=delivery_score,
            cost_score=cost_score,
        )

    # ------------------------------------------------------------------ #
    @staticmethod
    def _delivery_score(freight: FreightAnalysis) -> float:
        avg_days = freight.delivery_days_avg
        if avg_days is None:
            return 50.0  # unknown: neutral, neither rewarded nor punished
        return linear_score(avg_days, C.DELIVERY_DAYS_FAST, C.DELIVERY_DAYS_SLOW)

    @staticmethod
    def _extras_score(freight: FreightAnalysis) -> float:
        score = 50.0  # neutral baseline
        if freight.tracking:
            score += C.TRACKING_BONUS
        company = (freight.shipping_company or "").upper()
        if any(keyword in company for keyword in C.TRUSTED_CARRIER_KEYWORDS):
            score += C.TRUSTED_CARRIER_BONUS
        warehouse = (freight.warehouse_country or "").upper()
        if warehouse in C.PREFERRED_WAREHOUSES:
            score += C.PREFERRED_WAREHOUSE_BONUS
        return clamp(score)

    @staticmethod
    def _grade(score: float) -> str:
        if score >= C.SHIPPING_GRADE_EXCELLENT:
            return "Excellent"
        if score >= C.SHIPPING_GRADE_GOOD:
            return "Good"
        if score >= C.SHIPPING_GRADE_AVERAGE:
            return "Average"
        return "Poor"
