-- CodeGraph SQLite Schema for OpenClaw
-- Migrated from CodeGraph `src/db/schema.sql`
-- Nodes = symbols, Edges = relationships, Files = file metadata

CREATE TABLE IF NOT EXISTS files (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    path TEXT NOT NULL UNIQUE,
    hash TEXT NOT NULL,
    language TEXT NOT NULL DEFAULT 'unknown',
    size_bytes INTEGER DEFAULT 0,
    line_count INTEGER DEFAULT 0,
    last_indexed TEXT NOT NULL DEFAULT (datetime('now')),
    UNIQUE(path)
);

CREATE TABLE IF NOT EXISTS nodes (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    kind TEXT NOT NULL,                    -- function, class, method, variable, import, export, interface, type
    name TEXT NOT NULL,
    qualified_name TEXT,                   -- Module.Class.method
    file_id INTEGER NOT NULL REFERENCES files(id) ON DELETE CASCADE,
    line_start INTEGER,
    line_end INTEGER,
    signature TEXT,                        -- function/method signature
    visibility TEXT DEFAULT 'public',      -- public, private, protected
    docstring TEXT,
    metadata TEXT,                         -- JSON: extra info
    created_at TEXT NOT NULL DEFAULT (datetime('now'))
);

CREATE TABLE IF NOT EXISTS edges (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    from_node_id INTEGER NOT NULL REFERENCES nodes(id) ON DELETE CASCADE,
    to_node_id INTEGER NOT NULL REFERENCES nodes(id) ON DELETE CASCADE,
    kind TEXT NOT NULL,                    -- calls, imports, exports, extends, implements, references, contains, returns, decorates
    metadata TEXT,                         -- JSON: line, context, etc.
    created_at TEXT NOT NULL DEFAULT (datetime('now')),
    UNIQUE(from_node_id, to_node_id, kind)
);

CREATE TABLE IF NOT EXISTS unresolved_refs (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    file_id INTEGER NOT NULL REFERENCES files(id) ON DELETE CASCADE,
    name TEXT NOT NULL,
    kind TEXT NOT NULL DEFAULT 'unknown',  -- import, call, reference, extend
    context TEXT,                          -- surrounding code snippet
    line_number INTEGER,
    column_number INTEGER,
    resolved_node_id INTEGER REFERENCES nodes(id),
    created_at TEXT NOT NULL DEFAULT (datetime('now'))
);

-- FTS5 full-text search index on node names + signatures
CREATE VIRTUAL TABLE IF NOT EXISTS nodes_fts USING fts5(
    name,
    qualified_name,
    signature,
    docstring,
    content='nodes',
    content_rowid='id',
    tokenize='unicode61'
);

-- Triggers to keep FTS index in sync
CREATE TRIGGER IF NOT EXISTS nodes_ai AFTER INSERT ON nodes BEGIN
    INSERT INTO nodes_fts(rowid, name, qualified_name, signature, docstring)
    VALUES (new.id, new.name, new.qualified_name, new.signature, new.docstring);
END;

CREATE TRIGGER IF NOT EXISTS nodes_ad AFTER DELETE ON nodes BEGIN
    INSERT INTO nodes_fts(nodes_fts, rowid, name, qualified_name, signature, docstring)
    VALUES ('delete', old.id, old.name, old.qualified_name, old.signature, old.docstring);
END;

CREATE TRIGGER IF NOT EXISTS nodes_au AFTER UPDATE ON nodes BEGIN
    INSERT INTO nodes_fts(nodes_fts, rowid, name, qualified_name, signature, docstring)
    VALUES ('delete', old.id, old.name, old.qualified_name, old.signature, old.docstring);
    INSERT INTO nodes_fts(rowid, name, qualified_name, signature, docstring)
    VALUES (new.id, new.name, new.qualified_name, new.signature, new.docstring);
END;

-- Project metadata
CREATE TABLE IF NOT EXISTS project_meta (
    key TEXT PRIMARY KEY,
    value TEXT,
    updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);

-- Composite indexes
CREATE INDEX IF NOT EXISTS idx_nodes_file ON nodes(file_id);
CREATE INDEX IF NOT EXISTS idx_nodes_kind ON nodes(kind);
CREATE INDEX IF NOT EXISTS idx_nodes_name ON nodes(name);
CREATE INDEX IF NOT EXISTS idx_edges_from ON edges(from_node_id);
CREATE INDEX IF NOT EXISTS idx_edges_to ON edges(to_node_id);
CREATE INDEX IF NOT EXISTS idx_edges_kind ON edges(kind);
CREATE INDEX IF NOT EXISTS idx_unresolved_file ON unresolved_refs(file_id);
CREATE INDEX IF NOT EXISTS idx_unresolved_name ON unresolved_refs(name);
