"""Phase 5.11 — Compliance, Audit & Governance API."""
from __future__ import annotations

from datetime import datetime, timezone
from uuid import UUID

from fastapi import APIRouter, Depends, status
from pydantic import BaseModel
from sqlalchemy.ext.asyncio import AsyncSession

from app.api.deps import get_db, get_pagination, require_tenant
from app.core.security import get_current_user
from app.models.compliance import ApprovalRequest, ApprovalWorkflow, CompliancePolicy, ControlDefinition, GovernanceRule, PolicyViolation
from app.models.types import PolicyViolationSeverity, RiskLevel
from app.repositories.base import TenantBaseRepository
from app.services.compliance_service import AuditFramework, ComplianceEngine, GovernanceService
from shared.security import CurrentUser

router = APIRouter()


class AuditRecordCreate(BaseModel):
    action: str
    resource_type: str
    resource_id: str
    source_module: str | None = None
    before_value: str | None = None
    after_value: str | None = None
    reason: str | None = None


class CompliancePolicyCreate(BaseModel):
    code: str
    name: str
    policy_type: str
    rules_config: str
    country_code: str | None = None


class ApprovalRequestCreate(BaseModel):
    workflow_id: UUID
    resource_type: str
    resource_id: str


class RejectRequest(BaseModel):
    reason: str


class RiskCreate(BaseModel):
    code: str
    title: str
    risk_category: str
    risk_level: RiskLevel
    risk_score: int = 0
    description: str | None = None


class CompliancePolicyRepo(TenantBaseRepository[CompliancePolicy]):
    model = CompliancePolicy


@router.get("/audit-records")
async def list_audit_records(
    tenant_id: UUID = Depends(require_tenant),
    pagination=Depends(get_pagination),
    db: AsyncSession = Depends(get_db),
    _user: CurrentUser = Depends(get_current_user),
):
    from app.services.compliance_service import AuditRecordRepo

    repo = AuditRecordRepo(db)
    records = await repo.list_by_tenant(tenant_id, offset=pagination.offset, limit=pagination.page_size)
    return [
        {
            "id": str(r.id),
            "action": r.action,
            "resource_type": r.resource_type,
            "actor_user_id": r.actor_user_id,
            "created_at": r.created_at.isoformat(),
        }
        for r in records
    ]


@router.post("/audit-records", status_code=status.HTTP_201_CREATED)
async def create_audit_record(
    body: AuditRecordCreate,
    tenant_id: UUID = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
    user: CurrentUser = Depends(get_current_user),
):
    audit = AuditFramework(db)
    record = await audit.record(
        tenant_id,
        actor_user_id=user.user_id,
        action=body.action,
        resource_type=body.resource_type,
        resource_id=body.resource_id,
        source_module=body.source_module,
        before_value=body.before_value,
        after_value=body.after_value,
        reason=body.reason,
    )
    await db.commit()
    return {"id": str(record.id)}


@router.get("/policies")
async def list_compliance_policies(
    tenant_id: UUID = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
    _user: CurrentUser = Depends(get_current_user),
):
    rows = await CompliancePolicyRepo(db).list_by_tenant(tenant_id, limit=200)
    return [
        {
            "id": str(p.id),
            "code": p.code,
            "name": p.name,
            "policy_type": p.policy_type,
            "is_active": getattr(p, "is_active", True),
        }
        for p in rows
    ]


@router.post("/policies", status_code=status.HTTP_201_CREATED)
async def create_compliance_policy(
    body: CompliancePolicyCreate,
    tenant_id: UUID = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
    _user: CurrentUser = Depends(get_current_user),
):
    repo = CompliancePolicyRepo(db)
    entity = CompliancePolicy(tenant_id=tenant_id, **body.model_dump())
    await repo.add(entity)
    await db.commit()
    return {"id": str(entity.id)}


@router.post("/approvals")
async def request_approval(
    body: ApprovalRequestCreate,
    tenant_id: UUID = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
    user: CurrentUser = Depends(get_current_user),
):
    gov = GovernanceService(db)
    request = await gov.request_approval(
        tenant_id,
        workflow_id=body.workflow_id,
        resource_type=body.resource_type,
        resource_id=body.resource_id,
        requested_by=user.user_id,
    )
    await db.commit()
    return {"id": str(request.id), "status": request.status.value}


@router.post("/approvals/{request_id}/approve")
async def approve_request(
    request_id: UUID,
    tenant_id: UUID = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
    user: CurrentUser = Depends(get_current_user),
):
    gov = GovernanceService(db)
    request = await gov.approve(tenant_id, request_id, approver_user_id=user.user_id)
    await db.commit()
    return {"id": str(request.id), "status": request.status.value}


@router.post("/approvals/{request_id}/reject")
async def reject_request(
    request_id: UUID,
    body: RejectRequest,
    tenant_id: UUID = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
    user: CurrentUser = Depends(get_current_user),
):
    gov = GovernanceService(db)
    request = await gov.reject(tenant_id, request_id, approver_user_id=user.user_id, reason=body.reason)
    await db.commit()
    return {"id": str(request.id), "status": request.status.value}


@router.get("/risks")
async def list_risks(
    tenant_id: UUID = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
    _user: CurrentUser = Depends(get_current_user),
):
    from app.models.compliance import RiskRecord
    from sqlalchemy import select

    stmt = (
        select(RiskRecord)
        .where(RiskRecord.tenant_id == tenant_id)
        .order_by(RiskRecord.created_at.desc())
        .limit(200)
    )
    rows = list((await db.execute(stmt)).scalars().all())
    return [
        {
            "id": str(r.id),
            "code": r.code,
            "title": r.title,
            "risk_category": r.risk_category,
            "risk_level": r.risk_level.value,
            "risk_score": r.risk_score,
            "is_resolved": r.is_resolved,
        }
        for r in rows
    ]


@router.post("/risks", status_code=status.HTTP_201_CREATED)
async def create_risk(
    body: RiskCreate,
    tenant_id: UUID = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
    _user: CurrentUser = Depends(get_current_user),
):
    gov = GovernanceService(db)
    risk = await gov.create_risk(tenant_id, **body.model_dump())
    await db.commit()
    return {"id": str(risk.id), "risk_level": risk.risk_level.value}


class WorkflowCreate(BaseModel):
    name: str
    resource_type: str
    min_amount: str | None = None
    max_amount: str | None = None


class GovernanceRuleCreate(BaseModel):
    code: str
    name: str
    rule_type: str = "sod"
    condition_config: str
    action_config: str | None = None
    priority: int = 0


class ControlCreate(BaseModel):
    code: str
    name: str
    control_type: str
    description: str | None = None
    validation_config: str | None = None


class ViolationCreate(BaseModel):
    policy_id: UUID
    resource_type: str
    resource_id: str
    severity: PolicyViolationSeverity
    description: str


class WorkflowRepo(TenantBaseRepository[ApprovalWorkflow]):
    model = ApprovalWorkflow


class ApprovalRequestRepo(TenantBaseRepository[ApprovalRequest]):
    model = ApprovalRequest


class GovernanceRuleRepo(TenantBaseRepository[GovernanceRule]):
    model = GovernanceRule


class ControlRepo(TenantBaseRepository[ControlDefinition]):
    model = ControlDefinition


class ViolationRepo(TenantBaseRepository[PolicyViolation]):
    model = PolicyViolation


@router.get("/workflows")
async def list_workflows(
    tenant_id: UUID = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
    _user: CurrentUser = Depends(get_current_user),
):
    rows = await WorkflowRepo(db).list_by_tenant(tenant_id, limit=100)
    return [
        {
            "id": str(r.id),
            "name": r.name,
            "resource_type": r.resource_type,
            "min_amount": r.min_amount,
            "max_amount": r.max_amount,
            "is_active": r.is_active,
        }
        for r in rows
    ]


@router.post("/workflows", status_code=status.HTTP_201_CREATED)
async def create_workflow(
    body: WorkflowCreate,
    tenant_id: UUID = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
    _user: CurrentUser = Depends(get_current_user),
):
    entity = ApprovalWorkflow(tenant_id=tenant_id, **body.model_dump())
    await WorkflowRepo(db).add(entity)
    await db.commit()
    return {"id": str(entity.id)}


@router.get("/approvals")
async def list_approvals(
    tenant_id: UUID = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
    _user: CurrentUser = Depends(get_current_user),
):
    rows = await ApprovalRequestRepo(db).list_by_tenant(tenant_id, limit=200)
    return [
        {
            "id": str(r.id),
            "workflow_id": str(r.workflow_id),
            "resource_type": r.resource_type,
            "resource_id": r.resource_id,
            "requested_by": r.requested_by,
            "status": r.status.value,
            "current_step": r.current_step,
            "rejection_reason": r.rejection_reason,
        }
        for r in rows
    ]


@router.get("/governance-rules")
async def list_governance_rules(
    tenant_id: UUID = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
    _user: CurrentUser = Depends(get_current_user),
):
    rows = await GovernanceRuleRepo(db).list_by_tenant(tenant_id, limit=200)
    return [
        {
            "id": str(r.id),
            "code": r.code,
            "name": r.name,
            "rule_type": r.rule_type,
            "condition_config": r.condition_config,
            "priority": r.priority,
            "is_active": r.is_active,
        }
        for r in rows
    ]


@router.post("/governance-rules", status_code=status.HTTP_201_CREATED)
async def create_governance_rule(
    body: GovernanceRuleCreate,
    tenant_id: UUID = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
    _user: CurrentUser = Depends(get_current_user),
):
    entity = GovernanceRule(tenant_id=tenant_id, **body.model_dump())
    await GovernanceRuleRepo(db).add(entity)
    await db.commit()
    return {"id": str(entity.id)}


@router.get("/controls")
async def list_controls(
    tenant_id: UUID = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
    _user: CurrentUser = Depends(get_current_user),
):
    rows = await ControlRepo(db).list_by_tenant(tenant_id, limit=200)
    return [
        {
            "id": str(r.id),
            "code": r.code,
            "name": r.name,
            "control_type": r.control_type,
            "description": r.description,
            "is_active": r.is_active,
        }
        for r in rows
    ]


@router.post("/controls", status_code=status.HTTP_201_CREATED)
async def create_control(
    body: ControlCreate,
    tenant_id: UUID = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
    _user: CurrentUser = Depends(get_current_user),
):
    entity = ControlDefinition(tenant_id=tenant_id, **body.model_dump())
    await ControlRepo(db).add(entity)
    await db.commit()
    return {"id": str(entity.id)}


@router.get("/violations")
async def list_violations(
    tenant_id: UUID = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
    _user: CurrentUser = Depends(get_current_user),
):
    rows = await ViolationRepo(db).list_by_tenant(tenant_id, limit=200)
    return [
        {
            "id": str(r.id),
            "policy_id": str(r.policy_id),
            "resource_type": r.resource_type,
            "resource_id": r.resource_id,
            "severity": r.severity.value,
            "description": r.description,
            "detected_at": r.detected_at.isoformat(),
            "is_resolved": r.is_resolved,
        }
        for r in rows
    ]


@router.post("/violations", status_code=status.HTTP_201_CREATED)
async def create_violation(
    body: ViolationCreate,
    tenant_id: UUID = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
    _user: CurrentUser = Depends(get_current_user),
):
    entity = PolicyViolation(
        tenant_id=tenant_id,
        policy_id=body.policy_id,
        resource_type=body.resource_type,
        resource_id=body.resource_id,
        severity=body.severity,
        description=body.description,
        detected_at=datetime.now(timezone.utc),
    )
    await ViolationRepo(db).add(entity)
    await db.commit()
    return {"id": str(entity.id)}
