"""
Admin: training_parameters catalog (EAV keys for activity session metrics).

Agent guide: .claude/docs/technical/ACTIVITY_SESSION_METRICS_EAV_AGENT_GUIDE.md
"""
import re
from typing import Any, Optional

from fastapi import APIRouter, Depends, HTTPException, Query
from pydantic import BaseModel, Field
from psycopg2 import errors as pg_errors
from psycopg2.extras import Json

from auth import require_admin
from db import get_db, get_cursor, r2d

router = APIRouter(prefix="/api/admin/training-parameters", tags=["admin", "training-parameters"])

KEY_PATTERN = re.compile(r"^[a-z][a-z0-9_]{0,62}$")

PARAM_CATEGORY = {"physical", "physiological", "subjective", "environmental", "performance"}
DATA_TYPES = {"integer", "float", "string", "boolean"}


class TrainingParameterCreate(BaseModel):
    key: str = Field(..., min_length=1, max_length=50)
    name_de: str = Field(..., min_length=1, max_length=100)
    name_en: str = Field(..., min_length=1, max_length=100)
    category: str = Field(..., max_length=50)
    data_type: str = Field(..., max_length=20)
    unit: Optional[str] = Field(None, max_length=20)
    description_de: Optional[str] = None
    description_en: Optional[str] = None
    source_field: Optional[str] = Field(None, max_length=100)
    validation_rules: Optional[dict] = None
    is_active: bool = True


class TrainingParameterUpdate(BaseModel):
    name_de: Optional[str] = Field(None, min_length=1, max_length=100)
    name_en: Optional[str] = Field(None, min_length=1, max_length=100)
    category: Optional[str] = Field(None, max_length=50)
    data_type: Optional[str] = Field(None, max_length=20)
    unit: Optional[str] = Field(None, max_length=20)
    description_de: Optional[str] = None
    description_en: Optional[str] = None
    source_field: Optional[str] = Field(None, max_length=100)
    validation_rules: Optional[dict] = None
    is_active: Optional[bool] = None


def _norm_key(key: str) -> str:
    k = key.strip().lower()
    if not KEY_PATTERN.match(k):
        raise HTTPException(
            400,
            "Ungültiger key: nur Kleinbuchstaben, Ziffern, Unterstriche; muss mit Buchstabe beginnen.",
        )
    return k


def _validate_category(cat: str) -> str:
    c = cat.strip()
    if c not in PARAM_CATEGORY:
        raise HTTPException(400, f"category muss einer von {sorted(PARAM_CATEGORY)} sein")
    return c


def _validate_data_type(dt: str) -> str:
    d = dt.strip().lower()
    if d not in DATA_TYPES:
        raise HTTPException(400, f"data_type muss einer von {sorted(DATA_TYPES)} sein")
    return d


@router.get("")
def admin_list_training_parameters(
    include_inactive: bool = Query(False),
    session: dict = Depends(require_admin),
):
    with get_db() as conn:
        cur = get_cursor(conn)
        if include_inactive:
            cur.execute(
                """
                SELECT * FROM training_parameters
                ORDER BY category, key
                """
            )
        else:
            cur.execute(
                """
                SELECT * FROM training_parameters
                WHERE is_active = true
                ORDER BY category, key
                """
            )
        return [r2d(r) for r in cur.fetchall()]


@router.post("")
def admin_create_training_parameter(
    body: TrainingParameterCreate,
    session: dict = Depends(require_admin),
):
    key = _norm_key(body.key)
    cat = _validate_category(body.category)
    dt = _validate_data_type(body.data_type)
    rules = body.validation_rules if body.validation_rules is not None else {}

    with get_db() as conn:
        cur = get_cursor(conn)
        try:
            cur.execute(
                """
                INSERT INTO training_parameters (
                    key, name_de, name_en, category, data_type, unit,
                    description_de, description_en, source_field, validation_rules, is_active
                ) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)
                RETURNING id
                """,
                (
                    key,
                    body.name_de.strip(),
                    body.name_en.strip(),
                    cat,
                    dt,
                    body.unit.strip() if body.unit else None,
                    body.description_de,
                    body.description_en,
                    body.source_field.strip() if body.source_field else None,
                    Json(rules),
                    body.is_active,
                ),
            )
            new_id = cur.fetchone()["id"]
            conn.commit()
        except pg_errors.UniqueViolation:
            conn.rollback()
            raise HTTPException(409, "Parameter-key existiert bereits") from None
    return {"id": new_id, "key": key}


@router.put("/{param_id}")
def admin_update_training_parameter(
    param_id: int,
    body: TrainingParameterUpdate,
    session: dict = Depends(require_admin),
):
    cols: list[str] = []
    vals: list[Any] = []

    if body.name_de is not None:
        cols.append("name_de = %s")
        vals.append(body.name_de.strip())
    if body.name_en is not None:
        cols.append("name_en = %s")
        vals.append(body.name_en.strip())
    if body.category is not None:
        cols.append("category = %s")
        vals.append(_validate_category(body.category))
    if body.data_type is not None:
        cols.append("data_type = %s")
        vals.append(_validate_data_type(body.data_type))
    if body.unit is not None:
        cols.append("unit = %s")
        vals.append(body.unit.strip() or None)
    if body.description_de is not None:
        cols.append("description_de = %s")
        vals.append(body.description_de)
    if body.description_en is not None:
        cols.append("description_en = %s")
        vals.append(body.description_en)
    if body.source_field is not None:
        cols.append("source_field = %s")
        vals.append(body.source_field.strip() or None)
    if body.validation_rules is not None:
        cols.append("validation_rules = %s")
        vals.append(Json(body.validation_rules))
    if body.is_active is not None:
        cols.append("is_active = %s")
        vals.append(body.is_active)

    if not cols:
        raise HTTPException(400, "Keine Felder zum Aktualisieren")

    vals.append(param_id)
    with get_db() as conn:
        cur = get_cursor(conn)
        cur.execute(
            f"UPDATE training_parameters SET {', '.join(cols)} WHERE id = %s RETURNING id",
            vals,
        )
        if not cur.fetchone():
            raise HTTPException(404, "Parameter nicht gefunden")
        conn.commit()
    return {"ok": True, "id": param_id}


@router.delete("/{param_id}")
def admin_deactivate_training_parameter(
    param_id: int,
    session: dict = Depends(require_admin),
):
    """Soft-delete: is_active = false (FK von session_metrics verhindert hartes Löschen)."""
    with get_db() as conn:
        cur = get_cursor(conn)
        cur.execute(
            "UPDATE training_parameters SET is_active = false WHERE id = %s RETURNING id",
            (param_id,),
        )
        if not cur.fetchone():
            raise HTTPException(404, "Parameter nicht gefunden")
        conn.commit()
    return {"ok": True, "id": param_id}
