CREATE TABLE IF NOT EXISTS doc.doc_embedding_cluster_set (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    code VARCHAR(128) NOT NULL UNIQUE,
    name VARCHAR(255) NOT NULL,
    description TEXT,
    selection_json JSONB NOT NULL,
    active BOOLEAN NOT NULL DEFAULT TRUE,
    created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE IF NOT EXISTS doc.doc_embedding_cluster_run (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    cluster_set_id UUID,
    name VARCHAR(255) NOT NULL,
    status VARCHAR(32) NOT NULL,
    algorithm VARCHAR(64) NOT NULL,
    algorithm_version VARCHAR(64),
    selection_json JSONB NOT NULL,
    parameters_json JSONB NOT NULL,
    embedding_model_id UUID,
    prefix_profile_id UUID,
    document_type VARCHAR(64),
    document_family VARCHAR(64),
    representation_type VARCHAR(64),
    builder_key VARCHAR(255),
    item_count BIGINT,
    cluster_count BIGINT,
    noise_count BIGINT,
    started_at TIMESTAMP WITH TIME ZONE,
    finished_at TIMESTAMP WITH TIME ZONE,
    error_message TEXT,
    created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
    CONSTRAINT fk_doc_cluster_run_set
        FOREIGN KEY (cluster_set_id)
        REFERENCES doc.doc_embedding_cluster_set(id),
    CONSTRAINT fk_doc_cluster_run_model
        FOREIGN KEY (embedding_model_id)
        REFERENCES doc.doc_embedding_model(id),
    CONSTRAINT fk_doc_cluster_run_prefix_profile
        FOREIGN KEY (prefix_profile_id)
        REFERENCES doc.doc_embedding_prefix_profile(id)
);

CREATE INDEX IF NOT EXISTS idx_doc_cluster_run_status
    ON doc.doc_embedding_cluster_run(status);
CREATE INDEX IF NOT EXISTS idx_doc_cluster_run_algorithm
    ON doc.doc_embedding_cluster_run(algorithm);
CREATE INDEX IF NOT EXISTS idx_doc_cluster_run_created_at
    ON doc.doc_embedding_cluster_run(created_at);

CREATE TABLE IF NOT EXISTS doc.doc_embedding_cluster (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    cluster_run_id UUID NOT NULL,
    cluster_label INTEGER NOT NULL,
    display_name VARCHAR(255),
    item_count BIGINT NOT NULL,
    is_noise_cluster BOOLEAN NOT NULL DEFAULT FALSE,
    summary_text TEXT,
    top_terms_json JSONB,
    created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
    CONSTRAINT fk_doc_cluster_cluster_run
        FOREIGN KEY (cluster_run_id)
        REFERENCES doc.doc_embedding_cluster_run(id)
        ON DELETE CASCADE,
    CONSTRAINT uq_doc_cluster_run_label
        UNIQUE (cluster_run_id, cluster_label)
);

CREATE INDEX IF NOT EXISTS idx_doc_cluster_cluster_run
    ON doc.doc_embedding_cluster(cluster_run_id);

CREATE TABLE IF NOT EXISTS doc.doc_embedding_cluster_assignment (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    cluster_run_id UUID NOT NULL,
    cluster_id UUID,
    embedding_id UUID NOT NULL,
    document_id UUID NOT NULL,
    representation_id UUID NOT NULL,
    cluster_label_raw INTEGER NOT NULL,
    membership_score DOUBLE PRECISION,
    distance_to_centroid DOUBLE PRECISION,
    is_noise BOOLEAN NOT NULL DEFAULT FALSE,
    created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
    CONSTRAINT fk_doc_cluster_assignment_run
        FOREIGN KEY (cluster_run_id)
        REFERENCES doc.doc_embedding_cluster_run(id)
        ON DELETE CASCADE,
    CONSTRAINT fk_doc_cluster_assignment_cluster
        FOREIGN KEY (cluster_id)
        REFERENCES doc.doc_embedding_cluster(id)
        ON DELETE CASCADE,
    CONSTRAINT fk_doc_cluster_assignment_embedding
        FOREIGN KEY (embedding_id)
        REFERENCES doc.doc_embedding(id),
    CONSTRAINT uq_doc_cluster_run_embedding
        UNIQUE (cluster_run_id, embedding_id)
);

CREATE INDEX IF NOT EXISTS idx_doc_cluster_assignment_run
    ON doc.doc_embedding_cluster_assignment(cluster_run_id);
CREATE INDEX IF NOT EXISTS idx_doc_cluster_assignment_cluster
    ON doc.doc_embedding_cluster_assignment(cluster_id);
CREATE INDEX IF NOT EXISTS idx_doc_cluster_assignment_document
    ON doc.doc_embedding_cluster_assignment(cluster_run_id, document_id);
CREATE INDEX IF NOT EXISTS idx_doc_cluster_assignment_noise
    ON doc.doc_embedding_cluster_assignment(cluster_run_id, is_noise);
