"""
Rechtstexte (Impressum, Datenschutz, Nutzungsbedingungen, Medienrichtlinie).

Öffentlich (kein Auth):
  GET /api/legal-documents/{document_type}/published

Superadmin only:
  GET    /api/admin/legal-documents                          – Liste aller Versionen
  POST   /api/admin/legal-documents                          – Neuen Entwurf anlegen
  GET    /api/admin/legal-documents/{id}                     – Einzelnes Dokument
  PUT    /api/admin/legal-documents/{id}                     – Entwurf bearbeiten
  POST   /api/admin/legal-documents/{id}/publish             – Veröffentlichen
  POST   /api/admin/legal-documents/{id}/archive             – Archivieren
  GET    /api/admin/legal-documents/{id}/audit               – Änderungslog
"""
from typing import Any, Dict, List, Optional

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

from auth import require_auth
from club_tenancy import is_superadmin
from db import get_db, get_cursor, r2d

# ACCESS_LAYER exempt: Plattform-Rechtstexte ohne Vereinsbezug.
# Öffentlicher GET-Endpoint ohne jegliche Auth; Admin-Endpoints nutzen require_auth + is_superadmin().
# Eingetragen in backend/scripts/check_access_layer_hints.py EXEMPT_ROUTERS.
router = APIRouter(tags=["legal_documents"])

VALID_TYPES = {"impressum", "privacy_policy", "terms_of_use", "media_policy"}


def _require_superadmin(session: dict):
    role = (session.get("role") or "").lower()
    if not is_superadmin(role):
        raise HTTPException(status_code=403, detail="Nur Superadmins")
    return session


class LegalDocumentCreate(BaseModel):
    document_type: str
    title: str
    content_sections: List[Dict[str, Any]] = []
    change_note: Optional[str] = None


class LegalDocumentUpdate(BaseModel):
    title: Optional[str] = None
    content_sections: Optional[List[Dict[str, Any]]] = None
    change_note: Optional[str] = None


class PublishRequest(BaseModel):
    change_note: Optional[str] = None


# ─── Public endpoint ────────────────────────────────────────────────────────

@router.get("/api/legal-documents/{document_type}/published")
def get_published_legal_document(document_type: str):
    """Liefert das aktuell veröffentlichte Dokument oder null. Kein Auth erforderlich."""
    if document_type not in VALID_TYPES:
        raise HTTPException(status_code=404, detail="Unbekannter Dokumententyp")

    with get_db() as conn:
        cur = get_cursor(conn)
        cur.execute(
            """
            SELECT id, document_type, version, title, content_sections,
                   status, change_note, published_at, updated_at
            FROM legal_documents
            WHERE document_type = %s AND status = 'published'
            LIMIT 1
            """,
            (document_type,),
        )
        row = cur.fetchone()

    if not row:
        return None

    doc = r2d(row)
    return doc


# ─── Superadmin endpoints ────────────────────────────────────────────────────

@router.get("/api/admin/legal-documents")
def list_legal_documents(
    document_type: Optional[str] = None,
    session: dict = Depends(require_auth),
):
    """Alle Versionen aller Rechtstexte (oder gefiltert nach document_type)."""
    _require_superadmin(session)

    with get_db() as conn:
        cur = get_cursor(conn)
        if document_type:
            cur.execute(
                """
                SELECT d.id, d.document_type, d.version, d.title, d.status,
                       d.change_note, d.created_at, d.updated_at, d.published_at,
                       p.name AS created_by_name
                FROM legal_documents d
                LEFT JOIN profiles p ON p.id = d.created_by_profile_id
                WHERE d.document_type = %s
                ORDER BY d.document_type, d.version DESC
                """,
                (document_type,),
            )
        else:
            cur.execute(
                """
                SELECT d.id, d.document_type, d.version, d.title, d.status,
                       d.change_note, d.created_at, d.updated_at, d.published_at,
                       p.name AS created_by_name
                FROM legal_documents d
                LEFT JOIN profiles p ON p.id = d.created_by_profile_id
                ORDER BY d.document_type, d.version DESC
                """
            )
        rows = cur.fetchall()

    return [r2d(r) for r in rows]


@router.post("/api/admin/legal-documents", status_code=201)
def create_legal_document(
    body: LegalDocumentCreate,
    session: dict = Depends(require_auth),
):
    """Neuen Entwurf anlegen. Versionsnummer = max(vorherige) + 1."""
    _require_superadmin(session)

    if body.document_type not in VALID_TYPES:
        raise HTTPException(status_code=422, detail="Ungültiger document_type")

    profile_id = session["profile_id"]

    import json as _json
    sections_json = _json.dumps(body.content_sections, ensure_ascii=False)

    with get_db() as conn:
        cur = get_cursor(conn)
        cur.execute(
            "SELECT COALESCE(MAX(version), 0) FROM legal_documents WHERE document_type = %s",
            (body.document_type,),
        )
        row = cur.fetchone()
        next_version = list(row.values())[0] + 1

        cur.execute(
            """
            INSERT INTO legal_documents
                (document_type, version, title, content_sections, status, change_note, created_by_profile_id)
            VALUES (%s, %s, %s, %s::jsonb, 'draft', %s, %s)
            RETURNING id, document_type, version, title, content_sections,
                      status, change_note, created_at, updated_at
            """,
            (body.document_type, next_version, body.title, sections_json, body.change_note, profile_id),
        )
        new_row = cur.fetchone()
        new_id = list(new_row.values())[0]

        cur.execute(
            """
            INSERT INTO legal_document_audit (legal_document_id, action, changed_by_profile_id, change_note)
            VALUES (%s, 'created', %s, %s)
            """,
            (new_id, profile_id, body.change_note),
        )
        conn.commit()

    return r2d(new_row)


@router.get("/api/admin/legal-documents/{doc_id}")
def get_legal_document(doc_id: int, session: dict = Depends(require_auth)):
    """Einzelnes Dokument (alle Felder inkl. content_sections)."""
    _require_superadmin(session)

    with get_db() as conn:
        cur = get_cursor(conn)
        cur.execute(
            """
            SELECT d.id, d.document_type, d.version, d.title, d.content_sections,
                   d.status, d.change_note, d.created_at, d.updated_at,
                   d.published_at, d.created_by_profile_id,
                   p.name AS created_by_name,
                   pb.name AS published_by_name
            FROM legal_documents d
            LEFT JOIN profiles p  ON p.id  = d.created_by_profile_id
            LEFT JOIN profiles pb ON pb.id = d.published_by_profile_id
            WHERE d.id = %s
            """,
            (doc_id,),
        )
        row = cur.fetchone()

    if not row:
        raise HTTPException(status_code=404, detail="Dokument nicht gefunden")

    return r2d(row)


@router.put("/api/admin/legal-documents/{doc_id}")
def update_legal_document(
    doc_id: int,
    body: LegalDocumentUpdate,
    session: dict = Depends(require_auth),
):
    """Entwurf bearbeiten. Nur status='draft' kann bearbeitet werden."""
    _require_superadmin(session)

    profile_id = session["profile_id"]

    with get_db() as conn:
        cur = get_cursor(conn)
        cur.execute(
            "SELECT id, status, title, content_sections, change_note FROM legal_documents WHERE id = %s",
            (doc_id,),
        )
        row = cur.fetchone()

    if not row:
        raise HTTPException(status_code=404, detail="Dokument nicht gefunden")

    doc = r2d(row)
    if doc["status"] != "draft":
        raise HTTPException(status_code=409, detail="Nur Entwürfe können bearbeitet werden")

    import json as _json

    new_title = body.title if body.title is not None else doc["title"]
    new_sections = body.content_sections if body.content_sections is not None else doc["content_sections"]
    new_note = body.change_note if body.change_note is not None else doc["change_note"]
    sections_json = _json.dumps(new_sections, ensure_ascii=False)

    with get_db() as conn:
        cur = get_cursor(conn)
        cur.execute(
            """
            UPDATE legal_documents
            SET title = %s, content_sections = %s::jsonb, change_note = %s, updated_at = NOW()
            WHERE id = %s
            RETURNING id, document_type, version, title, content_sections,
                      status, change_note, created_at, updated_at
            """,
            (new_title, sections_json, new_note, doc_id),
        )
        updated = cur.fetchone()

        cur.execute(
            """
            INSERT INTO legal_document_audit (legal_document_id, action, changed_by_profile_id, change_note)
            VALUES (%s, 'updated', %s, %s)
            """,
            (doc_id, profile_id, new_note),
        )
        conn.commit()

    return r2d(updated)


@router.post("/api/admin/legal-documents/{doc_id}/publish")
def publish_legal_document(
    doc_id: int,
    body: PublishRequest = PublishRequest(),
    session: dict = Depends(require_auth),
):
    """
    Veröffentlicht dieses Dokument. Ein bisher veröffentlichtes Dokument desselben
    Typs wird automatisch auf 'archived' gesetzt (partial unique index erzwingt dies).
    """
    _require_superadmin(session)

    profile_id = session["profile_id"]

    with get_db() as conn:
        cur = get_cursor(conn)
        cur.execute(
            "SELECT id, document_type, status FROM legal_documents WHERE id = %s",
            (doc_id,),
        )
        row = cur.fetchone()

    if not row:
        raise HTTPException(status_code=404, detail="Dokument nicht gefunden")

    doc = r2d(row)
    if doc["status"] == "published":
        raise HTTPException(status_code=409, detail="Dokument ist bereits veröffentlicht")
    if doc["status"] == "archived":
        raise HTTPException(status_code=409, detail="Archivierte Dokumente können nicht veröffentlicht werden")

    with get_db() as conn:
        cur = get_cursor(conn)
        # Vorheriges published-Dokument desselben Typs archivieren
        cur.execute(
            """
            UPDATE legal_documents
            SET status = 'archived', updated_at = NOW()
            WHERE document_type = %s AND status = 'published' AND id != %s
            """,
            (doc["document_type"], doc_id),
        )
        # Dieses Dokument veröffentlichen
        cur.execute(
            """
            UPDATE legal_documents
            SET status = 'published', published_at = NOW(),
                published_by_profile_id = %s, updated_at = NOW()
            WHERE id = %s
            RETURNING id, document_type, version, title, content_sections,
                      status, change_note, published_at, updated_at
            """,
            (profile_id, doc_id),
        )
        updated = cur.fetchone()

        cur.execute(
            """
            INSERT INTO legal_document_audit
                (legal_document_id, action, changed_by_profile_id, change_note, previous_status)
            VALUES (%s, 'published', %s, %s, %s)
            """,
            (doc_id, profile_id, body.change_note, doc["status"]),
        )
        conn.commit()

    return r2d(updated)


@router.post("/api/admin/legal-documents/{doc_id}/archive")
def archive_legal_document(
    doc_id: int,
    session: dict = Depends(require_auth),
):
    """Archiviert ein Dokument. Veröffentlichte Dokumente dürfen nur archiviert werden wenn kein anderes published ist."""
    _require_superadmin(session)

    profile_id = session["profile_id"]

    with get_db() as conn:
        cur = get_cursor(conn)
        cur.execute(
            "SELECT id, status FROM legal_documents WHERE id = %s",
            (doc_id,),
        )
        row = cur.fetchone()

    if not row:
        raise HTTPException(status_code=404, detail="Dokument nicht gefunden")

    doc = r2d(row)
    if doc["status"] == "archived":
        raise HTTPException(status_code=409, detail="Dokument ist bereits archiviert")

    prev_status = doc["status"]

    with get_db() as conn:
        cur = get_cursor(conn)
        cur.execute(
            """
            UPDATE legal_documents
            SET status = 'archived', updated_at = NOW()
            WHERE id = %s
            RETURNING id, document_type, version, title, status, updated_at
            """,
            (doc_id,),
        )
        updated = cur.fetchone()

        cur.execute(
            """
            INSERT INTO legal_document_audit
                (legal_document_id, action, changed_by_profile_id, previous_status)
            VALUES (%s, 'archived', %s, %s)
            """,
            (doc_id, profile_id, prev_status),
        )
        conn.commit()

    return r2d(updated)


@router.post("/api/admin/legal-documents/{doc_id}/copy-as-draft", status_code=201)
def copy_legal_document_as_draft(
    doc_id: int,
    session: dict = Depends(require_auth),
):
    """
    Kopiert ein beliebiges Dokument (egal welcher Status) als neuen Entwurf mit
    nächster Versionsnummer. Inhalt und Titel werden übernommen.
    """
    _require_superadmin(session)

    profile_id = session["profile_id"]

    with get_db() as conn:
        cur = get_cursor(conn)
        cur.execute(
            "SELECT id, document_type, title, content_sections FROM legal_documents WHERE id = %s",
            (doc_id,),
        )
        row = cur.fetchone()

    if not row:
        raise HTTPException(status_code=404, detail="Dokument nicht gefunden")

    src = r2d(row)

    import json as _json
    sections_json = _json.dumps(src["content_sections"], ensure_ascii=False)

    with get_db() as conn:
        cur = get_cursor(conn)
        cur.execute(
            "SELECT COALESCE(MAX(version), 0) FROM legal_documents WHERE document_type = %s",
            (src["document_type"],),
        )
        row2 = cur.fetchone()
        next_version = list(row2.values())[0] + 1

        cur.execute(
            """
            INSERT INTO legal_documents
                (document_type, version, title, content_sections, status, change_note, created_by_profile_id)
            VALUES (%s, %s, %s, %s::jsonb, 'draft', NULL, %s)
            RETURNING id, document_type, version, title, content_sections,
                      status, change_note, created_at, updated_at
            """,
            (src["document_type"], next_version, src["title"], sections_json, profile_id),
        )
        new_row = cur.fetchone()
        new_id = list(new_row.values())[0]

        cur.execute(
            """
            INSERT INTO legal_document_audit
                (legal_document_id, action, changed_by_profile_id, change_note)
            VALUES (%s, 'created', %s, %s)
            """,
            (new_id, profile_id, f"Kopie von Version {src.get('version', '?')} (ID {doc_id})"),
        )
        conn.commit()

    return r2d(new_row)


@router.get("/api/admin/legal-documents/{doc_id}/audit")
def get_legal_document_audit(doc_id: int, session: dict = Depends(require_auth)):
    """Änderungslog für ein Dokument."""
    _require_superadmin(session)

    with get_db() as conn:
        cur = get_cursor(conn)
        cur.execute("SELECT id FROM legal_documents WHERE id = %s", (doc_id,))
        if not cur.fetchone():
            raise HTTPException(status_code=404, detail="Dokument nicht gefunden")

        cur.execute(
            """
            SELECT a.id, a.action, a.change_note, a.previous_status, a.created_at,
                   p.name AS changed_by_name
            FROM legal_document_audit a
            LEFT JOIN profiles p ON p.id = a.changed_by_profile_id
            WHERE a.legal_document_id = %s
            ORDER BY a.created_at DESC
            """,
            (doc_id,),
        )
        rows = cur.fetchall()

    return [r2d(r) for r in rows]
