from sqlalchemy import Column, Integer, String, Float, Boolean, DateTime, Text, ARRAY, ForeignKey from sqlalchemy.dialects.postgresql import UUID, JSONB from sqlalchemy.sql import func import uuid try: from backend.database import Base except ImportError: # pragma: no cover - compatibility for direct module runs from database import Base class User(Base): """User model for authentication.""" __tablename__ = "users" id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) username = Column(String(100), unique=True, nullable=False) email = Column(String(255), unique=True, nullable=False) hashed_password = Column(String(255), nullable=False) full_name = Column(String(255)) role = Column(String(20), nullable=False, default="operator") is_active = Column(Boolean, default=True) created_at = Column(DateTime, server_default=func.now()) last_login = Column(DateTime) class Case(Base): """Unified case model - combines search case and result.""" __tablename__ = "cases" id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) created_at = Column(DateTime, server_default=func.now()) status = Column(String(20), default="active") child_name = Column(String(255)) age_years = Column(Integer, nullable=False) gender = Column(String(1)) height_build = Column(Text) clothes_upper = Column(Text) clothes_lower = Column(Text) shoes = Column(Text) clothes_description = Column(Text) special_marks = Column(Text) phone_status = Column(String(20)) has_diagnosis = Column(Boolean, default=False) diagnosis_type = Column(ARRAY(String)) fitness_level = Column(String(20)) has_transport = Column(String(20), default="none") cant_swim = Column(Boolean, default=False) psychotype = Column(String(50)) psychotype_answers = Column(JSONB) loss_reason = Column(String(100)) loss_time = Column(DateTime) elapsed_hours = Column(Float) last_seen_direction = Column(String(10)) last_seen_reliability = Column(String(20)) last_seen_description = Column(Text) behavior_description = Column(Text) familiar_places = Column(Text) lost_before = Column(String(20)) season = Column(String(20)) temperature_c = Column(Float) precipitation = Column(String(20)) visibility = Column(String(20)) wind = Column(String(20)) terrain = Column(ARRAY(String)) tnp_lat = Column(Float) tnp_lon = Column(Float) tnp_address = Column(Text) teams_count = Column(Integer) team_size = Column(Integer) has_dog = Column(Boolean, default=False) extra_resources = Column(ARRAY(String)) found_alive = Column(Boolean) found_distance_km = Column(Float) found_direction = Column(String(10)) found_location_type = Column(String(50)) found_lat = Column(Float) found_lon = Column(Float) search_duration_hours = Column(Float) who_found = Column(String(50)) confidence_avg = Column(Float) raw_text = Column(Text) analysis_log = Column(JSONB) class AnalysisLog(Base): """Analysis log for audit and debugging.""" __tablename__ = "analysis_log" id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) case_id = Column(UUID(as_uuid=True), ForeignKey("cases.id", ondelete="CASCADE"), nullable=False) user_id = Column(UUID(as_uuid=True), ForeignKey("users.id", ondelete="SET NULL")) analysis_type = Column(String(50), nullable=False) input_data = Column(JSONB) output_data = Column(JSONB) execution_time = Column(Float) status = Column(String(20), default="success") error_message = Column(Text) created_at = Column(DateTime, server_default=func.now()) class RawDocument(Base): """Raw document storage for parsed reports.""" __tablename__ = "raw_documents" id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) filename = Column(String(255), nullable=False) raw_text = Column(Text) extracted_json = Column(JSONB) created_at = Column(DateTime, server_default=func.now())