import enum

from sqlalchemy import (
    JSON,
    Boolean,
    Column,
    DateTime,
    Enum,
    Float,
    ForeignKey,
    Integer,
    Sequence,
    String,
    Text,
    UniqueConstraint,
)
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
from sqlalchemy.sql import func

Base = declarative_base()


class ResearchMode(enum.Enum):
    QUICK = "quick"
    DETAILED = "detailed"


class ResearchStatus(enum.Enum):
    PENDING = "pending"
    IN_PROGRESS = "in_progress"
    COMPLETED = "completed"
    FAILED = "failed"
    CANCELLED = "cancelled"


class ResearchHistory(Base):
    """Represents the research table."""

    __tablename__ = "research_history"

    # Unique identifier for each record.
    id = Column(Integer, primary_key=True, autoincrement=True)
    # The search query.
    query = Column(Text, nullable=False)
    # The mode of research (e.g., 'quick_summary', 'detailed_report').
    mode = Column(Text, nullable=False)
    # Current status of the research.
    status = Column(Text, nullable=False)
    # The timestamp when the research started.
    created_at = Column(Text, nullable=False)
    # The timestamp when the research was completed.
    completed_at = Column(Text)
    # Duration of the research in seconds.
    duration_seconds = Column(Integer)
    # Path to the generated report.
    report_path = Column(Text)
    # Additional metadata about the research.
    research_meta = Column(JSON)
    # Latest progress log message.
    progress_log = Column(JSON)
    # Current progress of the research (as a percentage).
    progress = Column(Integer)
    # Title of the research report.
    title = Column(Text)


class Research(Base):
    __tablename__ = "research"

    id = Column(Integer, primary_key=True, index=True)
    query = Column(String, nullable=False)
    status = Column(
        Enum(ResearchStatus), default=ResearchStatus.PENDING, nullable=False
    )
    mode = Column(
        Enum(ResearchMode), default=ResearchMode.QUICK, nullable=False
    )
    created_at = Column(DateTime, server_default=func.now(), nullable=False)
    updated_at = Column(
        DateTime, server_default=func.now(), onupdate=func.now(), nullable=False
    )
    progress = Column(Float, default=0.0, nullable=False)
    start_time = Column(DateTime, nullable=True)
    end_time = Column(DateTime, nullable=True)
    error_message = Column(Text, nullable=True)


class ResearchLog(Base):
    __tablename__ = "app_logs"

    id = Column(
        Integer, Sequence("reseach_log_id_seq"), primary_key=True, index=True
    )

    timestamp = Column(DateTime, server_default=func.now(), nullable=False)
    message = Column(Text, nullable=False)
    # Module that the log message came from.
    module = Column(Text, nullable=False)
    # Function that the log message came from.
    function = Column(Text, nullable=False)
    # Line number that the log message came from.
    line_no = Column(Integer, nullable=False)
    # Log level.
    level = Column(String(32), nullable=False)
    research_id = Column(
        Integer,
        ForeignKey("research.id", ondelete="CASCADE"),
        nullable=True,
        index=True,
    )


class SettingType(enum.Enum):
    APP = "app"
    LLM = "llm"
    SEARCH = "search"
    REPORT = "report"


class Setting(Base):
    """Database model for storing settings"""

    __tablename__ = "settings"

    id = Column(Integer, primary_key=True, index=True)
    key = Column(String(255), nullable=False, unique=True, index=True)
    value = Column(JSON, nullable=True)
    type = Column(Enum(SettingType), nullable=False, index=True)
    name = Column(String(255), nullable=False)
    description = Column(Text, nullable=True)
    category = Column(String(100), nullable=True, index=True)
    ui_element = Column(String(50), default="text", nullable=False)
    options = Column(JSON, nullable=True)  # For select elements
    min_value = Column(Float, nullable=True)  # For numeric inputs
    max_value = Column(Float, nullable=True)  # For numeric inputs
    step = Column(Float, nullable=True)  # For sliders
    visible = Column(Boolean, default=True, nullable=False)
    editable = Column(Boolean, default=True, nullable=False)
    created_at = Column(DateTime, server_default=func.now(), nullable=False)
    updated_at = Column(
        DateTime, server_default=func.now(), onupdate=func.now(), nullable=False
    )

    __table_args__ = (UniqueConstraint("key", name="uix_settings_key"),)


class ResearchStrategy(Base):
    """Database model for tracking research strategies used"""

    __tablename__ = "research_strategies"

    id = Column(Integer, primary_key=True, index=True)
    research_id = Column(
        Integer,
        ForeignKey("research.id", ondelete="CASCADE"),
        nullable=False,
        unique=True,
        index=True,
    )
    strategy_name = Column(String(100), nullable=False, index=True)
    created_at = Column(DateTime, server_default=func.now(), nullable=False)

    # Relationship
    research = relationship("Research", backref="strategy")


class Journal(Base):
    """
    Database model for storing information about academic journals.
    """

    __tablename__ = "journals"

    id = Column(
        Integer, Sequence("journal_id_seq"), primary_key=True, index=True
    )

    # Name of the journal
    name = Column(String(255), nullable=False, unique=True, index=True)
    # Quality score of the journal
    quality = Column(Integer, nullable=True)
    # Model that was used to generate the quality score.
    quality_model = Column(String(255), nullable=True, index=True)
    # Time at which the quality was last analyzed.
    quality_analysis_time = Column(Integer, nullable=False)
