"""
Database schema for local code intelligence storage.
"""

import sqlite3

SCHEMA_VERSION = 2  # Increment when schema changes


def create_schema(conn: sqlite3.Connection) -> None:
    """Create all database tables for code intelligence storage."""
    conn.executescript(
        """
        -- Schema version tracking
        CREATE TABLE IF NOT EXISTS schema_version (
            version INTEGER PRIMARY KEY
        );

        -- Files table (already exists in watcher/storage.py, but included for completeness)
        CREATE TABLE IF NOT EXISTS files (
            id INTEGER PRIMARY KEY,
            path TEXT UNIQUE NOT NULL,
            content_hash TEXT NOT NULL,
            last_modified REAL NOT NULL,
            synced_at REAL,
            status TEXT NOT NULL DEFAULT 'active'
        );

        -- Sync events table (already exists)
        CREATE TABLE IF NOT EXISTS sync_events (
            id INTEGER PRIMARY KEY,
            file_id INTEGER NOT NULL,
            event_type TEXT NOT NULL,
            content_hash TEXT NOT NULL,
            timestamp REAL NOT NULL,
            FOREIGN KEY (file_id) REFERENCES files(id)
        );

        -- Symbols table (unified for all types: class, function, method, variable)
        CREATE TABLE IF NOT EXISTS symbols (
            id TEXT PRIMARY KEY,           -- "path/file.py::ClassName::method"
            name TEXT NOT NULL,
            file_id INTEGER NOT NULL,
            kind TEXT NOT NULL,            -- class/function/method/variable/etc
            parent_symbol_id TEXT,         -- For methods: their class symbol id
            exported INTEGER DEFAULT 0,
            line_start INTEGER,
            line_end INTEGER,
            signature TEXT,
            docstring TEXT,
            extra_data TEXT,               -- JSON for decorators, params, etc
            FOREIGN KEY (file_id) REFERENCES files(id) ON DELETE CASCADE,
            FOREIGN KEY (parent_symbol_id) REFERENCES symbols(id) ON DELETE CASCADE
        );

        -- File-level imports (which files import which)
        CREATE TABLE IF NOT EXISTS imports (
            id INTEGER PRIMARY KEY,
            source_file_id INTEGER NOT NULL,
            target_file_id INTEGER,        -- NULL if external module
            module_name TEXT NOT NULL,     -- The imported module path
            UNIQUE(source_file_id, module_name),
            FOREIGN KEY (source_file_id) REFERENCES files(id) ON DELETE CASCADE,
            FOREIGN KEY (target_file_id) REFERENCES files(id) ON DELETE CASCADE
        );

        -- Symbol-level imports (what symbols are imported from where)
        CREATE TABLE IF NOT EXISTS symbol_imports (
            id INTEGER PRIMARY KEY,
            source_file_id INTEGER NOT NULL,
            module_name TEXT NOT NULL,
            symbol_names TEXT NOT NULL,    -- JSON array of imported symbol names
            import_type TEXT NOT NULL,     -- 'named', 'default', 'wildcard', 'namespace'
            alias TEXT,                    -- Alias if renamed
            line INTEGER,
            FOREIGN KEY (source_file_id) REFERENCES files(id) ON DELETE CASCADE
        );

        -- Call edges (function/method calls)
        CREATE TABLE IF NOT EXISTS calls (
            id INTEGER PRIMARY KEY,
            caller_id TEXT NOT NULL,       -- Symbol id of the caller
            callee_id TEXT,                -- Symbol id of callee (NULL if unresolved)
            callee_name TEXT NOT NULL,     -- Name of the called function/method
            call_type TEXT NOT NULL,       -- 'function', 'method', 'constructor'
            receiver TEXT,                 -- For method calls: the receiver expression
            line INTEGER,
            FOREIGN KEY (caller_id) REFERENCES symbols(id) ON DELETE CASCADE,
            FOREIGN KEY (callee_id) REFERENCES symbols(id) ON DELETE SET NULL
        );

        -- Inheritance relationships
        CREATE TABLE IF NOT EXISTS inheritance (
            id INTEGER PRIMARY KEY,
            child_id TEXT NOT NULL,        -- Symbol id of the child class
            parent_name TEXT NOT NULL,     -- Name of the parent (may be unresolved)
            parent_id TEXT,                -- Symbol id of parent (NULL if external)
            type TEXT NOT NULL,            -- 'extends' or 'implements'
            FOREIGN KEY (child_id) REFERENCES symbols(id) ON DELETE CASCADE,
            FOREIGN KEY (parent_id) REFERENCES symbols(id) ON DELETE SET NULL
        );

        -- Indexes for efficient querying
        CREATE INDEX IF NOT EXISTS idx_files_path ON files(path);
        CREATE INDEX IF NOT EXISTS idx_files_status ON files(status);
        CREATE INDEX IF NOT EXISTS idx_symbols_file_id ON symbols(file_id);
        CREATE INDEX IF NOT EXISTS idx_symbols_name ON symbols(name);
        CREATE INDEX IF NOT EXISTS idx_symbols_kind ON symbols(kind);
        CREATE INDEX IF NOT EXISTS idx_symbols_parent ON symbols(parent_symbol_id);
        CREATE INDEX IF NOT EXISTS idx_imports_source ON imports(source_file_id);
        CREATE INDEX IF NOT EXISTS idx_imports_target ON imports(target_file_id);
        CREATE INDEX IF NOT EXISTS idx_symbol_imports_source ON symbol_imports(source_file_id);
        CREATE INDEX IF NOT EXISTS idx_calls_caller ON calls(caller_id);
        CREATE INDEX IF NOT EXISTS idx_calls_callee ON calls(callee_id);
        CREATE INDEX IF NOT EXISTS idx_calls_name ON calls(callee_name);
        CREATE INDEX IF NOT EXISTS idx_inheritance_child ON inheritance(child_id);
        CREATE INDEX IF NOT EXISTS idx_inheritance_parent ON inheritance(parent_id);
    """
    )


def get_schema_version(conn: sqlite3.Connection) -> int:
    """Get the current schema version from database."""
    try:
        cursor = conn.execute("SELECT version FROM schema_version LIMIT 1")
        row = cursor.fetchone()
        return row[0] if row else 0
    except sqlite3.OperationalError:
        return 0


def set_schema_version(conn: sqlite3.Connection, version: int) -> None:
    """Set the schema version in database."""
    conn.execute("DELETE FROM schema_version")
    conn.execute("INSERT INTO schema_version (version) VALUES (?)", (version,))
    conn.commit()


def migrate_schema(conn: sqlite3.Connection) -> bool:
    """
    Migrate schema to latest version if needed.
    Returns True if migration was performed.
    """
    current_version = get_schema_version(conn)

    if current_version >= SCHEMA_VERSION:
        return False

    # For now, we recreate schema on version mismatch
    # In production, you'd want proper migrations
    create_schema(conn)
    set_schema_version(conn, SCHEMA_VERSION)

    return True
