"""Admin-only audit-log read endpoints for the CMS.

Mounted at ``/api/v1/admin/audit-logs``. Only admins can read this.
"""

from __future__ import annotations

import logging
from datetime import datetime, timezone
from typing import Optional

from core.database import get_db
from dependencies.auth import get_admin_user
from fastapi import APIRouter, Depends, HTTPException, Query, status
from models.audit_log import AdminAuditLog
from schemas.audit_log import AuditLogItem, AuditLogListResponse
from schemas.auth import UserResponse
from services.audit_log import KNOWN_ACTIONS
from sqlalchemy import func, or_, select
from sqlalchemy.ext.asyncio import AsyncSession

logger = logging.getLogger(__name__)

router = APIRouter(prefix="/api/v1/admin/audit-logs", tags=["admin-audit-logs"])


def _parse_iso_datetime(value: str, field: str) -> datetime:
    """Parse an ISO-8601 datetime, tolerating 'Z' suffix and date-only input."""
    raw = value.strip()
    if not raw:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST, detail=f"{field} is empty"
        )
    if raw.endswith("Z"):
        raw = raw[:-1] + "+00:00"
    try:
        parsed = datetime.fromisoformat(raw)
    except ValueError:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=f"{field} must be an ISO-8601 datetime",
        )
    if parsed.tzinfo is None:
        parsed = parsed.replace(tzinfo=timezone.utc)
    return parsed


@router.get("", response_model=AuditLogListResponse)
async def list_audit_logs(
    action: Optional[str] = Query(default=None, description="Filter by exact action"),
    start: Optional[str] = Query(
        default=None, description="Inclusive lower-bound ISO-8601 timestamp"
    ),
    end: Optional[str] = Query(
        default=None, description="Exclusive upper-bound ISO-8601 timestamp"
    ),
    search: Optional[str] = Query(
        default=None, description="Case-insensitive match on admin/target email"
    ),
    page: int = Query(default=1, ge=1),
    page_size: int = Query(default=50, ge=1, le=200),
    db: AsyncSession = Depends(get_db),
    _admin: UserResponse = Depends(get_admin_user),
) -> AuditLogListResponse:
    """Return a filtered, paginated slice of the audit log (newest first)."""
    stmt = select(AdminAuditLog)
    count_stmt = select(func.count()).select_from(AdminAuditLog)

    filters = []
    if action:
        filters.append(AdminAuditLog.action == action)
    if start:
        start_dt = _parse_iso_datetime(start, "start")
        filters.append(AdminAuditLog.created_at >= start_dt)
    if end:
        end_dt = _parse_iso_datetime(end, "end")
        filters.append(AdminAuditLog.created_at < end_dt)
    if search:
        pattern = f"%{search.strip().lower()}%"
        filters.append(
            or_(
                func.lower(AdminAuditLog.admin_email).like(pattern),
                func.lower(AdminAuditLog.target_email).like(pattern),
            )
        )

    for f in filters:
        stmt = stmt.where(f)
        count_stmt = count_stmt.where(f)

    total_result = await db.execute(count_stmt)
    total = int(total_result.scalar() or 0)

    stmt = (
        stmt.order_by(AdminAuditLog.created_at.desc(), AdminAuditLog.id.desc())
        .offset((page - 1) * page_size)
        .limit(page_size)
    )
    result = await db.execute(stmt)
    rows = result.scalars().all()

    return AuditLogListResponse(
        items=[AuditLogItem.model_validate(r) for r in rows],
        total=total,
        page=page,
        page_size=page_size,
        known_actions=list(KNOWN_ACTIONS),
    )