"""P-11: Legal-Hold-Services fuer Medien-Assets.

Sofortsperrung bei Rechtsverletzungen (Compliance-Paket P-11).

Klare Trennung:
- P-06: Rechteerklaerungs-/Deklarationsstatus (rights_status='declared'/'legacy_unreviewed')
- P-11: Legal-Hold-Sperre (legal_hold_active + Metadaten)
- P-03: Normaler Papierkorb-Lifecycle (lifecycle_state)
- P-13: Meldeverfahren (spaeter; nutzt denselben set_legal_hold-Service)

Berechtigungen:
- Setzen und Aufheben: ausschliesslich Superadmin.
- Lesezugriff auf Legal-Hold-Status: Superadmin und Plattform-Admin.
"""
from __future__ import annotations

from typing import Any, Optional

from fastapi import HTTPException

from club_tenancy import is_superadmin
from media_rights import write_audit_log_entry

LEGAL_HOLD_REASON_CODES = {
    "rights_dispute",
    "consent_withdrawn",
    "privacy_complaint",
    "copyright_complaint",
    "youth_protection",
    "illegal_content",
    "other",
}


def assert_superadmin_for_legal_hold(role: Optional[str]) -> None:
    if not is_superadmin(role):
        raise HTTPException(
            status_code=403,
            detail="Legal-Hold-Aktionen sind nur fuer Superadmins verfuegbar.",
        )


def is_media_available_for_normal_use(asset: dict) -> bool:
    """True wenn das Medium fuer normale Nutzerpfade verfuegbar ist.

    Ein Medium ist NICHT verfuegbar wenn legal_hold_active = True,
    unabhaengig vom lifecycle_state.
    """
    return not bool(asset.get("legal_hold_active"))


def assert_not_under_legal_hold(asset: dict) -> None:
    """Wirft HTTPException 403 wenn das Medium unter Legal Hold steht."""
    if bool(asset.get("legal_hold_active")):
        raise HTTPException(
            status_code=403,
            detail={
                "code": "LEGAL_HOLD_ACTIVE",
                "message": (
                    "Dieses Medium ist durch einen Administrator sofort gesperrt und "
                    "kann nicht verwendet werden."
                ),
                "asset_id": asset.get("id"),
            },
        )


def set_legal_hold(
    cur: Any,
    conn: Any,
    asset_id: int,
    acting_profile_id: int,
    reason_code: str,
    reason_note: Optional[str],
) -> dict:
    """Setzt Legal Hold auf ein Medium. Nur Superadmin.

    Wirkung:
    - legal_hold_active = TRUE
    - legal_hold_reason_code, legal_hold_reason_note, legal_hold_set_by_profile_id, legal_hold_set_at
    - rights_status = 'blocked' (Spiegel fuer schnelle Checks)
    - Audit-Log-Eintrag 'legal_hold_set'

    Gibt das aktualisierte Asset-Dict zurueck.
    """
    if reason_code not in LEGAL_HOLD_REASON_CODES:
        raise HTTPException(
            status_code=400,
            detail=f"Ungueltiger reason_code. Erlaubt: {sorted(LEGAL_HOLD_REASON_CODES)}",
        )
    if not reason_note or not reason_note.strip():
        raise HTTPException(
            status_code=400,
            detail="reason_note (Begruendung) ist Pflicht beim Setzen eines Legal Holds.",
        )

    cur.execute(
        """SELECT id, legal_hold_active, rights_status, lifecycle_state, visibility
           FROM media_assets WHERE id = %s""",
        (asset_id,),
    )
    from db import r2d
    row = cur.fetchone()
    if not row:
        raise HTTPException(status_code=404, detail="Medium nicht gefunden")
    asset = r2d(row)

    if bool(asset.get("legal_hold_active")):
        raise HTTPException(
            status_code=409,
            detail="Dieses Medium befindet sich bereits unter Legal Hold.",
        )

    old_rights_status = asset.get("rights_status") or "legacy_unreviewed"

    cur.execute(
        """UPDATE media_assets
           SET legal_hold_active              = TRUE,
               legal_hold_reason_code         = %s,
               legal_hold_reason_note         = %s,
               legal_hold_set_by_profile_id   = %s,
               legal_hold_set_at              = NOW(),
               legal_hold_released_by_profile_id = NULL,
               legal_hold_released_at         = NULL,
               legal_hold_release_note        = NULL,
               rights_status                  = 'blocked',
               updated_at                     = NOW()
           WHERE id = %s
           RETURNING id, legal_hold_active, legal_hold_reason_code, legal_hold_reason_note,
                     legal_hold_set_by_profile_id, legal_hold_set_at, rights_status,
                     lifecycle_state, visibility""",
        (reason_code, reason_note.strip()[:2000], acting_profile_id, asset_id),
    )
    updated_row = cur.fetchone()
    updated = r2d(updated_row)

    write_audit_log_entry(
        cur,
        asset_id=asset_id,
        acting_profile_id=acting_profile_id,
        event_type="legal_hold_set",
        old_values={"rights_status": old_rights_status, "legal_hold_active": False},
        new_values={
            "rights_status": "blocked",
            "legal_hold_active": True,
            "reason_code": reason_code,
            "reason_note": reason_note.strip()[:2000] if reason_note else None,
        },
    )

    conn.commit()
    return updated


def release_legal_hold(
    cur: Any,
    conn: Any,
    asset_id: int,
    acting_profile_id: int,
    release_note: Optional[str],
) -> dict:
    """Hebt Legal Hold auf. Nur Superadmin.

    Wirkung:
    - legal_hold_active = FALSE
    - legal_hold_released_by_profile_id, legal_hold_released_at, legal_hold_release_note
    - rights_status: zurueck auf 'declared' wenn vorher declared war, sonst 'legacy_unreviewed'
      (Entscheidungslogik: war vor dem Hold ein Deklarations-Eintrag vorhanden?)
    - Audit-Log-Eintrag 'legal_hold_released'

    Gibt das aktualisierte Asset-Dict zurueck.
    """
    if not release_note or not release_note.strip():
        raise HTTPException(
            status_code=400,
            detail="release_note (Freigabe-Begruendung) ist Pflicht.",
        )

    cur.execute(
        """SELECT id, legal_hold_active, rights_status, lifecycle_state, visibility,
                  legal_hold_reason_code, legal_hold_reason_note
           FROM media_assets WHERE id = %s""",
        (asset_id,),
    )
    from db import r2d
    row = cur.fetchone()
    if not row:
        raise HTTPException(status_code=404, detail="Medium nicht gefunden")
    asset = r2d(row)

    if not bool(asset.get("legal_hold_active")):
        raise HTTPException(
            status_code=409,
            detail="Dieses Medium befindet sich nicht unter Legal Hold.",
        )

    # Bestimme den rights_status nach Freigabe:
    # Gibt es eine gueltige Deklaration? → 'declared', sonst 'legacy_unreviewed'
    cur.execute(
        """SELECT COUNT(*) AS cnt FROM media_asset_rights_declarations
           WHERE media_asset_id = %s
             AND action_type NOT IN ('correction')
             AND rights_holder_confirmed = TRUE""",
        (asset_id,),
    )
    decl_row = cur.fetchone()
    decl_count = int(decl_row[0] if not hasattr(decl_row, "keys") else decl_row["cnt"])
    restored_rights_status = "declared" if decl_count > 0 else "legacy_unreviewed"

    cur.execute(
        """UPDATE media_assets
           SET legal_hold_active                = FALSE,
               legal_hold_released_by_profile_id = %s,
               legal_hold_released_at            = NOW(),
               legal_hold_release_note           = %s,
               rights_status                     = %s,
               updated_at                        = NOW()
           WHERE id = %s
           RETURNING id, legal_hold_active, rights_status, lifecycle_state, visibility,
                     legal_hold_reason_code, legal_hold_reason_note,
                     legal_hold_set_by_profile_id, legal_hold_set_at,
                     legal_hold_released_by_profile_id, legal_hold_released_at,
                     legal_hold_release_note""",
        (acting_profile_id, release_note.strip()[:2000], restored_rights_status, asset_id),
    )
    updated_row = cur.fetchone()
    updated = r2d(updated_row)

    write_audit_log_entry(
        cur,
        asset_id=asset_id,
        acting_profile_id=acting_profile_id,
        event_type="legal_hold_released",
        old_values={
            "rights_status": "blocked",
            "legal_hold_active": True,
            "reason_code": asset.get("legal_hold_reason_code"),
        },
        new_values={
            "rights_status": restored_rights_status,
            "legal_hold_active": False,
            "release_note": release_note.strip()[:2000] if release_note else None,
        },
    )

    conn.commit()
    return updated
