"""Initial audit_log schema.

Revision ID: 001_initial_audit
Revises: None
Create Date: 2026-02-15

Creates the ``audit_log`` table and its indexes.  The migration is
idempotent: it checks ``inspector.has_table()`` before creating so it
won't fail against databases that already have the table from the legacy
``CREATE TABLE IF NOT EXISTS`` path in ``AuditLogger.initialize()``.
"""

from __future__ import annotations

from typing import TYPE_CHECKING

import sqlalchemy as sa
from alembic import op

if TYPE_CHECKING:
    from collections.abc import Sequence

# revision identifiers, used by Alembic.
revision: str = "001_initial_audit"
down_revision: str | None = None
branch_labels: str | Sequence[str] | None = None
depends_on: str | Sequence[str] | None = None


def upgrade() -> None:
    # Use the inspector to make this idempotent -- existing databases
    # already have the table created by AuditLogger.initialize().
    conn = op.get_bind()
    inspector = sa.inspect(conn)

    if not inspector.has_table("audit_log"):
        op.create_table(
            "audit_log",
            sa.Column("request_id", sa.Text(), primary_key=True),
            sa.Column("timestamp", sa.Text(), nullable=False),
            sa.Column("source_ip", sa.Text(), nullable=False),
            sa.Column("method", sa.Text(), nullable=False),
            sa.Column("path", sa.Text(), nullable=False),
            sa.Column("dialect", sa.Text(), nullable=False),
            sa.Column("model_requested", sa.Text(), nullable=False),
            sa.Column("model_used", sa.Text(), nullable=False),
            sa.Column("backend_type", sa.Text(), nullable=False),
            sa.Column("routing_tier", sa.Text(), nullable=False),
            sa.Column("routing_reasoning", sa.Text(), nullable=False, server_default=""),
            sa.Column("routing_confidence", sa.Float(), nullable=False, server_default="0.0"),
            sa.Column("input_tokens", sa.Integer(), nullable=False, server_default="0"),
            sa.Column("output_tokens", sa.Integer(), nullable=False, server_default="0"),
            sa.Column("actual_cost", sa.Float(), nullable=False, server_default="0.0"),
            sa.Column("cloud_equivalent_cost", sa.Float(), nullable=False, server_default="0.0"),
            sa.Column("cached", sa.Integer(), nullable=False, server_default="0"),
            sa.Column("cache_tier", sa.Text(), nullable=True),
            sa.Column("latency_ms", sa.Float(), nullable=False, server_default="0.0"),
            sa.Column("status_code", sa.Integer(), nullable=False, server_default="200"),
            sa.Column("error", sa.Text(), nullable=True),
        )

    # Indexes -- CREATE INDEX IF NOT EXISTS is supported by SQLite so
    # these are safe to run even when the table already exists.
    _indexes = [
        ("idx_audit_timestamp", "audit_log", ["timestamp"]),
        ("idx_audit_model", "audit_log", ["model_used"]),
        ("idx_audit_backend", "audit_log", ["backend_type"]),
        ("idx_audit_cached", "audit_log", ["cached"]),
        ("idx_audit_status", "audit_log", ["status_code"]),
        ("idx_audit_dialect", "audit_log", ["dialect"]),
    ]

    existing_indexes: set[str]
    if inspector.has_table("audit_log"):
        existing_indexes = {idx["name"] for idx in inspector.get_indexes("audit_log") if idx["name"] is not None}
    else:
        existing_indexes = set()

    for idx_name, table_name, columns in _indexes:
        if idx_name not in existing_indexes:
            op.create_index(idx_name, table_name, columns)


def downgrade() -> None:
    op.drop_index("idx_audit_dialect", table_name="audit_log")
    op.drop_index("idx_audit_status", table_name="audit_log")
    op.drop_index("idx_audit_cached", table_name="audit_log")
    op.drop_index("idx_audit_backend", table_name="audit_log")
    op.drop_index("idx_audit_model", table_name="audit_log")
    op.drop_index("idx_audit_timestamp", table_name="audit_log")
    op.drop_table("audit_log")
