from datetime import datetime from typing import Any from uuid import uuid4 from sqlalchemy import ( JSON, Boolean, DateTime, ForeignKey, Integer, String, UniqueConstraint, false, func, ) from sqlalchemy.orm import Mapped, mapped_column from ai_platform.infrastructure.persistence.database import Base class AppCredential(Base): __tablename__ = "app_credentials" app_id: Mapped[str] = mapped_column(String(128), primary_key=True) verifier: Mapped[str] = mapped_column(String(64), nullable=False, unique=True) active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) updated_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), nullable=False ) class AdminUser(Base): __tablename__ = "admin_users" email: Mapped[str] = mapped_column(String(254), primary_key=True) password_hash: Mapped[str] = mapped_column(String(512), nullable=False) class AdminSession(Base): __tablename__ = "admin_sessions" id: Mapped[str] = mapped_column(String(64), primary_key=True) admin_email: Mapped[str] = mapped_column(ForeignKey("admin_users.email"), nullable=False) csrf_hash: Mapped[str] = mapped_column(String(64), nullable=False) expires_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False) class AIProfile(Base): __tablename__ = "ai_profiles" revision: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) provider: Mapped[str] = mapped_column(String(32), nullable=False) base_url: Mapped[str] = mapped_column(String(2048), nullable=False) model: Mapped[str] = mapped_column(String(128), nullable=False) timeout_seconds: Mapped[int] = mapped_column(Integer, nullable=False) reasoning_effort: Mapped[str | None] = mapped_column(String(16)) instructions: Mapped[str] = mapped_column(String(8000), nullable=False) include_reference_date: Mapped[bool] = mapped_column(Boolean, nullable=False) timezone: Mapped[str] = mapped_column(String(64), nullable=False) suggested_action_enabled: Mapped[bool] = mapped_column(Boolean, nullable=False) created_by: Mapped[str] = mapped_column(String(254), nullable=False) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False) active: Mapped[bool] = mapped_column( Boolean, default=False, server_default=false(), nullable=False ) class ScoringRun(Base): __tablename__ = "scoring_runs" __table_args__ = (UniqueConstraint("app_id", "idempotency_key", name="uq_run_app_key"),) id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid4())) app_id: Mapped[str] = mapped_column(ForeignKey("app_credentials.app_id"), index=True) idempotency_key: Mapped[str] = mapped_column(String(36), nullable=False) fingerprint: Mapped[str] = mapped_column(String(64), nullable=False) created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), server_default=func.now(), index=True ) request: Mapped[dict[str, Any]] = mapped_column(JSON, nullable=False) rule_score: Mapped[int] = mapped_column(Integer, nullable=False) ai_score: Mapped[int | None] = mapped_column(Integer) final_score: Mapped[int] = mapped_column(Integer, nullable=False) result_mode: Mapped[str] = mapped_column(String(32), nullable=False) error_code: Mapped[str | None] = mapped_column(String(64)) breakdown: Mapped[list[dict[str, Any]]] = mapped_column(JSON, nullable=False) ai: Mapped[dict[str, Any] | None] = mapped_column(JSON) profile_revision: Mapped[int | None] = mapped_column(ForeignKey("ai_profiles.revision")) duration_ms: Mapped[int] = mapped_column(Integer, nullable=False)