"""Compliance Commit Ledger API — G2.

Tracks code commits and their compliance impact. SDK reports each commit
with affected controls, building an audit trail for code↔compliance mapping.
"""

import json
import logging
import uuid
from typing import Optional

from fastapi import APIRouter, HTTPException, Query
from pydantic import BaseModel
from sqlalchemy import text

from db.session import SessionLocal

logger = logging.getLogger(__name__)

router = APIRouter(prefix="/v1/compliance-commits", tags=["compliance-commits"])


class CreateCommitRequest(BaseModel):
    tenant_id: str
    project_id: Optional[str] = None
    commit_hash: str
    commit_message: Optional[str] = None
    commit_author: Optional[str] = None
    commit_date: Optional[str] = None
    branch: Optional[str] = None
    repo_url: Optional[str] = None
    affected_control_ids: list[str] = []
    affected_files: list[str] = []
    risk_level: str = "low"
    analysis_summary: Optional[str] = None
    analysis_metadata: dict = {}


@router.post("")
async def register_commit(req: CreateCommitRequest):
    """Register a code commit with its compliance impact."""
    db = SessionLocal()
    try:
        cid = str(uuid.uuid4())
        db.execute(text("""
            INSERT INTO compliance_commits
                (id, tenant_id, project_id, commit_hash, commit_message,
                 commit_author, commit_date, branch, repo_url,
                 affected_control_ids, affected_files,
                 risk_level, analysis_summary, analysis_metadata)
            VALUES
                (CAST(:id AS uuid), CAST(:tenant_id AS uuid), :project_id,
                 :commit_hash, :commit_message, :commit_author,
                 :commit_date, :branch, :repo_url,
                 CAST(:control_ids AS jsonb), CAST(:files AS jsonb),
                 :risk_level, :analysis_summary, CAST(:metadata AS jsonb))
        """), {
            "id": cid,
            "tenant_id": req.tenant_id,
            "project_id": req.project_id,
            "commit_hash": req.commit_hash,
            "commit_message": req.commit_message,
            "commit_author": req.commit_author,
            "commit_date": req.commit_date,
            "branch": req.branch,
            "repo_url": req.repo_url,
            "control_ids": json.dumps(req.affected_control_ids),
            "files": json.dumps(req.affected_files),
            "risk_level": req.risk_level,
            "analysis_summary": req.analysis_summary,
            "metadata": json.dumps(req.analysis_metadata),
        })
        db.commit()
        return {
            "id": cid,
            "status": "registered",
            "affected_controls": len(req.affected_control_ids),
            "risk_level": req.risk_level,
        }
    finally:
        db.close()


@router.get("")
async def list_commits(
    tenant_id: Optional[str] = None,
    control_id: Optional[str] = None,
    risk_level: Optional[str] = None,
    branch: Optional[str] = None,
    since: Optional[str] = None,
    limit: int = Query(50, ge=1, le=500),
    offset: int = Query(0, ge=0),
):
    """List compliance commits with filters."""
    db = SessionLocal()
    try:
        clauses = []
        params: dict = {"limit": limit, "offset": offset}

        if tenant_id:
            clauses.append("tenant_id = CAST(:tenant_id AS uuid)")
            params["tenant_id"] = tenant_id
        if control_id:
            clauses.append("affected_control_ids @> CAST(:cid_json AS jsonb)")
            params["cid_json"] = json.dumps([control_id])
        if risk_level:
            clauses.append("risk_level = :risk")
            params["risk"] = risk_level
        if branch:
            clauses.append("branch = :branch")
            params["branch"] = branch
        if since:
            clauses.append("commit_date >= CAST(:since AS timestamptz)")
            params["since"] = since

        where = "WHERE " + " AND ".join(clauses) if clauses else ""

        rows = db.execute(text(f"""
            SELECT id, commit_hash, commit_message, commit_author, commit_date,
                   branch, affected_control_ids, affected_files, risk_level
            FROM compliance_commits
            {where}
            ORDER BY commit_date DESC NULLS LAST
            LIMIT :limit OFFSET :offset
        """), params).fetchall()

        total = db.execute(text(f"""
            SELECT count(*) FROM compliance_commits {where}
        """), params).scalar()

        return {
            "total": total,
            "commits": [
                {
                    "id": str(r[0]),
                    "commit_hash": r[1],
                    "message": r[2],
                    "author": r[3],
                    "date": str(r[4]) if r[4] else None,
                    "branch": r[5],
                    "affected_control_ids": r[6],
                    "affected_files": r[7],
                    "risk_level": r[8],
                }
                for r in rows
            ],
        }
    finally:
        db.close()


@router.get("/stats")
async def commit_stats(tenant_id: Optional[str] = None):
    """Dashboard stats for compliance commits."""
    db = SessionLocal()
    try:
        tf = ""
        params: dict = {}
        if tenant_id:
            tf = "WHERE tenant_id = CAST(:tid AS uuid)"
            params["tid"] = tenant_id

        risk = db.execute(text(f"""
            SELECT risk_level, count(*) FROM compliance_commits {tf}
            GROUP BY risk_level
        """), params).fetchall()

        recent = db.execute(text(f"""
            SELECT count(*) FROM compliance_commits
            {tf + ' AND' if tf else 'WHERE'} commit_date > NOW() - interval '7 days'
        """), params).scalar()

        total = sum(r[1] for r in risk)

        return {
            "total_commits": total,
            "last_7_days": recent,
            "by_risk_level": {r[0]: r[1] for r in risk},
        }
    finally:
        db.close()


@router.get("/by-control/{control_id}")
async def commits_by_control(
    control_id: str,
    limit: int = Query(50, ge=1, le=200),
):
    """Get all commits that affect a specific control."""
    db = SessionLocal()
    try:
        rows = db.execute(text("""
            SELECT id, commit_hash, commit_message, commit_author, commit_date,
                   branch, repo_url, affected_files, risk_level
            FROM compliance_commits
            WHERE affected_control_ids @> CAST(:cid_json AS jsonb)
            ORDER BY commit_date DESC NULLS LAST
            LIMIT :limit
        """), {
            "cid_json": json.dumps([control_id]),
            "limit": limit,
        }).fetchall()

        return {
            "control_id": control_id,
            "total_commits": len(rows),
            "commits": [
                {
                    "id": str(r[0]),
                    "commit_hash": r[1],
                    "message": r[2],
                    "author": r[3],
                    "date": str(r[4]) if r[4] else None,
                    "branch": r[5],
                    "repo_url": r[6],
                    "affected_files": r[7],
                    "risk_level": r[8],
                }
                for r in rows
            ],
        }
    finally:
        db.close()


@router.get("/{commit_id}")
async def get_commit(commit_id: str):
    """Get details of a single compliance commit."""
    db = SessionLocal()
    try:
        row = db.execute(text("""
            SELECT * FROM compliance_commits WHERE id = CAST(:id AS uuid)
        """), {"id": commit_id}).fetchone()

        if not row:
            raise HTTPException(status_code=404, detail="Commit not found")

        return {
            "id": str(row.id),
            "tenant_id": str(row.tenant_id),
            "project_id": str(row.project_id) if row.project_id else None,
            "commit_hash": row.commit_hash,
            "commit_message": row.commit_message,
            "commit_author": row.commit_author,
            "commit_date": str(row.commit_date) if row.commit_date else None,
            "branch": row.branch,
            "repo_url": row.repo_url,
            "affected_control_ids": row.affected_control_ids,
            "affected_files": row.affected_files,
            "risk_level": row.risk_level,
            "analysis_summary": row.analysis_summary,
            "analysis_metadata": row.analysis_metadata,
        }
    finally:
        db.close()
