"""
Admin Management Endpoints for Mitai Jinkendo

Handles user management, permissions, and email testing (admin-only).
"""
import os
import smtplib
from email.mime.text import MIMEText
from datetime import datetime
from typing import Any

from fastapi import APIRouter, HTTPException, Depends

from db import get_db, get_cursor, r2d
from auth import require_admin, hash_pin
from models import AdminProfileUpdate
from dashboard_layout_schema import ALLOWED_WIDGET_IDS, DashboardLayoutPayload, product_default_layout_dict
from dashboard_widget_entitlements import widgets_catalog_admin_payload
from widget_catalog import WIDGET_CATALOG
from widget_feature_requirements_db import (
    clear_custom_requirements,
    fetch_assignments_bundle,
    set_custom_requirements,
)
from system_dashboard_product_default import (
    delete_product_default_override,
    get_product_default_base_dict,
    get_stored_product_default_validated,
    upsert_product_default_base,
)

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


@router.get("/profiles")
def admin_list_profiles(session: dict=Depends(require_admin)):
    """Admin: List all profiles with stats."""
    with get_db() as conn:
        cur = get_cursor(conn)
        cur.execute("SELECT * FROM profiles ORDER BY created")
        profs = [r2d(r) for r in cur.fetchall()]

        for p in profs:
            pid = p['id']
            cur.execute("SELECT COUNT(*) as count FROM weight_log WHERE profile_id=%s", (pid,))
            p['weight_count'] = cur.fetchone()['count']
            cur.execute("SELECT COUNT(*) as count FROM ai_insights WHERE profile_id=%s", (pid,))
            p['ai_insights_count'] = cur.fetchone()['count']

            today = datetime.now().date().isoformat()
            cur.execute("SELECT call_count FROM ai_usage WHERE profile_id=%s AND date=%s", (pid, today))
            usage = cur.fetchone()
            p['ai_usage_today'] = usage['call_count'] if usage else 0

    return profs


@router.put("/profiles/{pid}")
def admin_update_profile(pid: str, data: AdminProfileUpdate, session: dict=Depends(require_admin)):
    """Admin: Update profile settings."""
    with get_db() as conn:
        updates = {k:v for k,v in data.model_dump().items() if v is not None}
        if not updates:
            return {"ok": True}

        cur = get_cursor(conn)
        cur.execute(f"UPDATE profiles SET {', '.join(f'{k}=%s' for k in updates)} WHERE id=%s",
            list(updates.values()) + [pid])

    return {"ok": True}


@router.put("/profiles/{pid}/permissions")
def admin_set_permissions(pid: str, data: dict, session: dict=Depends(require_admin)):
    """Admin: Set profile permissions."""
    with get_db() as conn:
        cur = get_cursor(conn)
        updates = []
        values = []
        if 'ai_enabled' in data:
            updates.append('ai_enabled=%s')
            values.append(data['ai_enabled'])
        if 'ai_limit_day' in data:
            updates.append('ai_limit_day=%s')
            values.append(data['ai_limit_day'])
        if 'export_enabled' in data:
            updates.append('export_enabled=%s')
            values.append(data['export_enabled'])
        if 'role' in data:
            updates.append('role=%s')
            values.append(data['role'])

        if updates:
            cur.execute(f"UPDATE profiles SET {', '.join(updates)} WHERE id=%s", values + [pid])

    return {"ok": True}


@router.put("/profiles/{pid}/email")
def admin_set_email(pid: str, data: dict, session: dict=Depends(require_admin)):
    """Admin: Set profile email."""
    email = data.get('email', '').strip().lower()
    with get_db() as conn:
        cur = get_cursor(conn)
        cur.execute("UPDATE profiles SET email=%s WHERE id=%s", (email if email else None, pid))

    return {"ok": True}


@router.put("/profiles/{pid}/pin")
def admin_set_pin(pid: str, data: dict, session: dict=Depends(require_admin)):
    """Admin: Set profile PIN/password."""
    new_pin = data.get('pin', '')
    if len(new_pin) < 4:
        raise HTTPException(400, "PIN/Passwort muss mind. 4 Zeichen haben")

    new_hash = hash_pin(new_pin)
    with get_db() as conn:
        cur = get_cursor(conn)
        cur.execute("UPDATE profiles SET pin_hash=%s WHERE id=%s", (new_hash, pid))

    return {"ok": True}


@router.get("/email/status")
def admin_email_status(session: dict=Depends(require_admin)):
    """Admin: Check email configuration status."""
    smtp_host = os.getenv("SMTP_HOST")
    smtp_user = os.getenv("SMTP_USER")
    smtp_pass = os.getenv("SMTP_PASS")
    app_url = os.getenv("APP_URL", "http://localhost:3002")

    configured = bool(smtp_host and smtp_user and smtp_pass)

    return {
        "configured": configured,
        "smtp_host": smtp_host or "",
        "smtp_user": smtp_user or "",
        "app_url": app_url
    }


@router.post("/email/test")
def admin_test_email(data: dict, session: dict=Depends(require_admin)):
    """Admin: Send test email."""
    email = data.get('to', '')
    if not email:
        raise HTTPException(400, "E-Mail-Adresse fehlt")

    try:
        smtp_host = os.getenv("SMTP_HOST")
        smtp_port = int(os.getenv("SMTP_PORT", 587))
        smtp_user = os.getenv("SMTP_USER")
        smtp_pass = os.getenv("SMTP_PASS")
        smtp_from = os.getenv("SMTP_FROM")

        if not smtp_host or not smtp_user or not smtp_pass:
            raise HTTPException(500, "SMTP nicht konfiguriert")

        msg = MIMEText("Dies ist eine Test-E-Mail von Mitai Jinkendo.")
        msg['Subject'] = "Test-E-Mail"
        msg['From'] = smtp_from
        msg['To'] = email

        with smtplib.SMTP(smtp_host, smtp_port) as server:
            server.starttls()
            server.login(smtp_user, smtp_pass)
            server.send_message(msg)

        return {"ok": True, "message": f"Test-E-Mail an {email} gesendet"}
    except Exception as e:
        raise HTTPException(500, f"Fehler beim Senden: {str(e)}")


@router.get("/widgets/catalog-full")
def admin_widgets_catalog_full(session: dict = Depends(require_admin)):
    """Dashboard-Widget-Katalog ohne Feature-Filter (Konfiguration des Produkt-Standards)."""
    _ = session
    return widgets_catalog_admin_payload()


@router.get("/dashboard-product-default")
def admin_get_dashboard_product_default(session: dict = Depends(require_admin)):
    """Aktueller Produkt-Dashboard-Standard (DB oder Code)."""
    _ = session
    with get_db() as conn:
        layout = get_product_default_base_dict(conn)
        from_database = get_stored_product_default_validated(conn) is not None
        code_ref = product_default_layout_dict()
    return {
        "from_database": from_database,
        "layout": layout,
        "code_reference": code_ref,
    }


@router.put("/dashboard-product-default")
def admin_put_dashboard_product_default(
    body: dict[str, Any],
    session: dict = Depends(require_admin),
):
    """System-Standard persistieren (JSON wie Nutzer-Layout v1)."""
    _ = session
    try:
        payload = DashboardLayoutPayload.model_validate(body)
    except Exception as e:
        raise HTTPException(422, str(e)) from e
    stored = payload.to_stored_dict()
    with get_db() as conn:
        upsert_product_default_base(conn, stored)
    return {"ok": True, "layout": stored, "from_database": True}


@router.delete("/dashboard-product-default")
def admin_delete_dashboard_product_default(session: dict = Depends(require_admin)):
    """DB-Override entfernen; App fällt auf Code-Standard zurück."""
    _ = session
    with get_db() as conn:
        delete_product_default_override(conn)
        layout = get_product_default_base_dict(conn)
    return {"ok": True, "layout": layout, "from_database": False}


@router.get("/widget-feature-assignments")
def admin_list_widget_feature_assignments(session: dict = Depends(require_admin)):
    """Alle Katalog-Widgets mit Custom-/Katalog-Feature-Listen zur Admin-Pflege."""
    _ = session
    with get_db() as conn:
        custom_ids, by_w = fetch_assignments_bundle(conn)
        cur = get_cursor(conn)
        cur.execute(
            """
            SELECT id, name, category, active
            FROM features
            ORDER BY category NULLS LAST, name
            """
        )
        features = [r2d(r) for r in cur.fetchall()]
    widgets_out: list[dict[str, Any]] = []
    for e in WIDGET_CATALOG:
        wid = e["id"]
        cf = e.get("requires_feature")
        code_fids = [cf] if cf else []
        uses_custom = wid in custom_ids
        widgets_out.append(
            {
                "id": wid,
                "title": e["title"],
                "description": e["description"],
                "uses_custom_requirements": uses_custom,
                "feature_ids": list(by_w.get(wid, [])) if uses_custom else [],
                "catalog_feature_ids": code_fids,
            }
        )
    return {"widgets": widgets_out, "features": features}


@router.put("/widget-feature-assignments/{widget_id}")
def admin_put_widget_feature_assignment(
    widget_id: str,
    body: dict[str, Any],
    session: dict = Depends(require_admin),
):
    """
    mode=catalog: Katalog-Fallback (requires_feature im Code).
    mode=custom: AND über feature_ids (leere Liste = Widget ohne Feature-Gate).
    """
    _ = session
    if widget_id not in ALLOWED_WIDGET_IDS:
        raise HTTPException(404, "Unbekanntes Widget")
    mode = body.get("mode", "custom")
    if mode == "catalog":
        with get_db() as conn:
            clear_custom_requirements(conn, widget_id)
        return {"ok": True, "widget_id": widget_id, "uses_custom_requirements": False, "feature_ids": []}
    if mode != "custom":
        raise HTTPException(422, "mode muss catalog oder custom sein")
    raw_ids = body.get("feature_ids")
    if not isinstance(raw_ids, list):
        raise HTTPException(422, "feature_ids muss Liste sein")
    cleaned = [str(x).strip() for x in raw_ids if x is not None and str(x).strip()]
    with get_db() as conn:
        cur = get_cursor(conn)
        for fid in cleaned:
            cur.execute("SELECT id FROM features WHERE id = %s", (fid,))
            if not cur.fetchone():
                raise HTTPException(422, f"Unbekanntes Feature: {fid}")
        set_custom_requirements(conn, widget_id, cleaned)
    return {
        "ok": True,
        "widget_id": widget_id,
        "uses_custom_requirements": True,
        "feature_ids": cleaned,
    }
