"""
Database models for groknroll
"""

from datetime import datetime

from sqlalchemy import JSON, Column, DateTime, Float, ForeignKey, Index, Integer, String, Text
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship

Base = declarative_base()


class Project(Base):
    """Project metadata"""

    __tablename__ = "projects"

    id = Column(Integer, primary_key=True)
    path = Column(String, unique=True, nullable=False, index=True)
    name = Column(String, nullable=False)
    language = Column(String)  # Primary language
    total_files = Column(Integer, default=0)
    total_lines = Column(Integer, default=0)
    last_indexed = Column(DateTime)
    created_at = Column(DateTime, default=datetime.utcnow)
    updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)

    # Relationships
    files = relationship("FileIndex", back_populates="project", cascade="all, delete-orphan")
    executions = relationship("Execution", back_populates="project", cascade="all, delete-orphan")
    sessions = relationship("Session", back_populates="project", cascade="all, delete-orphan")
    analyses = relationship("Analysis", back_populates="project", cascade="all, delete-orphan")


class FileIndex(Base):
    """Indexed file metadata"""

    __tablename__ = "file_index"

    id = Column(Integer, primary_key=True)
    project_id = Column(Integer, ForeignKey("projects.id"), nullable=False, index=True)
    path = Column(String, nullable=False, index=True)
    relative_path = Column(String, nullable=False)
    language = Column(String)
    size_bytes = Column(Integer)
    lines_of_code = Column(Integer)
    complexity = Column(Float)  # Cyclomatic complexity
    last_modified = Column(DateTime)
    ast_data = Column(JSON)  # Parsed AST metadata
    imports = Column(JSON)  # List of imports
    exports = Column(JSON)  # List of exports
    created_at = Column(DateTime, default=datetime.utcnow)
    updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)

    # Relationships
    project = relationship("Project", back_populates="files")


class Execution(Base):
    """RLM execution history"""

    __tablename__ = "executions"

    id = Column(Integer, primary_key=True)
    project_id = Column(Integer, ForeignKey("projects.id"), index=True)
    session_id = Column(Integer, ForeignKey("sessions.id"), index=True)

    # Request
    task = Column(Text, nullable=False)
    context = Column(JSON)
    model = Column(String)

    # Response
    response = Column(Text)
    trace_log = Column(Text)

    # Metrics
    total_cost = Column(Float)
    total_time = Column(Float)
    iterations = Column(Integer)
    status = Column(String)  # success, failed, timeout
    error_message = Column(Text)

    # Timestamps
    started_at = Column(DateTime, default=datetime.utcnow, index=True)
    completed_at = Column(DateTime)
    created_at = Column(DateTime, default=datetime.utcnow)

    # Relationships
    project = relationship("Project", back_populates="executions")
    session = relationship("Session", back_populates="executions")


class Session(Base):
    """Interactive session history"""

    __tablename__ = "sessions"

    id = Column(Integer, primary_key=True)
    project_id = Column(Integer, ForeignKey("projects.id"), index=True)

    session_type = Column(String)  # chat, repl, dashboard
    started_at = Column(DateTime, default=datetime.utcnow, index=True)
    ended_at = Column(DateTime)
    message_count = Column(Integer, default=0)
    total_cost = Column(Float, default=0.0)

    # Relationships
    project = relationship("Project", back_populates="sessions")
    executions = relationship("Execution", back_populates="session", cascade="all, delete-orphan")


class Analysis(Base):
    """Code analysis results"""

    __tablename__ = "analyses"

    id = Column(Integer, primary_key=True)
    project_id = Column(Integer, ForeignKey("projects.id"), index=True)

    analysis_type = Column(String, nullable=False)  # security, complexity, review, etc
    target_path = Column(String)  # File or directory analyzed
    results = Column(JSON)  # Analysis results
    recommendations = Column(JSON)  # Recommendations
    issues = Column(JSON)  # Issues found
    metrics = Column(JSON)  # Metrics

    execution_time = Column(Float)
    created_at = Column(DateTime, default=datetime.utcnow, index=True)

    # Relationships
    project = relationship("Project", back_populates="analyses")


class ContextEntry(Base):
    """
    Persistent context storage for RLM.

    Stores all context, history, and variables permanently in SQLite.
    Never evicts data - provides 100% contextual awareness across sessions.

    Types:
    - context: Loaded context data (context_0, context_1, etc.)
    - history: Conversation message history (history_0, history_1, etc.)
    - variable: User-defined variables from REPL execution
    """

    __tablename__ = "context_entries"

    id = Column(Integer, primary_key=True)
    project_id = Column(Integer, ForeignKey("projects.id"), index=True)
    session_id = Column(Integer, ForeignKey("sessions.id"), nullable=True, index=True)

    # Context identification
    context_key = Column(String, index=True)  # "context_0", "history_1", "my_variable"
    context_type = Column(String, index=True)  # "context" | "history" | "variable"
    content = Column(Text)  # JSON serialized content
    content_hash = Column(String, index=True)  # SHA256 hash for deduplication
    variable_name = Column(String, index=True)  # Original variable name if applicable

    # Timestamps
    created_at = Column(DateTime, default=datetime.utcnow, index=True)
    accessed_at = Column(DateTime, default=datetime.utcnow)  # Updated on retrieval

    # Relationships
    project = relationship("Project")
    session = relationship("Session")


class CodeSummary(Base):
    """
    Hierarchical code summaries for intelligent retrieval.

    Stores LLM-generated summaries at different scope levels:
    - package: Directory-level summary
    - module: Single file summary
    - class: Class definition summary
    - function: Function definition summary

    Used by the hybrid retrieval system to find relevant code.
    """

    __tablename__ = "code_summaries"

    id = Column(Integer, primary_key=True)
    project_id = Column(Integer, ForeignKey("projects.id"), nullable=False, index=True)
    scope_type = Column(String, nullable=False)  # 'package', 'module', 'class', 'function'
    scope_path = Column(String, nullable=False)  # e.g., 'groknroll/oracle/oracle_agent.py'
    scope_name = Column(String)  # e.g., 'OracleAgent', 'ask'
    summary = Column(Text)  # LLM-generated summary
    keywords = Column(JSON)  # Extracted keywords for BM25
    parent_id = Column(Integer, ForeignKey("code_summaries.id"), nullable=True)
    signature = Column(String)  # Function signature or class inheritance
    docstring = Column(Text)  # Original docstring
    content_hash = Column(String, index=True)  # For change detection
    line_start = Column(Integer)  # Starting line number
    line_end = Column(Integer)  # Ending line number
    last_summarized = Column(DateTime)
    created_at = Column(DateTime, default=datetime.utcnow)
    updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)

    # Relationships
    project = relationship("Project")
    parent = relationship("CodeSummary", remote_side=[id], backref="children")

    # Composite index for efficient lookups
    __table_args__ = (
        Index("ix_code_summaries_project_scope", "project_id", "scope_type", "scope_path"),
    )


class CodeTerm(Base):
    """
    BM25 inverted index terms.

    Stores document frequency for each term in the index.
    Used for efficient BM25 scoring calculations.
    """

    __tablename__ = "code_terms"

    id = Column(Integer, primary_key=True)
    project_id = Column(Integer, ForeignKey("projects.id"), nullable=False, index=True)
    term = Column(String, nullable=False, index=True)
    document_freq = Column(Integer, default=1)  # Number of documents containing this term
    created_at = Column(DateTime, default=datetime.utcnow)

    # Relationships
    project = relationship("Project")

    # Unique constraint on project + term
    __table_args__ = (Index("ix_code_terms_project_term", "project_id", "term", unique=True),)


class TermOccurrence(Base):
    """
    Term occurrences for BM25 scoring.

    Links terms to summaries with field-specific term frequencies.
    Supports different weights for different fields (name, summary, docstring).
    """

    __tablename__ = "term_occurrences"

    id = Column(Integer, primary_key=True)
    term_id = Column(Integer, ForeignKey("code_terms.id"), nullable=False, index=True)
    summary_id = Column(Integer, ForeignKey("code_summaries.id"), nullable=False, index=True)
    term_freq = Column(Integer, default=1)  # Frequency in this document
    field_type = Column(String, nullable=False)  # 'name', 'summary', 'docstring', 'keywords'

    # Relationships
    term = relationship("CodeTerm")
    summary = relationship("CodeSummary")

    # Composite index for efficient BM25 lookups
    __table_args__ = (Index("ix_term_occurrences_term_summary", "term_id", "summary_id"),)


class CodeRelation(Base):
    """
    Code dependency graph edges.

    Stores relationships between code summaries for graph traversal:
    - imports: Source file imports target module
    - inherits: Source class inherits from target class
    - calls: Source function calls target function
    - contains: Source scope contains target scope (parent-child)

    Used to expand context by finding related code.
    """

    __tablename__ = "code_relations"

    id = Column(Integer, primary_key=True)
    source_id = Column(Integer, ForeignKey("code_summaries.id"), nullable=False, index=True)
    target_id = Column(Integer, ForeignKey("code_summaries.id"), nullable=False, index=True)
    relation_type = Column(String, nullable=False)  # 'imports', 'inherits', 'calls', 'contains'
    created_at = Column(DateTime, default=datetime.utcnow)

    # Relationships
    source = relationship("CodeSummary", foreign_keys=[source_id])
    target = relationship("CodeSummary", foreign_keys=[target_id])

    # Composite indexes for efficient graph traversal
    __table_args__ = (
        Index("ix_code_relations_source_type", "source_id", "relation_type"),
        Index("ix_code_relations_target_type", "target_id", "relation_type"),
    )


# =============================================================================
# OSINT Models
# =============================================================================


class OsintInvestigation(Base):
    """OSINT investigation session for dark web reconnaissance"""

    __tablename__ = "osint_investigations"

    id = Column(Integer, primary_key=True)
    project_id = Column(Integer, ForeignKey("projects.id"), index=True)
    query = Column(String, nullable=False)
    refined_query = Column(String)
    status = Column(String)  # 'pending', 'searching', 'scraping', 'analyzing', 'complete', 'failed'
    result_count = Column(Integer, default=0)
    report_path = Column(String)
    error_message = Column(Text)
    created_at = Column(DateTime, default=datetime.utcnow, index=True)
    completed_at = Column(DateTime)

    # Relationships
    project = relationship("Project")
    results = relationship("OsintResult", back_populates="investigation", cascade="all, delete-orphan")
    artifacts = relationship(
        "OsintArtifact", back_populates="investigation", cascade="all, delete-orphan"
    )


class OsintResult(Base):
    """Individual OSINT search result from dark web engines"""

    __tablename__ = "osint_results"

    id = Column(Integer, primary_key=True)
    investigation_id = Column(Integer, ForeignKey("osint_investigations.id"), nullable=False, index=True)
    url = Column(String, nullable=False)
    title = Column(String)
    content = Column(Text)
    source_engine = Column(String)
    relevance_score = Column(Float)
    scraped = Column(Integer, default=0)  # 0=not scraped, 1=scraped, -1=failed
    scraped_at = Column(DateTime)
    created_at = Column(DateTime, default=datetime.utcnow)

    # Relationships
    investigation = relationship("OsintInvestigation", back_populates="results")


class OsintArtifact(Base):
    """Extracted intelligence artifacts from OSINT investigations"""

    __tablename__ = "osint_artifacts"

    id = Column(Integer, primary_key=True)
    investigation_id = Column(Integer, ForeignKey("osint_investigations.id"), nullable=False, index=True)
    artifact_type = Column(String, nullable=False)  # 'email', 'btc', 'eth', 'onion', 'ip', 'phone', 'username'
    value = Column(String, nullable=False)
    context = Column(Text)  # Surrounding text for context
    source_url = Column(String)
    confidence = Column(Float, default=1.0)
    created_at = Column(DateTime, default=datetime.utcnow)

    # Relationships
    investigation = relationship("OsintInvestigation", back_populates="artifacts")

    # Composite index for efficient artifact lookups
    __table_args__ = (Index("ix_osint_artifacts_type_value", "artifact_type", "value"),)
