-- Down migration to restore query functionality
-- This recreates all query-related tables, views, and functions

-- Drop the simplified fullActiveCollectors view
DROP VIEW IF EXISTS fullActiveCollectors;

-- Recreate query type enum
CREATE TYPE queryType AS ENUM ('context_full', 'json_extractor');

-- Recreate queries table
CREATE TABLE queries (
    queryId uuid primary key DEFAULT uuid_generate_v7(),
    queryType queryType not null
);

-- Recreate queryVersions table
CREATE TABLE queryVersions (
    queryId uuid not null,
    versionId int not null,
    addedAt timestamp not null default current_timestamp,
    primary key (versionId, queryId),
    foreign key (queryId) references queries(queryId)
);

-- Recreate version number function and trigger
CREATE OR REPLACE FUNCTION setQueryVersionNumber()
RETURNS TRIGGER AS $$
BEGIN
    SELECT COALESCE(MAX(versionId), 0) + 1
    INTO NEW.versionId
    FROM queryVersions
    WHERE queryId = NEW.queryId;

    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER setQueryVersionNumberTrigger
BEFORE INSERT ON queryVersions
FOR EACH ROW
EXECUTE FUNCTION setQueryVersionNumber();

-- Recreate queryActiveVersions table
CREATE TABLE queryActiveVersions (
    activeVersionEntryId uuid primary key DEFAULT uuid_generate_v7(),
    queryId uuid not null,
    versionId int not null,
    foreign key (queryId, versionId) references queryVersions(queryId, versionId)
);

-- Recreate requiredQueries table
CREATE TABLE requiredQueries (
    requiredQueryEntryId uuid primary key DEFAULT uuid_generate_v7(),
    queryId uuid not null,
    requiredQueryId uuid not null,
    addedVersion int not null,
    removedVersion int,
    foreign key (queryId) references queries(queryId),
    foreign key (requiredQueryId) references queries(queryId),
    foreign key (queryId, addedVersion) references queryVersions(queryId, versionId),
    foreign key (queryId, removedVersion) references queryVersions(queryId, versionId),
    unique (queryId, requiredQueryId, removedVersion)
);

-- Recreate queryConfigs table
CREATE TABLE queryConfigs (
    configId uuid primary key DEFAULT uuid_generate_v7(),
    queryId uuid not null,
    config jsonb not null,
    addedVersion int not null,
    removedVersion int,
    foreign key (queryId) references queries(queryId),
    foreign key (queryId, addedVersion) references queryVersions(queryId, versionId),
    foreign key (queryId, removedVersion) references queryVersions(queryId, versionId),
    unique (queryId, removedVersion)
);

-- Recreate removeQueryConfig function and trigger
CREATE OR REPLACE FUNCTION removeQueryConfig()
RETURNS TRIGGER AS $$
BEGIN
    UPDATE queryConfigs
        SET removedVersion = NEW.addedVersion
        WHERE queryId = NEW.queryId and removedVersion is null;

    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER removeQueryConfigTrigger
BEFORE INSERT ON queryConfigs
FOR EACH ROW
EXECUTE FUNCTION removeQueryConfig();

-- Recreate collectorQueries table
CREATE TABLE collectorQueries (
    id uuid primary key DEFAULT uuid_generate_v7(),
    clientId varchar(255) not null,
    name varchar(255) not null,
    queryId uuid not null,
    addedVersion int not null,
    removedVersion int,
    foreign key (queryId) references queries(queryId),
    foreign key (clientId) references clients(clientId),
    foreign key (clientId, addedVersion) references collectorVersions(clientId, id),
    foreign key (clientId, removedVersion) references collectorVersions(clientId, id),
    unique (clientId, name, removedVersion)
);

-- Recreate results table
CREATE TABLE results (
    id uuid primary key DEFAULT uuid_generate_v7(),
    textEntryId uuid not null,
    queryId uuid not null,
    value TEXT not null,
    queryVersion int not null,
    foreign key (queryId) references queries(queryId),
    foreign key (textEntryId) references documentTextExtractions(id),
    foreign key (queryId, queryVersion) references queryVersions(queryId, versionId)
);

-- Recreate resultDependencies table
CREATE TABLE resultDependencies (
    resultId uuid not null,
    requiredResultId uuid not null,
    foreign key (resultId) references results(id),
    foreign key (requiredResultId) references results(id),
    CONSTRAINT result_not_self_dependent CHECK (resultId != requiredResultId)
);

-- Recreate query views
CREATE VIEW queryCurrentActiveVersions as
SELECT DISTINCT
        q.queryId,
        coalesce(
            (FIRST_VALUE(av.versionId) OVER (PARTITION BY q.queryId ORDER BY av.activeVersionEntryId DESC)),
            0
        )::int as activeVersion
    FROM queries AS q
    LEFT JOIN queryActiveVersions as av on av.queryId = q.queryId;

CREATE VIEW queryLatestVersions as
    SELECT
    q.queryId,
    coalesce(max(v.versionId), 0)::int as latestVersion
    FROM queries AS q
    LEFT JOIN queryVersions as v on v.queryId = q.queryId
        GROUP BY q.queryId;

CREATE VIEW queryCurrentConfigs as
    SELECT av.queryId, c.config
    FROM queryCurrentActiveVersions as av
    LEFT JOIN queryConfigs AS c ON av.queryId = c.queryId
        and isInVersion(av.activeVersion, c.addedVersion, c.removedVersion);

CREATE VIEW queryCurrentRequiredIds as
    SELECT DISTINCT av.queryId, r.requiredQueryId
    FROM queryCurrentActiveVersions as av
    LEFT JOIN requiredQueries AS r ON av.queryId = r.queryId
        and isInVersion(av.activeVersion, r.addedVersion, r.removedVersion);

CREATE VIEW queryCurrentRequiredIdsAGG as
    SELECT queryId,
    coalesce(
        ARRAY_AGG(DISTINCT requiredQueryId)
        FILTER (WHERE requiredQueryId != '00000000-0000-0000-0000-000000000000')::uuid[],
        array[]::uuid[]
    )::uuid[] as requiredIds
    FROM queryCurrentRequiredIds
    GROUP BY queryId;

CREATE VIEW fullActiveQueries AS
SELECT DISTINCT q.queryId, q.queryType, av.activeVersion, lv.latestVersion, c.config, r.requiredIds
    FROM queries AS q
    JOIN queryCurrentActiveVersions as av on q.queryId = av.queryId
    JOIN queryLatestVersions as lv on lv.queryId = q.queryId
    JOIN queryCurrentConfigs AS c ON q.queryId = c.queryId
    JOIN queryCurrentRequiredIdsAGG AS r ON q.queryId = r.queryId;

CREATE VIEW queryActiveDependencies AS
WITH RECURSIVE queryActiveDependencies(queryId, requiredQueryId, path, cycle) AS (
        SELECT
            queryId,
            requiredQueryId,
            ARRAY[queryId, requiredQueryId]::uuid[] AS path,
            false AS cycle
        FROM queryCurrentRequiredIds

        UNION ALL

        SELECT
            q.queryId,
            qd.requiredQueryId,
            path || qd.requiredQueryId,
            qd.requiredQueryId = ANY(path) AS cycle
        FROM queryCurrentRequiredIds as q
        JOIN queryActiveDependencies as qd ON q.queryId = qd.requiredQueryId
        WHERE NOT qd.cycle
    )
    SELECT DISTINCT queryId as id, requiredQueryId
    FROM queryActiveDependencies
    WHERE NOT cycle;

-- Recreate collector views that depend on queries
CREATE VIEW currentCollectorQueries as
SELECT DISTINCT
        av.clientId,
        q.name,
        q.queryId
    FROM collectorCurrentActiveVersions as av
    LEFT JOIN collectorQueries AS q ON av.clientId = q.clientId
        and isInVersion(av.activeVersion, q.addedVersion, q.removedVersion);

CREATE VIEW currentCollectorQueriesJSONAGG as
SELECT DISTINCT
        clientId,
        jsonb_object_agg(name, queryId) FILTER (WHERE name is not null) AS fields
    FROM currentCollectorQueries
    GROUP BY clientId;

CREATE VIEW fullActiveCollectors AS
    SELECT DISTINCT av.clientId,
    ccv.minCleanVersion, ctv.minTextVersion,
    av.activeVersion, lv.latestVersion,
    q.fields
    FROM collectorCurrentActiveVersions as av
    JOIN collectorLatestVersions as lv on lv.clientId = av.clientId
    JOIN currentCollectorMinCleanVersions AS ccv ON av.clientId = ccv.clientId
    JOIN currentCollectorMinTextVersions AS ctv ON av.clientId = ctv.clientId
    JOIN currentCollectorQueriesJSONAGG AS q ON av.clientId = q.clientId;

CREATE VIEW collectorQueryDependencyTree AS
    WITH RECURSIVE collectorQueryDependencyTree AS (
        SELECT cq.clientId, cq.queryId, ri.requiredIds
        FROM currentCollectorQueries as cq
        JOIN queryCurrentRequiredIdsAGG as ri on cq.queryId = ri.queryId

        UNION ALL

        SELECT acq.clientId, q.queryId, q.requiredIds
        FROM queryCurrentRequiredIdsAGG as q
        JOIN collectorQueryDependencyTree as acq on q.queryId = ANY(acq.requiredIds)
    )
    SELECT DISTINCT ct.clientId, ct.queryId, q.queryType, av.activeVersion as queryVersion, ct.requiredIds
        FROM collectorQueryDependencyTree as ct
        JOIN queryCurrentActiveVersions as av on ct.queryId = av.queryId
        JOIN queries as q on q.queryId = ct.queryId;

CREATE OR REPLACE FUNCTION collectorQueryDependencyTreeByClient(
    _clientId varchar(255)
)
RETURNS TABLE (
    clientId varchar(255),
    queryId uuid,
    queryType queryType,
    queryVersion int,
    requiredIds uuid[]
) AS $$
BEGIN
    RETURN QUERY
    WITH clientQueries as (
        SELECT q.clientId, q.queryId
        FROM currentCollectorQueries as q
        WHERE q.clientId = _clientId
    ),
    dependencyTree as (
        WITH RECURSIVE collectorQueryDependencyTree AS (
            SELECT cq.clientId, cq.queryId, ri.requiredIds
            FROM clientQueries as cq
            JOIN queryCurrentRequiredIdsAGG as ri on cq.queryId = ri.queryId

            UNION ALL

            SELECT acq.clientId, q.queryId, q.requiredIds
            FROM queryCurrentRequiredIdsAGG as q
            JOIN collectorQueryDependencyTree as acq on q.queryId = ANY(acq.requiredIds)
        )
        SELECT DISTINCT ct.clientId, ct.queryId, q.queryType, av.activeVersion as queryVersion, ct.requiredIds
            FROM collectorQueryDependencyTree as ct
            JOIN queryCurrentActiveVersions as av on ct.queryId = av.queryId
            JOIN queries as q on q.queryId = ct.queryId
    )
    SELECT t.clientId, t.queryId, t.queryType, t.queryVersion, t.requiredIds
        FROM dependencyTree as t
    WHERE t.clientID is not null;
END;
$$ LANGUAGE plpgsql;
