"""
Database-related Pydantic models for the Graph API.
"""

from typing import Any

from pydantic import BaseModel, Field


class QueryRequest(BaseModel):
  """Request model for Cypher query execution."""

  database: str = Field(
    ..., description="Target database name", pattern=r"^[a-zA-Z0-9_-]+$", max_length=64
  )
  cypher: str = Field(..., description="Cypher query to execute", max_length=10000)
  parameters: dict[str, Any] | None = Field(
    default=None, description="Query parameters"
  )

  class Config:
    # Prevent additional fields to avoid injection
    extra = "forbid"


class QueryResponse(BaseModel):
  """Response model for query results."""

  data: list[dict[str, Any]] = Field(..., description="Query result rows")
  columns: list[str] = Field(..., description="Column names")
  execution_time_ms: float = Field(
    ..., description="Query execution time in milliseconds"
  )
  row_count: int = Field(..., description="Number of rows returned")
  database: str = Field(..., description="Database that executed the query")


class SchemaInstallRequest(BaseModel):
  """Request to install schema on existing database."""

  type: str = Field(..., description="Schema type (custom, ddl)")
  ddl: str | None = Field(None, description="DDL commands to execute")
  metadata: dict[str, Any] | None = Field(
    None, description="Schema metadata (name, version, etc)"
  )


class SchemaInstallResponse(BaseModel):
  """Response from schema installation."""

  success: bool = Field(..., description="Whether schema was installed successfully")
  message: str = Field(..., description="Success or error message")
  statements_executed: int = Field(0, description="Number of DDL statements executed")


class S3Destination(BaseModel):
  """Target S3 location for on-instance backup upload."""

  bucket: str = Field(..., description="S3 bucket name")
  key: str = Field(..., description="S3 object key")


class BackupRequest(BaseModel):
  """Request model for database backup."""

  backup_format: str = Field(
    default="full_dump",
    description="Backup format: 'full_dump' (complete .lbug database file)",
    pattern="^full_dump$",  # Only allow full_dump for now
  )
  include_metadata: bool = Field(
    default=True, description="Include database metadata and schema information"
  )
  compression: bool = Field(
    default=True, description="Enable compression (always recommended)"
  )
  encryption: bool = Field(
    default=False, description="Enable encryption for secure storage"
  )
  backup_type: str = Field(
    default="standard",
    description="Backup type: 'standard' (ZIP to S3), 'replica' (raw .lbug to S3), 'shared_repository' (tar.gz to S3), 'duckdb_staging' (raw .duckdb to S3)",
    pattern="^(standard|replica|shared_repository|duckdb_staging|r2_download)$",
  )
  s3_destination: S3Destination | None = Field(
    default=None,
    description="Target S3 location for on-instance upload (required for replica/shared_repository types)",
  )
  checkpoint: bool = Field(
    default=True,
    description="Run CHECKPOINT to flush WAL before backup",
  )
  vacuum: bool = Field(
    default=False,
    description="Run VACUUM to compact database before backup (DuckDB only)",
  )


class BackupResponse(BaseModel):
  """Response from backup operation."""

  task_id: str = Field(
    ..., description="Background task ID for monitoring backup progress"
  )
  status: str = Field(..., description="Initial backup status")
  message: str = Field(..., description="Backup initiation message")
  database: str = Field(..., description="Database being backed up")
  backup_format: str = Field(..., description="Backup format requested")
  monitor_url: str | None = Field(
    None, description="SSE endpoint URL for monitoring backup progress"
  )
  estimated_completion_time: str | None = Field(
    None, description="Estimated completion time (ISO format)"
  )


class DatabaseInfo(BaseModel):
  """Information about a database on this node."""

  graph_id: str = Field(..., description="Graph database identifier")
  database_path: str = Field(..., description="Full path to database files")
  created_at: str = Field(..., description="Database creation timestamp")
  size_bytes: int = Field(..., description="Database size in bytes")
  read_only: bool = Field(..., description="Whether database is read-only")
  is_healthy: bool = Field(..., description="Database health status")
  last_accessed: str | None = Field(None, description="Last access timestamp")


class DatabaseCreateRequest(BaseModel):
  """Request to create a new database."""

  graph_id: str = Field(
    ...,
    description="Graph database identifier",
    pattern=r"^[a-zA-Z0-9_-]+$",
    max_length=64,
  )
  schema_type: str = Field(
    default="entity",
    description="Schema type (entity, shared, custom)",
    pattern=r"^(entity|shared|custom)$",
  )
  repository_name: str | None = Field(
    None,
    description="Repository name for shared schemas (e.g., 'sec', 'industry')",
  )
  custom_schema_ddl: str | None = Field(
    None,
    description="Custom DDL commands for custom schema type",
  )
  is_subgraph: bool = Field(
    default=False,
    description="Whether this is a subgraph (bypasses max_databases check for higher tiers)",
  )
  tenant_tier: str = Field(
    default="ladybug-standard",
    description="Tenant tier affecting resource allocation",
    pattern=r"^(free|ladybug-standard|ladybug-large|ladybug-xlarge|ladybug-shared)$",
  )


class DatabaseCreateResponse(BaseModel):
  """Response from database creation."""

  status: str = Field(..., description="Creation status")
  graph_id: str = Field(..., description="Graph database identifier")
  database_path: str = Field(..., description="Path to created database")
  schema_applied: bool = Field(..., description="Whether schema was applied")
  execution_time_ms: float = Field(..., description="Creation time in milliseconds")


class DatabaseListResponse(BaseModel):
  """Response listing all databases."""

  databases: list[DatabaseInfo] = Field(..., description="List of databases")
  total_databases: int = Field(..., description="Total number of databases")
  total_size_bytes: int = Field(..., description="Total size of all databases")
  node_capacity: dict[str, Any] = Field(..., description="Node capacity information")


class NodeDatabasesHealthResponse(BaseModel):
  """Health status for all databases on a cluster node."""

  healthy_databases: int = Field(..., description="Number of healthy databases")
  unhealthy_databases: int = Field(..., description="Number of unhealthy databases")
  databases: list[DatabaseInfo] = Field(..., description="Database health details")


class RestoreResponse(BaseModel):
  """Response from restore operation."""

  task_id: str = Field(
    ..., description="Background task ID for monitoring restore progress"
  )
  status: str = Field(..., description="Initial restore status")
  message: str = Field(..., description="Restore initiation message")
  database: str = Field(..., description="Database being restored")
  monitor_url: str | None = Field(
    None, description="SSE endpoint URL for monitoring restore progress"
  )
  system_backup_created: bool = Field(
    ..., description="Whether system backup was created"
  )
