"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildIssueShowChildIssuesViewModel = buildIssueShowChildIssuesViewModel;
const issue_id_1 = require("../../issues/issue-id");
const child_workflow_state_1 = require("../../run/run-once-cycle/child-workflow-state");
const recurring_child_dependencies_1 = require("../../run/run-once-cycle/recurring-child-dependencies");
const workflow_structure_1 = require("../../run/workflow-structure");
const issue_ref_1 = require("../../workflows/issue-ref");
function buildIssueShowChildIssuesViewModel(input) {
    const dependencyById = new Map(input.dependencies.map((dependency) => [dependency.id, dependency]));
    const controllerSteps = (0, workflow_structure_1.resolveWorkflowChildIssueSteps)(input.workflowState);
    const controllerDependencyIds = new Set();
    const groups = [];
    if (controllerSteps.length > 0) {
        groups.push({
            kind: "controller",
            items: controllerSteps.map((step) => {
                const issueId = (0, issue_ref_1.normalizeWorkflowIssueDisplayRef)(step.childIssueRef);
                if (issueId !== null) {
                    controllerDependencyIds.add(issueId);
                }
                const dependency = issueId === null ? undefined : dependencyById.get(issueId);
                if (dependency !== undefined) {
                    controllerDependencyIds.add(dependency.id);
                }
                return buildControllerChildIssueItem({
                    parentIssue: input.parentIssue,
                    step,
                    dependency: dependency ?? (issueId === null ? null : undefined),
                    depth: input.depth,
                });
            }),
        });
    }
    const generatedDependencies = input.dependencies.filter((dependency) => !controllerDependencyIds.has(dependency.id));
    const recurring = mergeRecurringChildIssues({
        parentDisplayId: input.parentIssue.displayId,
        dependencies: generatedDependencies,
        history: input.recurringHistory.filter((issue) => !controllerDependencyIds.has(issue.id)),
    }).sort(compareChildIssuesByRecentIdDesc);
    const unplanned = generatedDependencies
        .filter((dependency) => isUnplannedChildWorkflowStateForParent({
        workflowState: input.dependencyWorkflowStates.get(dependency.id) ?? null,
        parentDisplayId: input.parentIssue.displayId,
    }))
        .sort(compareSupportDependencies);
    const unplannedIds = new Set(unplanned.map((dependency) => dependency.id));
    const support = generatedDependencies
        .filter((dependency) => !unplannedIds.has(dependency.id) &&
        !isRecurringChildIssueForParent(dependency.title, input.parentIssue.displayId))
        .sort(compareSupportDependencies);
    const followup = (input.followupIssues ?? [])
        .filter((issue) => issue.id !== input.parentIssue.id)
        .sort(compareIssueRecordsByUpdatedAtDesc);
    if (recurring.length > 0) {
        groups.push({
            kind: "recurring",
            items: recurring.map((childIssue) => buildChildIssueItem(childIssue, input.depth)),
        });
    }
    if (unplanned.length > 0) {
        groups.push({
            kind: "unplanned",
            items: unplanned.map((dependency) => buildChildIssueItem(dependency, input.depth)),
        });
    }
    if (followup.length > 0) {
        groups.push({
            kind: "followup",
            items: followup.map((issue) => buildChildIssueItem(issue, input.depth)),
        });
    }
    if (support.length > 0) {
        groups.push({
            kind: "support",
            items: support.map((dependency) => buildChildIssueItem(dependency, input.depth)),
        });
    }
    const limited = limitChildIssueGroups({
        groups,
        limit: input.limitBudget !== undefined
            ? input.limitBudget
            : createChildIssueLimitBudget(input.limit),
    });
    return {
        requested: input.requested,
        groups: limited.groups,
        hiddenCount: limited.hiddenCount,
    };
}
function limitChildIssueGroups(input) {
    if (input.limit === null) {
        return { groups: input.groups.map(cloneChildIssueGroup), hiddenCount: 0 };
    }
    let hiddenCount = 0;
    const groups = [];
    for (const group of input.groups) {
        if (group.kind === "controller") {
            groups.push(cloneChildIssueGroup(group));
            continue;
        }
        const visibleItems = group.items.slice(0, Math.max(0, input.limit.remaining));
        hiddenCount += group.items.length - visibleItems.length;
        input.limit.remaining -= visibleItems.length;
        if (visibleItems.length > 0) {
            groups.push({ kind: group.kind, items: visibleItems });
        }
    }
    return { groups, hiddenCount };
}
function createChildIssueLimitBudget(limit) {
    return limit === null ? null : { remaining: limit };
}
function cloneChildIssueGroup(group) {
    return { kind: group.kind, items: [...group.items] };
}
function isUnplannedChildWorkflowStateForParent(input) {
    return (input.workflowState?.workflowSurface === "unplanned" &&
        input.workflowState.parentLink?.childKey === child_workflow_state_1.UNPLANNED_CHILD_KEY &&
        (0, issue_ref_1.workflowIssueRefsMatch)(input.workflowState.parentLink.parentRef, input.parentDisplayId));
}
function mergeRecurringChildIssues(input) {
    const byId = new Map();
    for (const dependency of input.dependencies) {
        if (isRecurringChildIssueForParent(dependency.title, input.parentDisplayId)) {
            byId.set(dependency.id, dependency);
        }
    }
    for (const issue of input.history) {
        if (!byId.has(issue.id) &&
            isRecurringChildIssueForParent(issue.title, input.parentDisplayId)) {
            byId.set(issue.id, issue);
        }
    }
    return [...byId.values()];
}
function isRecurringChildIssueForParent(title, parentDisplayId) {
    return (0, recurring_child_dependencies_1.matchesRecurringChildIssueForParent)({
        title,
        parentDisplayId,
    });
}
function buildControllerChildIssueItem(input) {
    const issueId = (0, issue_ref_1.normalizeWorkflowIssueDisplayRef)(input.step.childIssueRef);
    const displayId = input.dependency?.displayId ??
        input.step.childIssueRef ??
        input.step.childKey;
    return {
        id: input.dependency?.id ?? issueId,
        displayId,
        title: input.dependency?.title ?? input.step.title,
        url: input.dependency?.url ??
            (issueId === null
                ? null
                : buildSiblingIssueUrl(input.parentIssue, issueId)),
        state: input.dependency !== null && input.dependency !== undefined
            ? resolveChildIssueOpenState(input.dependency.isOpen)
            : issueId === null
                ? "pending"
                : "unknown",
        summary: input.step.result?.resultSummary ?? null,
        ...(input.depth !== undefined ? { depth: input.depth } : {}),
    };
}
function buildChildIssueItem(childIssue, depth) {
    return {
        id: childIssue.id,
        displayId: childIssue.displayId,
        title: childIssue.title,
        url: childIssue.url,
        state: resolveChildIssueOpenState(childIssue.isOpen),
        summary: null,
        ...(depth !== undefined ? { depth } : {}),
    };
}
function resolveChildIssueOpenState(isOpen) {
    return isOpen ? "open" : "closed";
}
function compareSupportDependencies(left, right) {
    if (left.isOpen !== right.isOpen) {
        return left.isOpen ? -1 : 1;
    }
    const updatedComparison = compareOptionalUpdatedAtDesc(left, right);
    if (updatedComparison !== 0) {
        return updatedComparison;
    }
    return compareDependenciesByRecentIdDesc(left, right);
}
function compareChildIssuesByRecentIdDesc(left, right) {
    return compareIssueIdsByRecentDesc(left.id, right.id);
}
function compareDependenciesByRecentIdDesc(left, right) {
    return compareIssueIdsByRecentDesc(left.id, right.id);
}
function compareIssueRecordsByUpdatedAtDesc(left, right) {
    const updatedComparison = right.updatedAt.localeCompare(left.updatedAt);
    if (updatedComparison !== 0) {
        return updatedComparison;
    }
    return compareIssueIdsByRecentDesc(left.id, right.id);
}
function compareOptionalUpdatedAtDesc(left, right) {
    const leftUpdatedAt = left.updatedAt ?? "";
    const rightUpdatedAt = right.updatedAt ?? "";
    if (leftUpdatedAt.length === 0 && rightUpdatedAt.length === 0) {
        return 0;
    }
    return rightUpdatedAt.localeCompare(leftUpdatedAt);
}
function compareIssueIdsByRecentDesc(left, right) {
    const leftId = (0, issue_id_1.parseNumericIssueId)(left);
    const rightId = (0, issue_id_1.parseNumericIssueId)(right);
    if (leftId !== null && rightId !== null && leftId !== rightId) {
        return rightId - leftId;
    }
    return right.localeCompare(left);
}
function buildSiblingIssueUrl(parentIssue, issueId) {
    try {
        const url = new URL(parentIssue.url);
        const segments = url.pathname.split("/");
        const lastSegment = segments.at(-1);
        if (lastSegment !== parentIssue.id) {
            return null;
        }
        segments[segments.length - 1] = issueId;
        url.pathname = segments.join("/");
        url.hash = "";
        return url.toString();
    }
    catch {
        return null;
    }
}
