-- Built-in knowledge base schema
--
-- Apply this to the agent-system skills database.
--
-- Prerequisites:
--   CREATE EXTENSION IF NOT EXISTS pgcrypto;
--   CREATE EXTENSION IF NOT EXISTS vector;

--------------------------------------------------------------------------------
-- ARTIFACT METADATA
--------------------------------------------------------------------------------

CREATE TABLE IF NOT EXISTS builtin_knowledge_artifacts (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    artifact_version TEXT NOT NULL UNIQUE,
    schema_version TEXT NOT NULL,
    source_snapshot TEXT,
    chunker_name TEXT NOT NULL,
    chunker_version TEXT NOT NULL,
    chunk_size INTEGER NOT NULL,
    chunk_overlap INTEGER NOT NULL DEFAULT 0,
    embedding_provider TEXT,
    embedding_model TEXT,
    embedding_dimensions INTEGER,
    generated_at TIMESTAMPTZ NOT NULL,
    document_count INTEGER,
    chunk_count INTEGER,
    embedding_count INTEGER,
    git_commit TEXT,
    metadata JSONB NOT NULL DEFAULT '{}'::jsonb,
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

--------------------------------------------------------------------------------
-- DOCUMENTS
--------------------------------------------------------------------------------

CREATE TABLE IF NOT EXISTS builtin_knowledge_documents (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    artifact_id UUID NOT NULL REFERENCES builtin_knowledge_artifacts(id) ON DELETE CASCADE,
    source_path TEXT NOT NULL,
    source_type TEXT NOT NULL DEFAULT 'doc',
    title TEXT NOT NULL,
    locale TEXT,
    checksum TEXT NOT NULL,
    metadata JSONB NOT NULL DEFAULT '{}'::jsonb,
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    UNIQUE (artifact_id, source_path)
);

CREATE INDEX IF NOT EXISTS idx_builtin_knowledge_documents_artifact_id
ON builtin_knowledge_documents(artifact_id);

CREATE INDEX IF NOT EXISTS idx_builtin_knowledge_documents_locale
ON builtin_knowledge_documents(locale);

--------------------------------------------------------------------------------
-- CHUNKS
--------------------------------------------------------------------------------

CREATE TABLE IF NOT EXISTS builtin_knowledge_chunks (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    document_id UUID NOT NULL REFERENCES builtin_knowledge_documents(id) ON DELETE CASCADE,
    chunk_order INTEGER NOT NULL,
    chunk_text TEXT NOT NULL,
    content_hash TEXT NOT NULL,
    metadata JSONB NOT NULL DEFAULT '{}'::jsonb,
    search_vector tsvector,
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    UNIQUE (document_id, chunk_order)
);

CREATE INDEX IF NOT EXISTS idx_builtin_knowledge_chunks_document_id
ON builtin_knowledge_chunks(document_id);

CREATE INDEX IF NOT EXISTS idx_builtin_knowledge_chunks_search_vector
ON builtin_knowledge_chunks
USING GIN(search_vector);

CREATE OR REPLACE FUNCTION builtin_knowledge_chunks_search_vector_update()
RETURNS trigger
AS $$
BEGIN
    NEW.search_vector := to_tsvector('simple', COALESCE(NEW.chunk_text, ''));
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

DROP TRIGGER IF EXISTS trg_builtin_knowledge_chunks_search_vector_update
ON builtin_knowledge_chunks;

CREATE TRIGGER trg_builtin_knowledge_chunks_search_vector_update
BEFORE INSERT OR UPDATE OF chunk_text
ON builtin_knowledge_chunks
FOR EACH ROW
EXECUTE FUNCTION builtin_knowledge_chunks_search_vector_update();

UPDATE builtin_knowledge_chunks
SET search_vector = to_tsvector('simple', COALESCE(chunk_text, ''))
WHERE search_vector IS NULL;

--------------------------------------------------------------------------------
-- OPTIONAL EMBEDDINGS
--------------------------------------------------------------------------------

CREATE TABLE IF NOT EXISTS builtin_knowledge_embeddings (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    chunk_id UUID NOT NULL UNIQUE REFERENCES builtin_knowledge_chunks(id) ON DELETE CASCADE,
    embedding vector(1024) NOT NULL,
    embedding_provider TEXT NOT NULL,
    embedding_model TEXT NOT NULL,
    chunking_version TEXT DEFAULT 'v1',
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE INDEX IF NOT EXISTS idx_builtin_knowledge_embeddings_hnsw
ON builtin_knowledge_embeddings
USING hnsw (embedding vector_cosine_ops);

CREATE INDEX IF NOT EXISTS idx_builtin_knowledge_embeddings_chunk_id
ON builtin_knowledge_embeddings(chunk_id);

--------------------------------------------------------------------------------
-- BASE SEARCH FUNCTION
--------------------------------------------------------------------------------

CREATE OR REPLACE FUNCTION search_builtin_knowledge(
    query_text TEXT,
    max_results INTEGER DEFAULT 10
)
RETURNS TABLE (
    artifact_version TEXT,
    source_path TEXT,
    source_type TEXT,
    title TEXT,
    locale TEXT,
    chunk_id UUID,
    chunk_text TEXT,
    text_rank REAL
)
AS $$
    SELECT
        a.artifact_version,
        d.source_path,
        d.source_type,
        d.title,
        d.locale,
        c.id AS chunk_id,
        c.chunk_text,
        ts_rank(c.search_vector, plainto_tsquery('simple', query_text)) AS text_rank
    FROM builtin_knowledge_chunks c
    JOIN builtin_knowledge_documents d ON d.id = c.document_id
    JOIN builtin_knowledge_artifacts a ON a.id = d.artifact_id
    WHERE c.search_vector @@ plainto_tsquery('simple', query_text)
    ORDER BY text_rank DESC, c.created_at DESC
    LIMIT GREATEST(max_results, 1);
$$ LANGUAGE SQL STABLE;
