-- name: CreateClient :one
INSERT INTO clients (externalId, name) VALUES ($1, $2) RETURNING id;

-- name: GetClient :one
SELECT * FROM fullClients WHERE id = $1;

-- name: GetClientByExternalId :one
SELECT * FROM fullClients WHERE externalId = $1;

-- name: UpdateClient :exec
UPDATE clients SET name = $1 WHERE id = $2;

-- name: AddClientCanSync :exec
INSERT INTO clientCanSync (canSync, clientId) VALUES ($1, $2);

-- name: IsClientSynced :one
WITH
docs AS (
    -- Get all documents for this client
    SELECT id, clientId FROM documents WHERE clientId = $1
),
doc_clean_entries as (
    -- Documents with their current clean entries
    SELECT
        d.id AS document_id,
        d.clientId as client_id,
        cte.id AS clean_entry_id
    FROM
        docs d
        LEFT JOIN currentCleanEntries cte ON cte.documentId = d.id
    WHERE cte.id is null or cte.id is not null and cte.fail is null
),
doc_text_entries AS (
    -- Documents with their current text entries
    SELECT
        d.document_id,
        cte.id AS text_entry_id
    FROM
        doc_clean_entries d
        LEFT JOIN currentTextEntries cte ON cte.cleanEntryId = d.clean_entry_id
),
required_results AS (
    -- All required document-query-version combinations
    SELECT
        d.document_id,
        cqdt.queryId,
        cqdt.queryVersion,
        dte.text_entry_id
    FROM
        doc_clean_entries d
        JOIN collectorQueryDependencyTree cqdt ON cqdt.clientId = d.client_id
        JOIN doc_text_entries dte ON dte.document_id = d.document_id
            and dte.text_entry_id IS NOT NULL
),
existing_results AS (
    -- Valid results that exist
    SELECT
        rr.document_id AS document_id,
        r.queryId,
        r.id AS result_id
    FROM
        results r
        JOIN required_results rr ON
            r.queryId = rr.queryId AND
            r.queryVersion = rr.queryVersion AND
            r.textEntryId = rr.text_entry_id
),
missing_results AS (
    -- Find missing results
    SELECT rr.queryId
    FROM required_results rr
    LEFT JOIN existing_results er on er.queryId = rr.queryId
    WHERE er.result_id is null
),
dependency_check AS (
    -- Check for missing dependencies
    SELECT DISTINCT er.queryId, er.result_id, qcri.queryId, rd.resultId
    FROM existing_results er
    JOIN queryCurrentRequiredIds qcri on qcri.requiredQueryId = er.queryId
    LEFT JOIN resultDependencies rd on rd.requiredResultId = er.result_id
    WHERE rd.resultId is null
)
SELECT (
    -- No documents means client is synced
    NOT EXISTS (SELECT 1 FROM docs)

    OR

    -- Documents with no text entries
    (NOT EXISTS (SELECT 1 FROM doc_text_entries WHERE text_entry_id IS NULL)

    and

    -- Documents with missing results
    NOT EXISTS (SELECT 1 FROM missing_results)

    and

    -- Documents with missing dependencies
    NOT EXISTS (SELECT 1 FROM dependency_check))
)::bool as is_synced;
