"""SQLAlchemy models for code graph storage."""

from __future__ import annotations

from datetime import datetime

from sqlalchemy import Boolean, DateTime, ForeignKey, Integer, String, Text, func
from sqlalchemy.orm import Mapped, mapped_column, relationship

from common.db import Base


class CodeVersion(Base):
    """Tracks a versioned snapshot of indexed code."""

    __tablename__ = "code_versions"

    id: Mapped[int] = mapped_column(primary_key=True)
    version_tag: Mapped[str] = mapped_column(String(128), unique=True, index=True)
    release_label: Mapped[str] = mapped_column(String(256), default="")
    base_commit: Mapped[str] = mapped_column(String(64), default="")
    file_count: Mapped[int] = mapped_column(Integer, default=0)
    entity_count: Mapped[int] = mapped_column(Integer, default=0)
    is_latest: Mapped[bool] = mapped_column(Boolean, default=True, index=True)
    indexed_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())

    files: Mapped[list[File]] = relationship(back_populates="version", cascade="all, delete-orphan")


class File(Base):
    __tablename__ = "files"

    id: Mapped[int] = mapped_column(primary_key=True)
    path: Mapped[str] = mapped_column(String(2048), index=True)
    language: Mapped[str] = mapped_column(String(64), index=True)
    hash: Mapped[str | None] = mapped_column(String(128), nullable=True)
    lines_of_code: Mapped[int] = mapped_column(Integer, default=0)
    tokens: Mapped[int] = mapped_column(Integer, default=0)
    version_id: Mapped[int | None] = mapped_column(
        ForeignKey("code_versions.id", ondelete="CASCADE"), index=True, nullable=True
    )

    version: Mapped[CodeVersion | None] = relationship(back_populates="files")
    entities: Mapped[list[Entity]] = relationship(back_populates="file", cascade="all, delete-orphan")
    dependencies: Mapped[list[Dependency]] = relationship(back_populates="source_file", cascade="all, delete-orphan")


class Entity(Base):
    __tablename__ = "entities"

    id: Mapped[int] = mapped_column(primary_key=True)
    file_id: Mapped[int] = mapped_column(ForeignKey("files.id", ondelete="CASCADE"), index=True)
    name: Mapped[str] = mapped_column(String(512), index=True)
    qualified_name: Mapped[str | None] = mapped_column(String(1024), index=True, nullable=True)
    type: Mapped[str] = mapped_column(String(128), index=True)
    kind: Mapped[str | None] = mapped_column(String(128), nullable=True)
    signature: Mapped[str | None] = mapped_column(Text, nullable=True)
    start_line: Mapped[int] = mapped_column(Integer, default=0)
    end_line: Mapped[int] = mapped_column(Integer, default=0)
    column_start: Mapped[int] = mapped_column(Integer, default=0)
    column_end: Mapped[int] = mapped_column(Integer, default=0)
    documentation: Mapped[str | None] = mapped_column(Text, nullable=True)
    parent: Mapped[str | None] = mapped_column(String(512), nullable=True)
    visibility: Mapped[str | None] = mapped_column(String(64), index=True, nullable=True)
    scope: Mapped[str | None] = mapped_column(String(64), nullable=True)
    language: Mapped[str | None] = mapped_column(String(64), index=True, nullable=True)
    attributes: Mapped[str | None] = mapped_column(Text, nullable=True)

    file: Mapped[File] = relationship(back_populates="entities")
    source_relations: Mapped[list[EntityRelation]] = relationship(
        foreign_keys="EntityRelation.source_entity_id",
        back_populates="source_entity",
        cascade="all, delete-orphan",
    )
    target_relations: Mapped[list[EntityRelation]] = relationship(
        foreign_keys="EntityRelation.target_entity_id",
        back_populates="target_entity",
        cascade="all, delete-orphan",
    )


class Dependency(Base):
    __tablename__ = "dependencies"

    id: Mapped[int] = mapped_column(primary_key=True)
    source_file_id: Mapped[int] = mapped_column(ForeignKey("files.id", ondelete="CASCADE"), index=True)
    target_path: Mapped[str] = mapped_column(String(2048))
    import_type: Mapped[str | None] = mapped_column(String(64), nullable=True)
    line_number: Mapped[int] = mapped_column(Integer, default=0)
    resolved: Mapped[str | None] = mapped_column(String(2048), nullable=True)
    is_local: Mapped[bool] = mapped_column(Boolean, default=False)

    source_file: Mapped[File] = relationship(back_populates="dependencies")


class EntityRelation(Base):
    __tablename__ = "entity_relations"

    id: Mapped[int] = mapped_column(primary_key=True)
    source_entity_id: Mapped[int] = mapped_column(ForeignKey("entities.id", ondelete="CASCADE"), index=True)
    target_entity_id: Mapped[int] = mapped_column(ForeignKey("entities.id", ondelete="CASCADE"), index=True)
    relation_type: Mapped[str] = mapped_column(String(64), index=True)
    line_number: Mapped[int] = mapped_column(Integer, default=0)
    context: Mapped[str | None] = mapped_column(Text, nullable=True)

    source_entity: Mapped[Entity] = relationship(foreign_keys=[source_entity_id], back_populates="source_relations")
    target_entity: Mapped[Entity] = relationship(foreign_keys=[target_entity_id], back_populates="target_relations")
