"""
FastAPI routes for Security Backlog Tracking.

Endpoints:
  GET    /security-backlog        — list with filters (status, severity, type, search; limit/offset)
  GET    /security-backlog/stats  — open, critical, high, overdue counts
  POST   /security-backlog        — create finding
  PUT    /security-backlog/{id}   — update finding
  DELETE /security-backlog/{id}   — delete finding (204)
"""

import logging
from datetime import datetime, timezone
from typing import Optional, 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="/security-backlog", tags=["security-backlog"])


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

class SecurityItemCreate(BaseModel):
    title: str
    description: Optional[str] = None
    type: str = "vulnerability"
    severity: str = "medium"
    status: str = "open"
    source: Optional[str] = None
    cve: Optional[str] = None
    cvss: Optional[float] = None
    affected_asset: Optional[str] = None
    assigned_to: Optional[str] = None
    due_date: Optional[datetime] = None
    remediation: Optional[str] = None


class SecurityItemUpdate(BaseModel):
    title: Optional[str] = None
    description: Optional[str] = None
    type: Optional[str] = None
    severity: Optional[str] = None
    status: Optional[str] = None
    source: Optional[str] = None
    cve: Optional[str] = None
    cvss: Optional[float] = None
    affected_asset: Optional[str] = None
    assigned_to: Optional[str] = None
    due_date: Optional[datetime] = None
    remediation: Optional[str] = None



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

@router.get("")
async def list_security_items(
    status: Optional[str] = Query(None),
    severity: Optional[str] = Query(None),
    type: Optional[str] = Query(None),
    search: Optional[str] = Query(None),
    limit: int = Query(100, ge=1, le=500),
    offset: int = Query(0, ge=0),
    db: Session = Depends(get_db),
    tenant_id: str = Depends(_get_tenant_id),
):
    """List security backlog items 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 severity:
        where_clauses.append("severity = :severity")
        params["severity"] = severity
    if type:
        where_clauses.append("type = :type")
        params["type"] = type
    if search:
        where_clauses.append("(title ILIKE :search OR description ILIKE :search)")
        params["search"] = f"%{search}%"

    where_sql = " AND ".join(where_clauses)

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

    rows = db.execute(
        text(f"""
            SELECT * FROM compliance_security_backlog
            WHERE {where_sql}
            ORDER BY
                CASE severity
                    WHEN 'critical' THEN 0
                    WHEN 'high' THEN 1
                    WHEN 'medium' THEN 2
                    ELSE 3
                END,
                CASE status
                    WHEN 'open' THEN 0
                    WHEN 'in-progress' THEN 1
                    WHEN 'accepted-risk' THEN 2
                    ELSE 3
                END,
                created_at DESC
            LIMIT :limit OFFSET :offset
        """),
        params,
    ).fetchall()

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


@router.get("/stats")
async def get_security_stats(
    db: Session = Depends(get_db),
    tenant_id: str = Depends(_get_tenant_id),
):
    """Return security backlog counts."""

    rows = db.execute(text("""
        SELECT
            COUNT(*) FILTER (WHERE status = 'open')                               AS open,
            COUNT(*) FILTER (WHERE status = 'in-progress')                        AS in_progress,
            COUNT(*) FILTER (WHERE status = 'resolved')                           AS resolved,
            COUNT(*) FILTER (WHERE status = 'accepted-risk')                      AS accepted_risk,
            COUNT(*) FILTER (WHERE severity = 'critical' AND status != 'resolved') AS critical,
            COUNT(*) FILTER (WHERE severity = 'high' AND status != 'resolved')    AS high,
            COUNT(*) FILTER (
                WHERE due_date IS NOT NULL
                  AND due_date < NOW()
                  AND status NOT IN ('resolved', 'accepted-risk')
            )                                                                      AS overdue,
            COUNT(*)                                                               AS total
        FROM compliance_security_backlog
        WHERE tenant_id = :tenant_id
    """), {"tenant_id": tenant_id}).fetchone()

    if rows:
        d = dict(rows._mapping)
        return {k: (v or 0) for k, v in d.items()}
    return {"open": 0, "in_progress": 0, "resolved": 0, "accepted_risk": 0,
            "critical": 0, "high": 0, "overdue": 0, "total": 0}


@router.post("", status_code=201)
async def create_security_item(
    payload: SecurityItemCreate,
    db: Session = Depends(get_db),
    tenant_id: str = Depends(_get_tenant_id),
):
    """Create a new security backlog item."""

    row = db.execute(text("""
        INSERT INTO compliance_security_backlog
            (tenant_id, title, description, type, severity, status,
             source, cve, cvss, affected_asset, assigned_to, due_date, remediation)
        VALUES
            (:tenant_id, :title, :description, :type, :severity, :status,
             :source, :cve, :cvss, :affected_asset, :assigned_to, :due_date, :remediation)
        RETURNING *
    """), {
        "tenant_id": tenant_id,
        "title": payload.title,
        "description": payload.description,
        "type": payload.type,
        "severity": payload.severity,
        "status": payload.status,
        "source": payload.source,
        "cve": payload.cve,
        "cvss": payload.cvss,
        "affected_asset": payload.affected_asset,
        "assigned_to": payload.assigned_to,
        "due_date": payload.due_date,
        "remediation": payload.remediation,
    }).fetchone()
    db.commit()
    return _row_to_dict(row)


@router.put("/{item_id}")
async def update_security_item(
    item_id: str,
    payload: SecurityItemUpdate,
    db: Session = Depends(get_db),
    tenant_id: str = Depends(_get_tenant_id),
):
    """Update a security backlog item."""

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

    for field, value in payload.model_dump(exclude_unset=True).items():
        updates[field] = value
        set_clauses.append(f"{field} = :{field}")

    if len(set_clauses) == 1:
        raise HTTPException(status_code=400, detail="No fields to update")

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

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


@router.delete("/{item_id}", status_code=204)
async def delete_security_item(
    item_id: str,
    db: Session = Depends(get_db),
    tenant_id: str = Depends(_get_tenant_id),
):
    result = db.execute(text("""
        DELETE FROM compliance_security_backlog
        WHERE id = :id AND tenant_id = :tenant_id
    """), {"id": item_id, "tenant_id": tenant_id})
    db.commit()
    if result.rowcount == 0:
        raise HTTPException(status_code=404, detail="Security item not found")
