-- PR Insights queries for the /agents analytics dashboard.
-- These aggregate data from chat_diff_statuses (PR metadata) joined
-- with chats and chat_messages (cost) to power the PR Insights view.
--
-- Cost is computed per PR by summing the PR-linked chat's own cost plus
-- the costs of any direct children (subagents) it spawned that do NOT
-- have their own PR association. If a child chat has its own
-- chat_diff_statuses entry (with a non-NULL pull_request_state), its
-- cost is attributed to that child's PR instead — preventing
-- double-counting when sibling chats create different PRs.
-- Subagent trees are at most 2 levels deep (enforced by the
-- application layer). PR metadata (state, additions, deletions)
-- comes from the most recent chat via DISTINCT ON so that each PR
-- is counted exactly once.

-- name: GetPRInsightsSummary :one
-- Returns aggregate PR metrics for the given date range.
-- The handler calls this twice (current + previous period) for trends.
-- Uses two CTEs: pr_costs sums cost for the PR-linked chat and its
-- direct children (that lack their own PR), and deduped picks one row
-- per PR for state/additions/deletions.
WITH pr_costs AS (
    SELECT
        prc.pr_key,
        COALESCE(SUM(cc.cost_micros), 0) AS cost_micros
    FROM (
        -- For each PR, include the chat that references it plus any
        -- direct children (subagents) that do not have their own PR.
        SELECT DISTINCT
            COALESCE(NULLIF(cds.url, ''), c.id::text) AS pr_key,
            related.id AS chat_id
        FROM chat_diff_statuses cds
        JOIN chats c ON c.id = cds.chat_id
        JOIN chats related
          ON related.id = c.id
          OR (related.parent_chat_id = c.id
              AND NOT EXISTS (
                  SELECT 1 FROM chat_diff_statuses cds2
                  WHERE cds2.chat_id = related.id
                    AND cds2.pull_request_state IS NOT NULL
              ))
        WHERE cds.pull_request_state IS NOT NULL
          AND c.created_at >= @start_date::timestamptz
          AND c.created_at < @end_date::timestamptz
          AND (sqlc.narg('owner_id')::uuid IS NULL OR c.owner_id = sqlc.narg('owner_id')::uuid)
    ) prc
    LEFT JOIN LATERAL (
        SELECT COALESCE(SUM(cm.total_cost_micros), 0) AS cost_micros
        FROM chat_messages cm
        WHERE cm.chat_id = prc.chat_id
          AND cm.total_cost_micros IS NOT NULL
    ) cc ON TRUE
    GROUP BY prc.pr_key
),
deduped AS (
    SELECT DISTINCT ON (COALESCE(NULLIF(cds.url, ''), c.id::text))
        COALESCE(NULLIF(cds.url, ''), c.id::text) AS pr_key,
        cds.pull_request_state,
        cds.additions,
        cds.deletions
    FROM chat_diff_statuses cds
    JOIN chats c ON c.id = cds.chat_id
    WHERE cds.pull_request_state IS NOT NULL
      AND c.created_at >= @start_date::timestamptz
      AND c.created_at < @end_date::timestamptz
      AND (sqlc.narg('owner_id')::uuid IS NULL OR c.owner_id = sqlc.narg('owner_id')::uuid)
    ORDER BY COALESCE(NULLIF(cds.url, ''), c.id::text), c.created_at DESC, c.id DESC
)
SELECT
    COUNT(*)::bigint AS total_prs_created,
    COUNT(*) FILTER (WHERE d.pull_request_state = 'merged')::bigint AS total_prs_merged,
    COUNT(*) FILTER (WHERE d.pull_request_state = 'closed')::bigint AS total_prs_closed,
    COALESCE(SUM(d.additions), 0)::bigint AS total_additions,
    COALESCE(SUM(d.deletions), 0)::bigint AS total_deletions,
    COALESCE(SUM(pc.cost_micros), 0)::bigint AS total_cost_micros,
    COALESCE(SUM(pc.cost_micros) FILTER (WHERE d.pull_request_state = 'merged'), 0)::bigint AS merged_cost_micros
FROM deduped d
JOIN pr_costs pc ON pc.pr_key = d.pr_key;

-- name: GetPRInsightsTimeSeries :many
-- Returns daily PR counts grouped by state for the chart.
-- Uses a CTE to deduplicate by PR URL so that multiple chats referencing
-- the same pull request are only counted once (keeping the most recent chat).
WITH deduped AS (
    SELECT DISTINCT ON (COALESCE(NULLIF(cds.url, ''), c.id::text))
        cds.pull_request_state,
        c.created_at
    FROM chat_diff_statuses cds
    JOIN chats c ON c.id = cds.chat_id
    WHERE cds.pull_request_state IS NOT NULL
      AND c.created_at >= @start_date::timestamptz
      AND c.created_at < @end_date::timestamptz
      AND (sqlc.narg('owner_id')::uuid IS NULL OR c.owner_id = sqlc.narg('owner_id')::uuid)
    ORDER BY COALESCE(NULLIF(cds.url, ''), c.id::text), c.created_at DESC, c.id DESC
)
SELECT
    date_trunc('day', created_at)::timestamptz AS date,
    COUNT(*)::bigint AS prs_created,
    COUNT(*) FILTER (WHERE pull_request_state = 'merged')::bigint AS prs_merged,
    COUNT(*) FILTER (WHERE pull_request_state = 'closed')::bigint AS prs_closed
FROM deduped
GROUP BY date_trunc('day', created_at)
ORDER BY date_trunc('day', created_at);

-- name: GetPRInsightsPerModel :many
-- Returns PR metrics grouped by the model used for each chat.
-- Uses two CTEs: pr_costs sums cost for the PR-linked chat and its
-- direct children (that lack their own PR), and deduped picks one row
-- per PR for state/additions/deletions/model (model comes from the
-- most recent chat).
WITH pr_costs AS (
    SELECT
        prc.pr_key,
        COALESCE(SUM(cc.cost_micros), 0) AS cost_micros
    FROM (
        SELECT DISTINCT
            COALESCE(NULLIF(cds.url, ''), c.id::text) AS pr_key,
            related.id AS chat_id
        FROM chat_diff_statuses cds
        JOIN chats c ON c.id = cds.chat_id
        JOIN chats related
          ON related.id = c.id
          OR (related.parent_chat_id = c.id
              AND NOT EXISTS (
                  SELECT 1 FROM chat_diff_statuses cds2
                  WHERE cds2.chat_id = related.id
                    AND cds2.pull_request_state IS NOT NULL
              ))
        WHERE cds.pull_request_state IS NOT NULL
          AND c.created_at >= @start_date::timestamptz
          AND c.created_at < @end_date::timestamptz
          AND (sqlc.narg('owner_id')::uuid IS NULL OR c.owner_id = sqlc.narg('owner_id')::uuid)
    ) prc
    LEFT JOIN LATERAL (
        SELECT COALESCE(SUM(cm.total_cost_micros), 0) AS cost_micros
        FROM chat_messages cm
        WHERE cm.chat_id = prc.chat_id
          AND cm.total_cost_micros IS NOT NULL
    ) cc ON TRUE
    GROUP BY prc.pr_key
),
deduped AS (
    SELECT DISTINCT ON (COALESCE(NULLIF(cds.url, ''), c.id::text))
        COALESCE(NULLIF(cds.url, ''), c.id::text) AS pr_key,
        cds.pull_request_state,
        cds.additions,
        cds.deletions,
        cmc.id AS model_config_id,
        cmc.display_name,
        cmc.model,
        cmc.provider
    FROM chat_diff_statuses cds
    JOIN chats c ON c.id = cds.chat_id
    LEFT JOIN chat_model_configs cmc ON cmc.id = c.last_model_config_id
    WHERE cds.pull_request_state IS NOT NULL
      AND c.created_at >= @start_date::timestamptz
      AND c.created_at < @end_date::timestamptz
      AND (sqlc.narg('owner_id')::uuid IS NULL OR c.owner_id = sqlc.narg('owner_id')::uuid)
    ORDER BY COALESCE(NULLIF(cds.url, ''), c.id::text), c.created_at DESC, c.id DESC
)
SELECT
    d.model_config_id,
    COALESCE(NULLIF(d.display_name, ''), NULLIF(d.model, ''), 'Unknown')::text AS display_name,
    COALESCE(d.provider, 'unknown')::text AS provider,
    COUNT(*)::bigint AS total_prs,
    COUNT(*) FILTER (WHERE d.pull_request_state = 'merged')::bigint AS merged_prs,
    COALESCE(SUM(d.additions), 0)::bigint AS total_additions,
    COALESCE(SUM(d.deletions), 0)::bigint AS total_deletions,
    COALESCE(SUM(pc.cost_micros), 0)::bigint AS total_cost_micros,
    COALESCE(SUM(pc.cost_micros) FILTER (WHERE d.pull_request_state = 'merged'), 0)::bigint AS merged_cost_micros
FROM deduped d
JOIN pr_costs pc ON pc.pr_key = d.pr_key
GROUP BY d.model_config_id, d.display_name, d.model, d.provider
ORDER BY total_prs DESC;

-- name: GetPRInsightsPullRequests :many
-- Returns all individual PR rows with cost for the selected time range.
-- Uses two CTEs: pr_costs sums cost for the PR-linked chat and its
-- direct children (that lack their own PR), and deduped picks one row
-- per PR for metadata. A safety-cap LIMIT guards against unexpectedly
-- large result sets from direct API callers.
WITH pr_costs AS (
    SELECT
        prc.pr_key,
        COALESCE(SUM(cc.cost_micros), 0) AS cost_micros
    FROM (
        SELECT DISTINCT
            COALESCE(NULLIF(cds.url, ''), c.id::text) AS pr_key,
            related.id AS chat_id
        FROM chat_diff_statuses cds
        JOIN chats c ON c.id = cds.chat_id
        JOIN chats related
          ON related.id = c.id
          OR (related.parent_chat_id = c.id
              AND NOT EXISTS (
                  SELECT 1 FROM chat_diff_statuses cds2
                  WHERE cds2.chat_id = related.id
                    AND cds2.pull_request_state IS NOT NULL
              ))
        WHERE cds.pull_request_state IS NOT NULL
          AND c.created_at >= @start_date::timestamptz
          AND c.created_at < @end_date::timestamptz
          AND (sqlc.narg('owner_id')::uuid IS NULL OR c.owner_id = sqlc.narg('owner_id')::uuid)
    ) prc
    LEFT JOIN LATERAL (
        SELECT COALESCE(SUM(cm.total_cost_micros), 0) AS cost_micros
        FROM chat_messages cm
        WHERE cm.chat_id = prc.chat_id
          AND cm.total_cost_micros IS NOT NULL
    ) cc ON TRUE
    GROUP BY prc.pr_key
),
deduped AS (
    SELECT DISTINCT ON (COALESCE(NULLIF(cds.url, ''), c.id::text))
        COALESCE(NULLIF(cds.url, ''), c.id::text) AS pr_key,
        c.id AS chat_id,
        cds.pull_request_title AS pr_title,
        cds.url AS pr_url,
        cds.pr_number,
        cds.pull_request_state AS state,
        cds.pull_request_draft AS draft,
        cds.additions,
        cds.deletions,
        cds.changed_files,
        cds.commits,
        cds.approved,
        cds.changes_requested,
        cds.reviewer_count,
        cds.author_login,
        cds.author_avatar_url,
        COALESCE(cds.base_branch, '')::text AS base_branch,
        COALESCE(NULLIF(cmc.display_name, ''), NULLIF(cmc.model, ''), 'Unknown')::text AS model_display_name,
        c.created_at
    FROM chat_diff_statuses cds
    JOIN chats c ON c.id = cds.chat_id
    LEFT JOIN chat_model_configs cmc ON cmc.id = c.last_model_config_id
    WHERE cds.pull_request_state IS NOT NULL
      AND c.created_at >= @start_date::timestamptz
      AND c.created_at < @end_date::timestamptz
      AND (sqlc.narg('owner_id')::uuid IS NULL OR c.owner_id = sqlc.narg('owner_id')::uuid)
    ORDER BY COALESCE(NULLIF(cds.url, ''), c.id::text), c.created_at DESC, c.id DESC
)
SELECT * FROM (
    SELECT
        d.chat_id,
        d.pr_title,
        d.pr_url,
        d.pr_number,
        d.state,
        d.draft,
        d.additions,
        d.deletions,
        d.changed_files,
        d.commits,
        d.approved,
        d.changes_requested,
        d.reviewer_count,
        d.author_login,
        d.author_avatar_url,
        d.base_branch,
        d.model_display_name,
        COALESCE(pc.cost_micros, 0)::bigint AS cost_micros,
        d.created_at
    FROM deduped d
    JOIN pr_costs pc ON pc.pr_key = d.pr_key
) sub
ORDER BY sub.created_at DESC
LIMIT 500;
