from datetime import datetime
from typing import Optional
from sqlalchemy import String, Float, Integer, Boolean, DateTime, JSON, ForeignKey
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship


class Base(DeclarativeBase):
    pass


class FlightModel(Base):
    __tablename__ = "flights"

    id: Mapped[str] = mapped_column(String(36), primary_key=True)
    name: Mapped[str] = mapped_column(String(255))
    description: Mapped[str] = mapped_column(String(1000))
    start_lat: Mapped[float] = mapped_column(Float)
    start_lon: Mapped[float] = mapped_column(Float)
    altitude: Mapped[float] = mapped_column(Float)
    camera_params: Mapped[dict] = mapped_column(JSON)
    geofences: Mapped[dict] = mapped_column(JSON)
    status: Mapped[str] = mapped_column(String(50), default="created")
    frames_processed: Mapped[int] = mapped_column(Integer, default=0)
    frames_total: Mapped[int] = mapped_column(Integer, default=0)
    created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
    updated_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)

    waypoints: Mapped[list["WaypointModel"]] = relationship(back_populates="flight", cascade="all, delete-orphan")
    frame_results: Mapped[list["FrameResultModel"]] = relationship(back_populates="flight", cascade="all, delete-orphan")
    chunks: Mapped[list["ChunkModel"]] = relationship(back_populates="flight", cascade="all, delete-orphan")


class WaypointModel(Base):
    __tablename__ = "waypoints"

    id: Mapped[str] = mapped_column(String(36), primary_key=True)
    flight_id: Mapped[str] = mapped_column(String(36), ForeignKey("flights.id"))
    lat: Mapped[float] = mapped_column(Float)
    lon: Mapped[float] = mapped_column(Float)
    altitude: Mapped[Optional[float]] = mapped_column(Float, nullable=True)
    confidence: Mapped[float] = mapped_column(Float, default=0.0)
    refined: Mapped[bool] = mapped_column(Boolean, default=False)
    timestamp: Mapped[datetime] = mapped_column(DateTime)

    flight: Mapped["FlightModel"] = relationship(back_populates="waypoints")


class FrameResultModel(Base):
    __tablename__ = "frame_results"

    id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
    flight_id: Mapped[str] = mapped_column(String(36), ForeignKey("flights.id"))
    frame_id: Mapped[int] = mapped_column(Integer)
    gps_lat: Mapped[float] = mapped_column(Float)
    gps_lon: Mapped[float] = mapped_column(Float)
    altitude: Mapped[float] = mapped_column(Float)
    heading: Mapped[float] = mapped_column(Float)
    confidence: Mapped[float] = mapped_column(Float)
    refined: Mapped[bool] = mapped_column(Boolean, default=False)
    objects: Mapped[dict] = mapped_column(JSON, default=list)
    timestamp: Mapped[datetime] = mapped_column(DateTime)
    updated_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)

    flight: Mapped["FlightModel"] = relationship(back_populates="frame_results")


class ChunkModel(Base):
    __tablename__ = "chunks"

    id: Mapped[str] = mapped_column(String(36), primary_key=True)
    flight_id: Mapped[str] = mapped_column(String(36), ForeignKey("flights.id"))
    start_frame_id: Mapped[int] = mapped_column(Integer)
    end_frame_id: Mapped[Optional[int]] = mapped_column(Integer, nullable=True)
    frames: Mapped[list] = mapped_column(JSON, default=list)
    is_active: Mapped[bool] = mapped_column(Boolean, default=True)
    has_anchor: Mapped[bool] = mapped_column(Boolean, default=False)
    anchor_frame_id: Mapped[Optional[int]] = mapped_column(Integer, nullable=True)
    anchor_lat: Mapped[Optional[float]] = mapped_column(Float, nullable=True)
    anchor_lon: Mapped[Optional[float]] = mapped_column(Float, nullable=True)
    matching_status: Mapped[str] = mapped_column(String(50), default="unanchored")
    created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
    updated_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)

    flight: Mapped["FlightModel"] = relationship(back_populates="chunks")

