"""User UI preferences — dashboard layout, widgets, KPIs, visualization modes."""
from __future__ import annotations

import json
from typing import Any

from app.db import fetch_one

DEFAULT_LAYOUT = [
    "kpis",
    "executive",
    "briefing",
    "rss",
    "retail",
    "analytics",
    "approvals",
    "feed",
]
DEFAULT_VIZ = "neo-bars"

DEFAULT_KPI_LAYOUT = [
    "pipeline",
    "clients_active",
    "crm_partnerships",
    "supermarkets",
    "trending_food",
    "pending_approvals",
]

WIDGET_CATALOG = [
    {"id": "kpis", "label": "CEO KPI's", "icon": "📊"},
    {"id": "executive", "label": "Alles op een rij", "icon": "📋"},
    {"id": "briefing", "label": "Herman briefing", "icon": "📝"},
    {"id": "rss", "label": "RSS live feed", "icon": "📰"},
    {"id": "retail", "label": "Retail operatie", "icon": "🏪"},
    {"id": "analytics", "label": "Data & analytics", "icon": "📈"},
    {"id": "approvals", "label": "Agent goedkeuringen", "icon": "✓"},
    {"id": "feed", "label": "Agent feed & projecten", "icon": "⚡"},
]

KPI_CATALOG = [
    {"id": "pipeline", "label": "Pipeline", "sub": "actieve deals", "icon": "💰"},
    {"id": "clients_active", "label": "Actieve klanten", "sub": "CRM · zaken mee", "icon": "🤝"},
    {"id": "clients_total", "label": "Totaal klanten", "sub": "CRM database", "icon": "👥"},
    {"id": "crm_partnerships", "label": "CRM partnerships", "sub": "actieve filialen", "icon": "🏪"},
    {"id": "supermarkets", "label": "Supermarkten", "sub": "Retail 360 DB", "icon": "🛒"},
    {"id": "wholesalers", "label": "Groothandels", "sub": "Retail 360 DB", "icon": "📦"},
    {"id": "trending_food", "label": "Food trends", "sub": "RSS live", "icon": "📰"},
    {"id": "rss_items", "label": "RSS items", "sub": "totaal in DB", "icon": "📡"},
    {"id": "rss_bookmarks", "label": "RSS bookmarks", "sub": "opgeslagen", "icon": "★"},
    {"id": "pending_approvals", "label": "Goedkeuringen", "sub": "wacht op OK", "icon": "✓"},
    {"id": "deals", "label": "Deals", "sub": "totaal CRM", "icon": "💼"},
    {"id": "products", "label": "Producten", "sub": "catalogus", "icon": "🥫"},
    {"id": "suppliers", "label": "Leveranciers", "sub": "sourcing", "icon": "🚚"},
    {"id": "nas_docs", "label": "NAS documenten", "sub": "geanalyseerd", "icon": "📊"},
    {"id": "promo_campaigns", "label": "Promo campagnes", "sub": "actief", "icon": "📁"},
    {"id": "market_best", "label": "Aandeel top", "sub": "retail markt", "icon": "📈"},
]

VIZ_MODES = [
    {"id": "neo-bars", "label": "Neo staafdiagram", "icon": "📊"},
    {"id": "neo-rings", "label": "Neo ringen", "icon": "🍩"},
    {"id": "neo-equalizer", "label": "Neo equalizer", "icon": "🎚️"},
    {"id": "neo-cards", "label": "Neo kaarten", "icon": "🃏"},
    {"id": "neo-table", "label": "Neo tabel", "icon": "📋"},
]

_ALL_WIDGET_IDS = {w["id"] for w in WIDGET_CATALOG}
_ALL_KPI_IDS = {k["id"] for k in KPI_CATALOG}


def _default_widgets() -> dict[str, bool]:
    return {w["id"]: True for w in WIDGET_CATALOG}


def _parse_json(val: Any, fallback: Any) -> Any:
    if val is None:
        return fallback
    if isinstance(val, str):
        try:
            return json.loads(val)
        except Exception:
            return fallback
    return val


def _normalize_layout(layout: list[str]) -> list[str]:
    seen: set[str] = set()
    out: list[str] = []
    for wid in layout:
        if wid in _ALL_WIDGET_IDS and wid not in seen:
            out.append(wid)
            seen.add(wid)
    for w in WIDGET_CATALOG:
        if w["id"] not in seen:
            out.append(w["id"])
    return out


def _normalize_widgets(widgets: dict[str, Any] | None) -> dict[str, bool]:
    base = _default_widgets()
    if not widgets:
        return base
    for wid in _ALL_WIDGET_IDS:
        if wid in widgets:
            base[wid] = bool(widgets[wid])
    return base


def _normalize_kpis(kpis: list[str] | None) -> list[str]:
    if not kpis:
        return list(DEFAULT_KPI_LAYOUT)
    seen: set[str] = set()
    out: list[str] = []
    for kid in kpis:
        if kid in _ALL_KPI_IDS and kid not in seen:
            out.append(kid)
            seen.add(kid)
    return out or list(DEFAULT_KPI_LAYOUT)


def get_preferences(user_key: str = "ceo") -> dict[str, Any]:
    row = fetch_one("SELECT * FROM user_ui_preferences WHERE user_key = %s", (user_key,))
    if not row:
        return {
            "user_key": user_key,
            "dashboard_layout": list(DEFAULT_LAYOUT),
            "dashboard_widgets": _default_widgets(),
            "dashboard_kpis": list(DEFAULT_KPI_LAYOUT),
            "viz_modes": {},
            "global_viz_mode": DEFAULT_VIZ,
            "locale": "nl",
            "viz_options": VIZ_MODES,
            "widget_catalog": WIDGET_CATALOG,
            "kpi_catalog": KPI_CATALOG,
        }
    layout = _normalize_layout(_parse_json(row.get("dashboard_layout"), DEFAULT_LAYOUT))
    widgets = _normalize_widgets(_parse_json(row.get("dashboard_widgets"), None))
    kpis = _normalize_kpis(_parse_json(row.get("dashboard_kpis"), None))
    viz_modes = _parse_json(row.get("viz_modes"), {})
    return {
        "user_key": user_key,
        "dashboard_layout": layout,
        "dashboard_widgets": widgets,
        "dashboard_kpis": kpis,
        "viz_modes": viz_modes if isinstance(viz_modes, dict) else {},
        "global_viz_mode": row.get("global_viz_mode") or DEFAULT_VIZ,
        "locale": row.get("locale") or "nl",
        "viz_options": VIZ_MODES,
        "widget_catalog": WIDGET_CATALOG,
        "kpi_catalog": KPI_CATALOG,
    }


def save_preferences(
    user_key: str,
    dashboard_layout: list[str] | None = None,
    dashboard_widgets: dict[str, bool] | None = None,
    dashboard_kpis: list[str] | None = None,
    global_viz_mode: str | None = None,
    viz_modes: dict[str, str] | None = None,
    locale: str | None = None,
) -> dict[str, Any]:
    current = get_preferences(user_key)
    layout = _normalize_layout(dashboard_layout if dashboard_layout is not None else current["dashboard_layout"])
    widgets = _normalize_widgets(
        dashboard_widgets if dashboard_widgets is not None else current["dashboard_widgets"]
    )
    kpis = _normalize_kpis(dashboard_kpis if dashboard_kpis is not None else current["dashboard_kpis"])
    gviz = global_viz_mode if global_viz_mode is not None else current["global_viz_mode"]
    vmodes = viz_modes if viz_modes is not None else current["viz_modes"]
    loc = locale if locale is not None else current.get("locale", "nl")
    if loc not in ("nl", "en"):
        loc = "nl"
    fetch_one(
        """
        INSERT INTO user_ui_preferences (
            user_key, dashboard_layout, dashboard_widgets, dashboard_kpis,
            global_viz_mode, viz_modes, locale, updated_at
        )
        VALUES (%s, %s::jsonb, %s::jsonb, %s::jsonb, %s, %s::jsonb, %s, NOW())
        ON CONFLICT (user_key) DO UPDATE SET
            dashboard_layout = EXCLUDED.dashboard_layout,
            dashboard_widgets = EXCLUDED.dashboard_widgets,
            dashboard_kpis = EXCLUDED.dashboard_kpis,
            global_viz_mode = EXCLUDED.global_viz_mode,
            viz_modes = EXCLUDED.viz_modes,
            locale = EXCLUDED.locale,
            updated_at = NOW()
        RETURNING user_key
        """,
        (
            user_key,
            json.dumps(layout),
            json.dumps(widgets),
            json.dumps(kpis),
            gviz,
            json.dumps(vmodes),
            loc,
        ),
    )
    return get_preferences(user_key)
