"""Executive Dashboard schemas — read-only company overview for CEO/CFO."""
from __future__ import annotations

from typing import Optional

from pydantic import BaseModel


class InventorySnapshot(BaseModel):
    total_inventory_eur: float
    total_inventory_eur_prev_week: Optional[float] = None
    wow_change_eur: Optional[float] = None
    wow_change_pct: Optional[float] = None
    target_eur: float
    vs_target_pct: float
    wh_eur: float
    store_eur: float
    n_skus_with_stock: int


class ChannelRevenue(BaseModel):
    channel: str
    mtd_revenue: float
    last_week_revenue: float
    prev_week_revenue: float
    wow_change_pct: Optional[float] = None


class RevenuePulse(BaseModel):
    month_label: str
    last_week_label: str
    prev_week_label: str
    mtd_revenue_total: float
    last_week_total: float
    prev_week_total: float
    wow_change_pct: Optional[float] = None
    by_channel: list[ChannelRevenue]


class RevenueWeekly(BaseModel):
    year_week: str
    retail: float
    wholesale: float
    webshop: float
    total: float
    # RUC € per channel per week — populated alongside revenue so the
    # dashboard chart can toggle "Revenue" vs "RUC" without a second fetch.
    ruc_retail: float = 0.0
    ruc_wholesale: float = 0.0
    ruc_webshop: float = 0.0
    ruc_total: float = 0.0


class PlanCompare(BaseModel):
    """Current-month snapshot plan vs month-to-date actuals.

    Pulls totals from the active `monthly_plan_snapshots` row (locked
    Consensus Plan) and compares to the live MTD from erp_transactions.
    Used by Executive Dashboard to show "how are we tracking vs plan".
    """
    month_key: int
    month_label: str                          # e.g. "May 2026"
    plan_source: str                          # 'snapshot' | 'no_snapshot'
    plan_revenue_eur: Optional[float] = None
    plan_ruc_eur:     Optional[float] = None
    mtd_revenue_eur:  float = 0.0
    mtd_ruc_eur:      float = 0.0
    revenue_progress_pct: Optional[float] = None  # mtd / plan × 100
    ruc_progress_pct:     Optional[float] = None
    days_in_month: int = 0
    days_observed: int = 0


class StockoutRisk(BaseModel):
    sku: str
    name: Optional[str] = None
    tier: Optional[str] = None
    category: Optional[str] = None
    wh_stock: float
    weekly_demand: float
    weeks_cover: float
    effective_weeks_cover: float = 0.0
    lead_time_weeks: float = 0.0
    incoming_in_lt: float = 0.0
    status: str = "CRITICAL"   # CRITICAL | ORDER_SOON
    revenue_at_risk_weekly: float
    incoming_po_week: Optional[str] = None
    days_until_stockout: float


class SupplyArrivalRow(BaseModel):
    supplier_name: str
    po_count: int
    total_qty: float
    total_eur: float
    is_abc: bool = False


class SupplyArrivals(BaseModel):
    this_week_label: str
    next_week_label: str
    this_week: list[SupplyArrivalRow]
    next_week: list[SupplyArrivalRow]
    this_week_total_eur: float
    next_week_total_eur: float
    overdue_pos: int = 0
    overdue_total_eur: float = 0.0


class TierAccuracy(BaseModel):
    tier: str
    fa_pct: Optional[float] = None
    n_skus: int = 0


class ForecastAccuracySummary(BaseModel):
    fa_pct: Optional[float] = None
    fa_pct_prev_month: Optional[float] = None
    trend: str  # "up" | "down" | "stable" | "unknown"
    bias_pct: Optional[float] = None
    measurement_month: Optional[str] = None
    tier_breakdown: list[TierAccuracy] = []


class InventoryTrendPoint(BaseModel):
    year_week: str
    total_eur: float


class InventoryTrend(BaseModel):
    points: list[InventoryTrendPoint]
    has_history: bool


class SectionError(BaseModel):
    error: str


class ExecutiveDashboard(BaseModel):
    anchor_year_week: str
    refreshed_at: str
    inventory: Optional[InventorySnapshot] = None
    inventory_error: Optional[str] = None
    revenue: Optional[RevenuePulse] = None
    revenue_error: Optional[str] = None
    stockout_risks: list[StockoutRisk] = []
    stockout_error: Optional[str] = None
    supply_arrivals: Optional[SupplyArrivals] = None
    supply_error: Optional[str] = None
    forecast_accuracy: Optional[ForecastAccuracySummary] = None
    forecast_accuracy_error: Optional[str] = None
    inventory_trend: Optional[InventoryTrend] = None
    inventory_trend_error: Optional[str] = None
    revenue_weekly: list[RevenueWeekly] = []
    plan_compare: Optional[PlanCompare] = None
    plan_compare_error: Optional[str] = None
