"""
Admin: training_category_parameter + training_type_parameter (attribute profiles).

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

from fastapi import APIRouter, Depends, HTTPException, Query
from pydantic import BaseModel, Field

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

router = APIRouter(prefix="/api/admin", tags=["admin", "activity-attribute-profiles"])


class CategoryParameterCreate(BaseModel):
    training_category: str = Field(..., min_length=1, max_length=50)
    training_parameter_id: int
    sort_order: int = 0
    required: bool = False
    ui_group: Optional[str] = Field(None, max_length=50)


class TypeParameterCreate(BaseModel):
    training_type_id: int
    training_parameter_id: int
    sort_order: Optional[int] = None
    required: Optional[bool] = None
    ui_group: Optional[str] = Field(None, max_length=50)


class CategoryParameterUpdate(BaseModel):
    sort_order: Optional[int] = None
    required: Optional[bool] = None
    ui_group: Optional[str] = Field(None, max_length=50)


class TypeParameterUpdate(BaseModel):
    sort_order: Optional[int] = None
    required: Optional[bool] = None
    ui_group: Optional[str] = Field(None, max_length=50)


@router.get("/training-category-parameters")
def admin_list_category_parameters(
    category: Optional[str] = Query(None, description="Filter: training_types.category"),
    session: dict = Depends(require_admin),
):
    with get_db() as conn:
        cur = get_cursor(conn)
        if category:
            cur.execute(
                """
                SELECT tcp.*, tp.key AS parameter_key, tp.name_de AS parameter_name_de
                FROM training_category_parameter tcp
                JOIN training_parameters tp ON tp.id = tcp.training_parameter_id
                WHERE tcp.training_category = %s
                ORDER BY tcp.sort_order, tp.key
                """,
                (category.strip(),),
            )
        else:
            cur.execute(
                """
                SELECT tcp.*, tp.key AS parameter_key, tp.name_de AS parameter_name_de
                FROM training_category_parameter tcp
                JOIN training_parameters tp ON tp.id = tcp.training_parameter_id
                ORDER BY tcp.training_category, tcp.sort_order, tp.key
                """
            )
        return [r2d(r) for r in cur.fetchall()]


@router.post("/training-category-parameters")
def admin_add_category_parameter(
    body: CategoryParameterCreate,
    session: dict = Depends(require_admin),
):
    cat = body.training_category.strip()
    with get_db() as conn:
        cur = get_cursor(conn)
        cur.execute("SELECT id FROM training_parameters WHERE id = %s", (body.training_parameter_id,))
        if not cur.fetchone():
            raise HTTPException(404, "training_parameter_id unbekannt")
        try:
            cur.execute(
                """
                INSERT INTO training_category_parameter (
                    training_category, training_parameter_id, sort_order, required, ui_group
                ) VALUES (%s,%s,%s,%s,%s)
                RETURNING id
                """,
                (cat, body.training_parameter_id, body.sort_order, body.required, body.ui_group),
            )
            new_id = cur.fetchone()["id"]
            conn.commit()
        except Exception as e:
            conn.rollback()
            if "uq_training_category_parameter" in str(e).lower() or "unique" in str(e).lower():
                raise HTTPException(409, "Zuordnung existiert bereits") from e
            raise HTTPException(400, str(e)) from e
    return {"id": new_id}


@router.put("/training-category-parameters/{link_id}")
def admin_update_category_parameter(
    link_id: int,
    body: CategoryParameterUpdate,
    session: dict = Depends(require_admin),
):
    patch = body.model_dump(exclude_unset=True)
    if not patch:
        raise HTTPException(400, "Keine Felder zum Aktualisieren")
    cols: list[str] = []
    vals: list = []
    if "sort_order" in patch:
        cols.append("sort_order = %s")
        vals.append(patch["sort_order"])
    if "required" in patch:
        cols.append("required = %s")
        vals.append(patch["required"])
    if "ui_group" in patch:
        cols.append("ui_group = %s")
        vals.append(patch["ui_group"].strip() if patch["ui_group"] else None)
    if not cols:
        raise HTTPException(400, "Keine Felder zum Aktualisieren")
    vals.append(link_id)
    with get_db() as conn:
        cur = get_cursor(conn)
        cur.execute(
            f"UPDATE training_category_parameter SET {', '.join(cols)} WHERE id = %s RETURNING id",
            vals,
        )
        if not cur.fetchone():
            raise HTTPException(404, "Eintrag nicht gefunden")
        conn.commit()
    return {"ok": True, "id": link_id}


@router.delete("/training-category-parameters/{link_id}")
def admin_delete_category_parameter(
    link_id: int,
    session: dict = Depends(require_admin),
):
    with get_db() as conn:
        cur = get_cursor(conn)
        cur.execute(
            "DELETE FROM training_category_parameter WHERE id = %s RETURNING id",
            (link_id,),
        )
        if not cur.fetchone():
            raise HTTPException(404, "Eintrag nicht gefunden")
        conn.commit()
    return {"ok": True}


@router.get("/training-type-parameters")
def admin_list_type_parameters(
    training_type_id: int = Query(..., ge=1),
    session: dict = Depends(require_admin),
):
    with get_db() as conn:
        cur = get_cursor(conn)
        cur.execute(
            """
            SELECT ttp.*, tp.key AS parameter_key, tp.name_de AS parameter_name_de
            FROM training_type_parameter ttp
            JOIN training_parameters tp ON tp.id = ttp.training_parameter_id
            WHERE ttp.training_type_id = %s
            ORDER BY ttp.sort_order NULLS LAST, tp.key
            """,
            (training_type_id,),
        )
        return [r2d(r) for r in cur.fetchall()]


@router.post("/training-type-parameters")
def admin_add_type_parameter(
    body: TypeParameterCreate,
    session: dict = Depends(require_admin),
):
    with get_db() as conn:
        cur = get_cursor(conn)
        cur.execute("SELECT id FROM training_types WHERE id = %s", (body.training_type_id,))
        if not cur.fetchone():
            raise HTTPException(404, "training_type_id unbekannt")
        cur.execute("SELECT id FROM training_parameters WHERE id = %s", (body.training_parameter_id,))
        if not cur.fetchone():
            raise HTTPException(404, "training_parameter_id unbekannt")
        try:
            cur.execute(
                """
                INSERT INTO training_type_parameter (
                    training_type_id, training_parameter_id, sort_order, required, ui_group
                ) VALUES (%s,%s,%s,%s,%s)
                RETURNING id
                """,
                (
                    body.training_type_id,
                    body.training_parameter_id,
                    body.sort_order,
                    body.required,
                    body.ui_group,
                ),
            )
            new_id = cur.fetchone()["id"]
            conn.commit()
        except Exception as e:
            conn.rollback()
            if "uq_training_type_parameter" in str(e).lower() or "unique" in str(e).lower():
                raise HTTPException(409, "Zuordnung existiert bereits") from e
            raise HTTPException(400, str(e)) from e
    return {"id": new_id}


@router.put("/training-type-parameters/{link_id}")
def admin_update_type_parameter(
    link_id: int,
    body: TypeParameterUpdate,
    session: dict = Depends(require_admin),
):
    patch = body.model_dump(exclude_unset=True)
    if not patch:
        raise HTTPException(400, "Keine Felder zum Aktualisieren")
    cols: list[str] = []
    vals: list = []
    if "sort_order" in patch:
        cols.append("sort_order = %s")
        vals.append(patch["sort_order"])
    if "required" in patch:
        cols.append("required = %s")
        vals.append(patch["required"])
    if "ui_group" in patch:
        cols.append("ui_group = %s")
        vals.append(patch["ui_group"].strip() if patch["ui_group"] else None)
    if not cols:
        raise HTTPException(400, "Keine Felder zum Aktualisieren")
    vals.append(link_id)
    with get_db() as conn:
        cur = get_cursor(conn)
        cur.execute(
            f"UPDATE training_type_parameter SET {', '.join(cols)} WHERE id = %s RETURNING id",
            vals,
        )
        if not cur.fetchone():
            raise HTTPException(404, "Eintrag nicht gefunden")
        conn.commit()
    return {"ok": True, "id": link_id}


@router.delete("/training-type-parameters/{link_id}")
def admin_delete_type_parameter(
    link_id: int,
    session: dict = Depends(require_admin),
):
    with get_db() as conn:
        cur = get_cursor(conn)
        cur.execute(
            "DELETE FROM training_type_parameter WHERE id = %s RETURNING id",
            (link_id,),
        )
        if not cur.fetchone():
            raise HTTPException(404, "Eintrag nicht gefunden")
        conn.commit()
    return {"ok": True}
