from datetime import datetime, timedelta

from fastapi import APIRouter, Depends, HTTPException, Query, status
from pydantic import BaseModel
from common_logging import get_logger
from sqlalchemy import desc
from sqlalchemy.orm import Session

from app.api.permissions import require_read
from app.db.session import get_db_without_tenant
from app.models.audit_log import AuditLog
from app.models.user import User

logger = get_logger(__name__)
router = APIRouter(tags=["audit-logs"])


class AuditLogResponse(BaseModel):
    id: int
    tenant_id: int | None
    user_id: int | None
    action: str
    resource_type: str
    resource_id: int | None
    method: str | None
    path: str | None
    ip_address: str | None
    response_status: int | None
    error_message: str | None
    duration_ms: int | None
    created_at: datetime

    class Config:
        from_attributes = True


class AuditLogStats(BaseModel):
    total_requests: int
    failed_requests: int
    avg_duration_ms: float
    actions_by_type: dict
    resources_by_type: dict


@router.get("", response_model=list[AuditLogResponse])
def list_audit_logs(
    skip: int = Query(0, ge=0),
    limit: int = Query(100, ge=1, le=1000),
    tenant_id: int | None = None,
    user_id: int | None = None,
    action: str | None = None,
    resource_type: str | None = None,
    start_date: datetime | None = None,
    end_date: datetime | None = None,
    db: Session = Depends(get_db_without_tenant),
    current_user: User = Depends(require_read("audit_logs")),
):
    query = db.query(AuditLog)
    if current_user.role == "platform_admin":
        if tenant_id is not None:
            query = query.filter(AuditLog.tenant_id == tenant_id)
    elif current_user.role == "customer_admin":
        query = query.filter(AuditLog.tenant_id == current_user.tenant_id)
    else:
        logger.bind(user_id=current_user.id).warning("Insufficient permissions for audit logs")
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Insufficient permissions to access audit logs",
        )
    if user_id is not None:
        query = query.filter(AuditLog.user_id == user_id)
    if action:
        query = query.filter(AuditLog.action == action)
    if resource_type:
        query = query.filter(AuditLog.resource_type == resource_type)
    if start_date:
        query = query.filter(AuditLog.created_at >= start_date)
    if end_date:
        query = query.filter(AuditLog.created_at <= end_date)
    query = query.order_by(desc(AuditLog.created_at))
    logs = query.offset(skip).limit(limit).all()
    return logs


@router.get("/stats", response_model=AuditLogStats)
def get_audit_stats(
    tenant_id: int | None = None,
    days: int = Query(7, ge=1, le=90),
    db: Session = Depends(get_db_without_tenant),
    current_user: User = Depends(require_read("audit_logs")),
):
    from sqlalchemy import case, func

    start_date = datetime.utcnow() - timedelta(days=days)
    query = db.query(AuditLog).filter(AuditLog.created_at >= start_date)
    if current_user.role == "platform_admin":
        if tenant_id is not None:
            query = query.filter(AuditLog.tenant_id == tenant_id)
    elif current_user.role == "customer_admin":
        query = query.filter(AuditLog.tenant_id == current_user.tenant_id)
    else:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Insufficient permissions to access audit stats",
        )
    stats = db.query(
        func.count(AuditLog.id).label("total"),
        func.count(case((AuditLog.response_status >= 400, 1))).label("failed"),
        func.avg(AuditLog.duration_ms).label("avg_time"),
    ).filter(AuditLog.created_at >= start_date)
    if current_user.role == "platform_admin":
        if tenant_id is not None:
            stats = stats.filter(AuditLog.tenant_id == tenant_id)
    elif current_user.role == "customer_admin":
        stats = stats.filter(AuditLog.tenant_id == current_user.tenant_id)
    stats_result = stats.first()
    total_requests = stats_result.total or 0
    failed_requests = stats_result.failed or 0
    avg_duration_ms = float(stats_result.avg_time) if stats_result.avg_time else 0.0
    actions_query = db.query(AuditLog.action, func.count(AuditLog.id).label("count")).filter(
        AuditLog.created_at >= start_date
    )
    if current_user.role == "platform_admin":
        if tenant_id is not None:
            actions_query = actions_query.filter(AuditLog.tenant_id == tenant_id)
    elif current_user.role == "customer_admin":
        actions_query = actions_query.filter(AuditLog.tenant_id == current_user.tenant_id)
    actions_by_type = dict(actions_query.group_by(AuditLog.action).all())
    resources_query = db.query(
        AuditLog.resource_type, func.count(AuditLog.id).label("count")
    ).filter(AuditLog.created_at >= start_date)
    if current_user.role == "platform_admin":
        if tenant_id is not None:
            resources_query = resources_query.filter(AuditLog.tenant_id == tenant_id)
    elif current_user.role == "customer_admin":
        resources_query = resources_query.filter(AuditLog.tenant_id == current_user.tenant_id)
    resources_by_type = dict(resources_query.group_by(AuditLog.resource_type).all())
    return AuditLogStats(
        total_requests=total_requests,
        failed_requests=failed_requests,
        avg_duration_ms=avg_duration_ms,
        actions_by_type=actions_by_type,
        resources_by_type=resources_by_type,
    )


@router.get("/{log_id}", response_model=AuditLogResponse)
def get_audit_log(
    log_id: int,
    db: Session = Depends(get_db_without_tenant),
    current_user: User = Depends(require_read("audit_logs")),
):
    log = db.query(AuditLog).filter(AuditLog.id == log_id).first()
    if not log:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Audit log not found")
    if current_user.role == "platform_admin":
        pass
    elif current_user.role == "customer_admin":
        if log.tenant_id != current_user.tenant_id:
            raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Access denied")
    else:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN, detail="Insufficient permissions"
        )
    return log
