"""
FastAPI routes for Legal Templates (Document Generator).

Self-authored templates (MIT License) stored in compliance_legal_templates.

Endpoints:
  GET    /legal-templates           — list (query, document_type, language, status, limit, offset)
  GET    /legal-templates/status    — counts by type
  GET    /legal-templates/sources   — distinct source_name list
  GET    /legal-templates/{id}      — single template by id
  POST   /legal-templates           — create (admin)
  PUT    /legal-templates/{id}      — update
  DELETE /legal-templates/{id}      — delete (204)
"""

import json
import logging
from datetime import datetime, timezone
from typing import Optional, List, Any, Dict

from fastapi import APIRouter, Depends, HTTPException, Query
from pydantic import BaseModel
from sqlalchemy import text
from sqlalchemy.orm import Session

from classroom_engine.database import get_db
from .tenant_utils import get_tenant_id as _get_tenant_id
from .db_utils import row_to_dict as _row_to_dict

logger = logging.getLogger(__name__)
router = APIRouter(prefix="/legal-templates", tags=["legal-templates"])

VALID_DOCUMENT_TYPES = {
    # Original types
    "privacy_policy",
    "terms_of_service",
    "impressum",
    "cookie_policy",
    # Renamed from data_processing_agreement / withdrawal_policy (Migration 020)
    "dpa",
    "widerruf",
    # New types (Migration 020)
    "nda",
    "sla",
    "acceptable_use",
    "community_guidelines",
    "copyright_policy",
    "cloud_service_agreement",
    "data_usage_clause",
    "cookie_banner",
    "agb",
    "clause",
    # Security document templates (Migration 051)
    "it_security_concept",
    "data_protection_concept",
    "backup_recovery_concept",
    "logging_concept",
    "incident_response_plan",
    "access_control_concept",
    "risk_management_concept",
    # Policy templates — IT Security (Migration 054)
    "information_security_policy",
    "access_control_policy",
    "password_policy",
    "encryption_policy",
    "logging_policy",
    "backup_policy",
    "incident_response_policy",
    "change_management_policy",
    "patch_management_policy",
    "asset_management_policy",
    "cloud_security_policy",
    "devsecops_policy",
    "secrets_management_policy",
    "vulnerability_management_policy",
    # Policy templates — Data (Migration 054)
    "data_protection_policy",
    "data_classification_policy",
    "data_retention_policy",
    "data_transfer_policy",
    "privacy_incident_policy",
    # Policy templates — Personnel (Migration 054)
    "employee_security_policy",
    "security_awareness_policy",
    "remote_work_policy",
    "offboarding_policy",
    # Policy templates — Vendor/Supply Chain (Migration 054)
    "vendor_risk_management_policy",
    "third_party_security_policy",
    "supplier_security_policy",
    # Policy templates — BCM (Migration 054)
    "business_continuity_policy",
    "disaster_recovery_policy",
    "crisis_management_policy",
    # CRA Cybersecurity (Migration 056)
    "cybersecurity_policy",
    # DSFA template
    "dsfa",
    # Module document templates (Migration 073)
    "vvt_register",
    "tom_documentation",
    "loeschkonzept",
    "pflichtenregister",
    # DSR Process Documents (Migration 085)
    "dsr_process_art15",
    "dsr_process_art16",
    "dsr_process_art17",
    "dsr_process_art18",
    "dsr_process_art19",
    "dsr_process_art20",
    "dsr_process_art21",
}
VALID_STATUSES = {"published", "draft", "archived"}


# =============================================================================
# Pydantic Schemas
# =============================================================================

class LegalTemplateCreate(BaseModel):
    document_type: str
    title: str
    description: Optional[str] = None
    content: str
    placeholders: Optional[List[str]] = None
    language: str = "de"
    jurisdiction: str = "DE"
    license_id: str = "mit"
    license_name: str = "MIT License"
    source_name: str = "BreakPilot Compliance"
    attribution_required: bool = False
    is_complete_document: bool = True
    version: str = "1.0.0"
    status: str = "published"
    # Attribution / source traceability
    source_url: Optional[str] = None
    source_repo: Optional[str] = None
    source_file_path: Optional[str] = None
    attribution_text: Optional[str] = None
    inspiration_sources: Optional[List[Any]] = None


class LegalTemplateUpdate(BaseModel):
    document_type: Optional[str] = None
    title: Optional[str] = None
    description: Optional[str] = None
    content: Optional[str] = None
    placeholders: Optional[List[str]] = None
    language: Optional[str] = None
    jurisdiction: Optional[str] = None
    license_id: Optional[str] = None
    license_name: Optional[str] = None
    source_name: Optional[str] = None
    attribution_required: Optional[bool] = None
    is_complete_document: Optional[bool] = None
    version: Optional[str] = None
    status: Optional[str] = None
    # Attribution / source traceability
    source_url: Optional[str] = None
    source_repo: Optional[str] = None
    source_file_path: Optional[str] = None
    attribution_text: Optional[str] = None
    inspiration_sources: Optional[List[Any]] = None


# =============================================================================
# Routes
# =============================================================================

@router.get("")
async def list_legal_templates(
    query: Optional[str] = Query(None, description="Full-text ILIKE search on title/description/content"),
    document_type: Optional[str] = Query(None),
    language: Optional[str] = Query(None),
    status: Optional[str] = Query("published"),
    limit: int = Query(50, ge=1, le=200),
    offset: int = Query(0, ge=0),
    db: Session = Depends(get_db),
    tenant_id: str = Depends(_get_tenant_id),
):
    """List legal templates with optional filters."""

    where_clauses = ["tenant_id = :tenant_id"]
    params: Dict[str, Any] = {"tenant_id": tenant_id, "limit": limit, "offset": offset}

    if status:
        where_clauses.append("status = :status")
        params["status"] = status
    if document_type:
        where_clauses.append("document_type = :document_type")
        params["document_type"] = document_type
    if language:
        where_clauses.append("language = :language")
        params["language"] = language
    if query:
        where_clauses.append(
            "(title ILIKE :query OR description ILIKE :query OR content ILIKE :query)"
        )
        params["query"] = f"%{query}%"

    where_sql = " AND ".join(where_clauses)

    total_row = db.execute(
        text(f"SELECT COUNT(*) FROM compliance_legal_templates WHERE {where_sql}"),
        params,
    ).fetchone()
    total = total_row[0] if total_row else 0

    rows = db.execute(
        text(f"""
            SELECT * FROM compliance_legal_templates
            WHERE {where_sql}
            ORDER BY document_type, title
            LIMIT :limit OFFSET :offset
        """),
        params,
    ).fetchall()

    return {
        "templates": [_row_to_dict(r) for r in rows],
        "total": total,
    }


@router.get("/status")
async def get_templates_status(
    db: Session = Depends(get_db),
    tenant_id: str = Depends(_get_tenant_id),
):
    """Return template counts by document_type."""

    total_row = db.execute(
        text("SELECT COUNT(*) FROM compliance_legal_templates WHERE tenant_id = :tenant_id"),
        {"tenant_id": tenant_id},
    ).fetchone()
    total = int(total_row[0] or 0) if total_row else 0

    status_rows = db.execute(text("""
        SELECT status, COUNT(*) AS cnt
        FROM compliance_legal_templates
        WHERE tenant_id = :tenant_id
        GROUP BY status
    """), {"tenant_id": tenant_id}).fetchall()
    by_status: Dict[str, int] = {r[0]: int(r[1] or 0) for r in status_rows}

    type_rows = db.execute(text("""
        SELECT document_type, COUNT(*) AS cnt
        FROM compliance_legal_templates
        WHERE tenant_id = :tenant_id
        GROUP BY document_type
        ORDER BY document_type
    """), {"tenant_id": tenant_id}).fetchall()
    by_type: Dict[str, int] = {r[0]: int(r[1] or 0) for r in type_rows}

    return {
        "total": total,
        "by_status": {
            "published": by_status.get("published", 0),
            "draft": by_status.get("draft", 0),
            "archived": by_status.get("archived", 0),
        },
        "by_type": by_type,
    }


@router.get("/sources")
async def get_template_sources(
    db: Session = Depends(get_db),
    tenant_id: str = Depends(_get_tenant_id),
):
    """Return distinct source_name values."""

    rows = db.execute(
        text("SELECT DISTINCT source_name FROM compliance_legal_templates WHERE tenant_id = :tenant_id ORDER BY source_name"),
        {"tenant_id": tenant_id},
    ).fetchall()

    return {"sources": [r[0] for r in rows]}


@router.get("/{template_id}")
async def get_legal_template(
    template_id: str,
    db: Session = Depends(get_db),
    tenant_id: str = Depends(_get_tenant_id),
):
    """Fetch a single template by ID."""
    row = db.execute(
        text("SELECT * FROM compliance_legal_templates WHERE id = :id AND tenant_id = :tenant_id"),
        {"id": template_id, "tenant_id": tenant_id},
    ).fetchone()
    if not row:
        raise HTTPException(status_code=404, detail="Template not found")
    return _row_to_dict(row)


@router.post("", status_code=201)
async def create_legal_template(
    payload: LegalTemplateCreate,
    db: Session = Depends(get_db),
    tenant_id: str = Depends(_get_tenant_id),
):
    """Create a new legal template."""

    if payload.document_type not in VALID_DOCUMENT_TYPES:
        raise HTTPException(
            status_code=400,
            detail=f"Invalid document_type. Must be one of: {', '.join(VALID_DOCUMENT_TYPES)}"
        )
    if payload.status not in VALID_STATUSES:
        raise HTTPException(
            status_code=400,
            detail=f"Invalid status. Must be one of: {', '.join(VALID_STATUSES)}"
        )

    placeholders_json = json.dumps(payload.placeholders or [])
    inspiration_json = json.dumps(payload.inspiration_sources or [])

    row = db.execute(text("""
        INSERT INTO compliance_legal_templates (
            tenant_id, document_type, title, description, content,
            placeholders, language, jurisdiction,
            license_id, license_name, source_name,
            attribution_required, is_complete_document, version, status,
            source_url, source_repo, source_file_path, source_retrieved_at,
            attribution_text, inspiration_sources
        ) VALUES (
            :tenant_id, :document_type, :title, :description, :content,
            CAST(:placeholders AS jsonb), :language, :jurisdiction,
            :license_id, :license_name, :source_name,
            :attribution_required, :is_complete_document, :version, :status,
            :source_url, :source_repo, :source_file_path, :source_retrieved_at,
            :attribution_text, CAST(:inspiration_sources AS jsonb)
        ) RETURNING *
    """), {
        "tenant_id": tenant_id,
        "document_type": payload.document_type,
        "title": payload.title,
        "description": payload.description,
        "content": payload.content,
        "placeholders": placeholders_json,
        "language": payload.language,
        "jurisdiction": payload.jurisdiction,
        "license_id": payload.license_id,
        "license_name": payload.license_name,
        "source_name": payload.source_name,
        "attribution_required": payload.attribution_required,
        "is_complete_document": payload.is_complete_document,
        "version": payload.version,
        "status": payload.status,
        "source_url": payload.source_url,
        "source_repo": payload.source_repo,
        "source_file_path": payload.source_file_path,
        "source_retrieved_at": None,
        "attribution_text": payload.attribution_text,
        "inspiration_sources": inspiration_json,
    }).fetchone()
    db.commit()
    return _row_to_dict(row)


@router.put("/{template_id}")
async def update_legal_template(
    template_id: str,
    payload: LegalTemplateUpdate,
    db: Session = Depends(get_db),
    tenant_id: str = Depends(_get_tenant_id),
):
    """Update an existing legal template."""

    updates = payload.model_dump(exclude_unset=True)
    if not updates:
        raise HTTPException(status_code=400, detail="No fields to update")

    if "document_type" in updates and updates["document_type"] not in VALID_DOCUMENT_TYPES:
        raise HTTPException(status_code=400, detail="Invalid document_type")
    if "status" in updates and updates["status"] not in VALID_STATUSES:
        raise HTTPException(status_code=400, detail="Invalid status")

    set_clauses = ["updated_at = :updated_at"]
    params: Dict[str, Any] = {
        "id": template_id,
        "tenant_id": tenant_id,
        "updated_at": datetime.now(timezone.utc),
    }

    jsonb_fields = {"placeholders", "inspiration_sources"}
    for field, value in updates.items():
        if field in jsonb_fields:
            params[field] = json.dumps(value if value is not None else [])
            set_clauses.append(f"{field} = CAST(:{field} AS jsonb)")
        else:
            params[field] = value
            set_clauses.append(f"{field} = :{field}")

    row = db.execute(
        text(f"""
            UPDATE compliance_legal_templates
            SET {', '.join(set_clauses)}
            WHERE id = :id AND tenant_id = :tenant_id
            RETURNING *
        """),
        params,
    ).fetchone()
    db.commit()

    if not row:
        raise HTTPException(status_code=404, detail="Template not found")
    return _row_to_dict(row)


@router.delete("/{template_id}", status_code=204)
async def delete_legal_template(
    template_id: str,
    db: Session = Depends(get_db),
    tenant_id: str = Depends(_get_tenant_id),
):
    """Delete a legal template."""
    result = db.execute(
        text("DELETE FROM compliance_legal_templates WHERE id = :id AND tenant_id = :tenant_id"),
        {"id": template_id, "tenant_id": tenant_id},
    )
    db.commit()
    if result.rowcount == 0:
        raise HTTPException(status_code=404, detail="Template not found")
