"""LLMHosts audit export API -- ``GET /v1/audit/export``.

Provides an HTTP endpoint for exporting audit log data in JSONL or CSV
format.  Gated behind enterprise plan check -- only API keys with the
``enterprise`` plan can access the export endpoint.
"""

from __future__ import annotations

import json
import logging
from datetime import datetime, timezone
from typing import TYPE_CHECKING, Any

from fastapi import APIRouter, Query, Request
from fastapi.responses import JSONResponse, StreamingResponse

if TYPE_CHECKING:
    from collections.abc import AsyncIterator

    from llmhosts.audit.logger import AuditLogger

logger = logging.getLogger(__name__)

router = APIRouter()


def _truncate_api_key(raw_key: str) -> str:
    """Return a truncated API key identifier: first 8 chars + '...'."""
    if len(raw_key) <= 8:
        return raw_key
    return raw_key[:8] + "..."


def _parse_datetime(value: str | None) -> datetime | None:
    """Parse an ISO 8601 datetime string, returning None on failure or if empty."""
    if not value:
        return None
    try:
        dt = datetime.fromisoformat(value)
        # If naive, assume UTC
        if dt.tzinfo is None:
            dt = dt.replace(tzinfo=timezone.utc)
        return dt
    except (ValueError, TypeError):
        return None


@router.get("/v1/audit/export", response_model=None)
async def audit_export(
    request: Request,
    export_format: str = Query(
        default="jsonl", alias="format", pattern="^(jsonl|csv)$", description="Export format: jsonl or csv"
    ),
    since: str | None = Query(default=None, description="Start datetime (ISO 8601)"),
    until: str | None = Query(default=None, description="End datetime (ISO 8601)"),
    model: str | None = Query(default=None, description="Filter by model name"),
    limit: int = Query(default=1000, ge=1, le=100_000, description="Max records to return"),
) -> StreamingResponse | JSONResponse:
    """Export audit log data in JSONL or CSV format.

    Requires an enterprise plan API key.  Returns 403 if the caller's
    plan is not ``enterprise``.
    """
    # Enterprise plan gating
    plan = getattr(request.state, "plan", "free")
    if plan != "enterprise":
        return JSONResponse(
            status_code=403,
            content={
                "error": {
                    "message": "Audit export requires an enterprise plan API key.",
                    "type": "permission_error",
                    "code": "enterprise_required",
                }
            },
        )

    audit_logger: AuditLogger | None = getattr(request.app.state, "audit_logger", None)
    if audit_logger is None:
        return JSONResponse(
            status_code=503,
            content={
                "error": {
                    "message": "Audit logger not available.",
                    "type": "service_error",
                    "code": "audit_unavailable",
                }
            },
        )

    # Build query
    from llmhosts.audit.models import AuditQuery

    query = AuditQuery(
        limit=limit,
        start_date=_parse_datetime(since),
        end_date=_parse_datetime(until),
        model=model,
    )

    entries = await audit_logger.query(query)

    if export_format == "csv":
        return StreamingResponse(
            _stream_csv(entries),
            media_type="text/csv",
            headers={"Content-Disposition": "attachment; filename=audit_export.csv"},
        )

    # Default: JSONL
    return StreamingResponse(
        _stream_jsonl(entries),
        media_type="application/x-ndjson",
        headers={"Content-Disposition": "attachment; filename=audit_export.jsonl"},
    )


async def _stream_jsonl(entries: list[Any]) -> AsyncIterator[str]:
    """Yield one JSON line per audit entry."""
    for entry in entries:
        line = json.dumps(entry.model_dump(mode="json"), default=str)
        yield line + "\n"


async def _stream_csv(entries: list[Any]) -> AsyncIterator[str]:
    """Yield CSV rows: header first, then one row per entry."""
    if not entries:
        return

    # Header from the first entry's fields
    first = entries[0].model_dump(mode="json")
    columns = list(first.keys())
    yield ",".join(columns) + "\n"

    for entry in entries:
        row = entry.model_dump(mode="json")
        values: list[str] = []
        for col in columns:
            val = row.get(col, "")
            val_str = str(val) if val is not None else ""
            # Escape CSV: quote fields containing commas, quotes, or newlines
            if "," in val_str or '"' in val_str or "\n" in val_str:
                val_str = '"' + val_str.replace('"', '""') + '"'
            values.append(val_str)
        yield ",".join(values) + "\n"
