from __future__ import annotations

from dataclasses import dataclass

from app.market.models import CandidateRecord, InquiryRequest


@dataclass(frozen=True)
class CustomerSignals:
    price_sensitivity: float
    time_sensitivity: float
    reliability_sensitivity: float
    repeat_purchase_count: int
    overdue_days: int
    service_requirement: str


def score_candidates(
    candidates: list[CandidateRecord],
    inquiry: InquiryRequest,
    customer: CustomerSignals,
) -> tuple[list[dict], dict[str, float]]:
    if not candidates:
        return [], {}

    costs = [candidate.supplier_cost for candidate in candidates]
    min_cost, max_cost = min(costs), max(costs)
    min_transit = min(candidate.transit_days for candidate in candidates)

    raw_weights = {
        "price": 1 + customer.price_sensitivity,
        "transit": 0.8 + customer.time_sensitivity,
        "supplier": 1 + customer.reliability_sensitivity,
        "customer": 0.9,
        "strategy": 0.5,
    }
    weight_total = sum(raw_weights.values())
    weights = {name: value / weight_total for name, value in raw_weights.items()}

    scored: list[dict] = []
    for candidate in candidates:
        if max_cost == min_cost:
            price_score = 100.0
        else:
            price_score = 100 - ((candidate.supplier_cost - min_cost) / (max_cost - min_cost) * 35)

        transit_penalty = 12 if candidate.transport_mode == "空运" else 5
        transit_score = max(
            40.0,
            100 - (candidate.transit_days - min_transit) * transit_penalty,
        )
        offering_reliability = (
            candidate.booking_success_rate + candidate.space_release_success_rate
        ) / 2
        product_reliability = (
            candidate.etd_on_time_rate + candidate.eta_on_time_rate
        ) / 2
        supplier_score = (offering_reliability * 0.7 + product_reliability * 0.3) * 100

        is_brand_unit = "品牌本地分支机构" in candidate.agency_level
        customer_score = 94.0 if is_brand_unit else 83.0
        if candidate.route_type == inquiry.preferred_route_type:
            customer_score += 4
            if customer.time_sensitivity >= 0.85:
                customer_score += 8
        if customer.price_sensitivity >= 0.7 and not is_brand_unit:
            customer_score += 7
        if customer.reliability_sensitivity >= 0.85 and is_brand_unit:
            customer_score += 2
        customer_score = min(100.0, customer_score)

        strategy_score = 92.0 if candidate.route_type == "直航" else 72.0
        total_score = (
            price_score * weights["price"]
            + transit_score * weights["transit"]
            + supplier_score * weights["supplier"]
            + customer_score * weights["customer"]
            + strategy_score * weights["strategy"]
        )

        scored.append({
            "candidate": candidate,
            "price_score": round(price_score, 1),
            "transit_score": round(transit_score, 1),
            "supplier_execution_score": round(supplier_score, 1),
            "customer_fit_score": round(customer_score, 1),
            "product_strategy_score": round(strategy_score, 1),
            "total_score": round(total_score, 1),
        })

    assign_solution_types(scored)
    scored.sort(key=lambda item: item["total_score"], reverse=True)
    for rank, item in enumerate(scored, start=1):
        item["rank"] = rank
    return scored, {name: round(value, 4) for name, value in weights.items()}


def assign_solution_types(scored: list[dict]) -> None:
    economy = min(scored, key=lambda item: item["candidate"].supplier_cost)
    fastest = min(
        (item for item in scored if item is not economy),
        key=lambda item: item["candidate"].transit_days,
        default=economy,
    )
    balanced = max(
        (item for item in scored if item not in (economy, fastest)),
        key=lambda item: item["total_score"],
        default=max(scored, key=lambda item: item["total_score"]),
    )

    for item in scored:
        item["solution_type"] = "候选方案"
    economy["solution_type"] = "经济方案"
    fastest["solution_type"] = "时效方案"
    balanced["solution_type"] = "均衡方案"
