--
-- Records queries
-- All SQL for api/routes/records.js
--

SET search_path TO dataflow, public;

-- ── Read ──────────────────────────────────────────────────────────────────────

CREATE OR REPLACE FUNCTION list_records(
    p_source_name     TEXT,
    p_limit           INT     DEFAULT 100,
    p_offset          INT     DEFAULT 0,
    p_transformed_only BOOLEAN DEFAULT FALSE
)
RETURNS SETOF dataflow.records AS $$
    SELECT * FROM dataflow.records
    WHERE source_name = p_source_name
      AND (NOT p_transformed_only OR transformed IS NOT NULL)
    ORDER BY id DESC
    LIMIT p_limit OFFSET p_offset;
$$ LANGUAGE sql STABLE;

CREATE OR REPLACE FUNCTION get_record(p_id BIGINT)
RETURNS dataflow.records AS $$
    SELECT * FROM dataflow.records WHERE id = p_id;
$$ LANGUAGE sql STABLE;

CREATE OR REPLACE FUNCTION search_records(
    p_source_name TEXT,
    p_query       JSONB,
    p_limit       INT DEFAULT 100
)
RETURNS SETOF dataflow.records AS $$
    SELECT * FROM dataflow.records
    WHERE source_name = p_source_name
      AND (data @> p_query OR transformed @> p_query)
    ORDER BY id DESC
    LIMIT p_limit;
$$ LANGUAGE sql STABLE;

-- ── Overrides ─────────────────────────────────────────────────────────────────

-- Store manual overrides. Overrides stay in their own column — never merged into
-- transformed — so reprocessing rules cannot clobber a manual edit.
DROP FUNCTION IF EXISTS set_record_overrides(INTEGER, JSONB);
CREATE OR REPLACE FUNCTION set_record_overrides(p_id INTEGER, p_overrides JSONB)
RETURNS JSON AS $$
    WITH updated AS (
        UPDATE dataflow.records
        SET overrides = CASE WHEN p_overrides = '{}'::jsonb THEN NULL ELSE p_overrides END
        WHERE id = p_id
        RETURNING *
    )
    SELECT row_to_json(updated) FROM updated;
$$ LANGUAGE sql;

-- Merge overrides into multiple records at once; returns actual updated count
DROP FUNCTION IF EXISTS bulk_set_record_overrides(TEXT, INTEGER[], JSONB);
CREATE OR REPLACE FUNCTION bulk_set_record_overrides(p_source_name TEXT, p_ids INTEGER[], p_overrides JSONB)
RETURNS JSON AS $$
    WITH updated AS (
        UPDATE dataflow.records
        SET overrides = COALESCE(overrides, '{}'::jsonb) || p_overrides
        WHERE id = ANY(p_ids)
          AND source_name = p_source_name
        RETURNING id
    )
    SELECT json_build_object('updated', count(*)) FROM updated;
$$ LANGUAGE sql;

-- Clear overrides; the computed values in transformed are untouched
DROP FUNCTION IF EXISTS clear_record_overrides(INTEGER);
CREATE OR REPLACE FUNCTION clear_record_overrides(p_id INTEGER)
RETURNS JSON AS $$
    WITH updated AS (
        UPDATE dataflow.records
        SET overrides = NULL
        WHERE id = p_id
        RETURNING *
    )
    SELECT row_to_json(updated) FROM updated;
$$ LANGUAGE sql;

-- ── Delete ────────────────────────────────────────────────────────────────────

CREATE OR REPLACE FUNCTION delete_record(p_id BIGINT)
RETURNS TABLE (id BIGINT) AS $$
    DELETE FROM dataflow.records WHERE id = p_id RETURNING id;
$$ LANGUAGE sql;

CREATE OR REPLACE FUNCTION delete_source_records(p_source_name TEXT)
RETURNS TABLE (deleted_count BIGINT) AS $$
    WITH deleted AS (
        DELETE FROM dataflow.records WHERE source_name = p_source_name RETURNING id
    )
    SELECT count(*) AS deleted_count FROM deleted;
$$ LANGUAGE sql;
