"""
Shared versioning utilities for all compliance document types.

Provides create_version_snapshot() and list_versions() helpers that work
with all 5 version tables (DSFA, VVT, TOM, Loeschfristen, Obligations).
"""

import json
import logging
from typing import Optional, List

from fastapi import APIRouter, Depends, HTTPException, Request
from sqlalchemy import text
from sqlalchemy.orm import Session

from classroom_engine.database import get_db
from .tenant_utils import get_tenant_id

logger = logging.getLogger(__name__)

# Table → FK column mapping
VERSION_TABLES = {
    "dsfa": ("compliance_dsfa_versions", "dsfa_id", "compliance_dsfas"),
    "vvt_activity": ("compliance_vvt_activity_versions", "activity_id", "compliance_vvt_activities"),
    "tom": ("compliance_tom_versions", "measure_id", "compliance_tom_measures"),
    "loeschfristen": ("compliance_loeschfristen_versions", "policy_id", "compliance_loeschfristen"),
    "obligation": ("compliance_obligation_versions", "obligation_id", "compliance_obligations"),
}


def create_version_snapshot(
    db: Session,
    doc_type: str,
    doc_id: str,
    tenant_id: str,
    snapshot: dict,
    change_summary: str = "",
    changed_sections: list = None,
    created_by: str = "system",
) -> dict:
    """Create a new version snapshot for any document type.

    Args:
        doc_type: One of "dsfa", "vvt_activity", "tom", "loeschfristen", "obligation"
        doc_id: UUID of the source document
        tenant_id: Tenant UUID
        snapshot: Full JSONB snapshot of the document state
        change_summary: Human-readable summary of changes
        changed_sections: List of section identifiers that changed
        created_by: User who created this version

    Returns:
        Dict with version info (id, version_number, created_at)
    """
    if doc_type not in VERSION_TABLES:
        raise ValueError(f"Unknown document type: {doc_type}")

    version_table, fk_column, source_table = VERSION_TABLES[doc_type]

    # Get next version number
    result = db.execute(
        text(f"SELECT COALESCE(MAX(version_number), 0) FROM {version_table} WHERE {fk_column} = :doc_id"),
        {"doc_id": doc_id},
    )
    next_version = result.scalar() + 1

    # Insert version
    result = db.execute(
        text(f"""
            INSERT INTO {version_table}
                ({fk_column}, tenant_id, version_number, snapshot, change_summary,
                 changed_sections, created_by)
            VALUES (:doc_id, :tenant_id, :version_number, CAST(:snapshot AS jsonb),
                    :change_summary, CAST(:changed_sections AS jsonb), :created_by)
            RETURNING id, version_number, created_at
        """),
        {
            "doc_id": doc_id,
            "tenant_id": tenant_id,
            "version_number": next_version,
            "snapshot": json.dumps(snapshot),
            "change_summary": change_summary,
            "changed_sections": json.dumps(changed_sections or []),
            "created_by": created_by,
        },
    )
    row = result.fetchone()

    # Update current_version on the source table
    db.execute(
        text(f"UPDATE {source_table} SET current_version = :v WHERE id = :doc_id"),
        {"v": next_version, "doc_id": doc_id},
    )

    return {
        "id": str(row[0]),
        "version_number": row[1],
        "created_at": row[2].isoformat() if row[2] else None,
    }


def list_versions(
    db: Session,
    doc_type: str,
    doc_id: str,
    tenant_id: str,
) -> List[dict]:
    """List all versions for a document, newest first."""
    if doc_type not in VERSION_TABLES:
        raise ValueError(f"Unknown document type: {doc_type}")

    version_table, fk_column, _ = VERSION_TABLES[doc_type]

    result = db.execute(
        text(f"""
            SELECT id, version_number, status, change_summary, changed_sections,
                   created_by, approved_by, approved_at, created_at
            FROM {version_table}
            WHERE {fk_column} = :doc_id AND tenant_id = :tenant_id
            ORDER BY version_number DESC
        """),
        {"doc_id": doc_id, "tenant_id": tenant_id},
    )
    rows = result.fetchall()
    return [
        {
            "id": str(r[0]),
            "version_number": r[1],
            "status": r[2],
            "change_summary": r[3],
            "changed_sections": r[4] or [],
            "created_by": r[5],
            "approved_by": r[6],
            "approved_at": r[7].isoformat() if r[7] else None,
            "created_at": r[8].isoformat() if r[8] else None,
        }
        for r in rows
    ]


def get_version(
    db: Session,
    doc_type: str,
    doc_id: str,
    version_number: int,
    tenant_id: str,
) -> Optional[dict]:
    """Get a specific version with its full snapshot."""
    if doc_type not in VERSION_TABLES:
        raise ValueError(f"Unknown document type: {doc_type}")

    version_table, fk_column, _ = VERSION_TABLES[doc_type]

    result = db.execute(
        text(f"""
            SELECT id, version_number, status, snapshot, change_summary,
                   changed_sections, created_by, approved_by, approved_at, created_at
            FROM {version_table}
            WHERE {fk_column} = :doc_id AND version_number = :v AND tenant_id = :tenant_id
        """),
        {"doc_id": doc_id, "v": version_number, "tenant_id": tenant_id},
    )
    r = result.fetchone()
    if not r:
        return None

    return {
        "id": str(r[0]),
        "version_number": r[1],
        "status": r[2],
        "snapshot": r[3],
        "change_summary": r[4],
        "changed_sections": r[5] or [],
        "created_by": r[6],
        "approved_by": r[7],
        "approved_at": r[8].isoformat() if r[8] else None,
        "created_at": r[9].isoformat() if r[9] else None,
    }


def register_version_routes(
    router: APIRouter,
    doc_type: str,
    id_param: str = "item_id",
    resource_name: str = "Item",
):
    """Register GET /{id}/versions and GET /{id}/versions/{v} on an existing router.

    Uses a standardized path param name `item_id` in the generated routes.
    The actual URL path parameter can be customized via `id_param`.

    Args:
        router: The APIRouter to add version routes to
        doc_type: One of the keys in VERSION_TABLES
        id_param: Path parameter name in the URL (e.g. "obligation_id")
        resource_name: Human-readable name for error messages
    """
    # Capture doc_type and resource_name in closure
    _doc_type = doc_type
    _resource_name = resource_name

    @router.get(f"/{{{id_param}}}/versions")
    async def list_item_versions(
        request: Request,
        db: Session = Depends(get_db),
        tid: str = Depends(get_tenant_id),
    ):
        doc_id = request.path_params[id_param]
        return list_versions(db, _doc_type, doc_id, tid)

    @router.get(f"/{{{id_param}}}/versions/{{version_number}}")
    async def get_item_version(
        version_number: int,
        request: Request,
        db: Session = Depends(get_db),
        tid: str = Depends(get_tenant_id),
    ):
        doc_id = request.path_params[id_param]
        v = get_version(db, _doc_type, doc_id, version_number, tid)
        if not v:
            raise HTTPException(
                status_code=404,
                detail=f"{_resource_name} version {version_number} not found",
            )
        return v
