import { getGitSyncSummary, probeGitWorkspaceState } from "../workspace/git-sync.js";
import { getTaskWorkspacePathInfo } from "../workspace/task-worktree.js";
const WORKSPACE_METADATA_POLL_INTERVAL_MS = 1_000;
function collectTrackedTasks(board) {
    const tracked = [];
    for (const column of board.columns) {
        if (column.id === "backlog" || column.id === "trash") {
            continue;
        }
        for (const card of column.cards) {
            tracked.push({
                taskId: card.id,
                baseRef: card.baseRef,
            });
        }
    }
    return tracked;
}
function areGitSummariesEqual(a, b) {
    if (a === b) {
        return true;
    }
    if (!a || !b) {
        return false;
    }
    return (a.currentBranch === b.currentBranch &&
        a.upstreamBranch === b.upstreamBranch &&
        a.changedFiles === b.changedFiles &&
        a.additions === b.additions &&
        a.deletions === b.deletions &&
        a.aheadCount === b.aheadCount &&
        a.behindCount === b.behindCount);
}
function areTaskMetadataEqual(a, b) {
    return (a.taskId === b.taskId &&
        a.path === b.path &&
        a.exists === b.exists &&
        a.baseRef === b.baseRef &&
        a.branch === b.branch &&
        a.isDetached === b.isDetached &&
        a.headCommit === b.headCommit &&
        a.changedFiles === b.changedFiles &&
        a.additions === b.additions &&
        a.deletions === b.deletions &&
        a.stateVersion === b.stateVersion);
}
function areWorkspaceMetadataEqual(a, b) {
    if (!areGitSummariesEqual(a.homeGitSummary, b.homeGitSummary)) {
        return false;
    }
    if (a.homeGitStateVersion !== b.homeGitStateVersion) {
        return false;
    }
    if (a.taskWorkspaces.length !== b.taskWorkspaces.length) {
        return false;
    }
    for (let index = 0; index < a.taskWorkspaces.length; index += 1) {
        const left = a.taskWorkspaces[index];
        const right = b.taskWorkspaces[index];
        if (!left || !right || !areTaskMetadataEqual(left, right)) {
            return false;
        }
    }
    return true;
}
function createEmptyWorkspaceMetadata() {
    return {
        homeGitSummary: null,
        homeGitStateVersion: 0,
        taskWorkspaces: [],
    };
}
function createWorkspaceEntry(workspacePath) {
    return {
        workspacePath,
        trackedTasks: [],
        subscriberCount: 0,
        pollTimer: null,
        refreshPromise: null,
        homeGit: {
            summary: null,
            stateToken: null,
            stateVersion: 0,
        },
        taskMetadataByTaskId: new Map(),
    };
}
function buildWorkspaceMetadataSnapshot(entry) {
    return {
        homeGitSummary: entry.homeGit.summary,
        homeGitStateVersion: entry.homeGit.stateVersion,
        taskWorkspaces: entry.trackedTasks
            .map((task) => entry.taskMetadataByTaskId.get(task.taskId)?.data ?? null)
            .filter((task) => task !== null),
    };
}
async function loadHomeGitMetadata(entry) {
    try {
        const probe = await probeGitWorkspaceState(entry.workspacePath);
        if (entry.homeGit.stateToken === probe.stateToken) {
            return entry.homeGit;
        }
        const summary = await getGitSyncSummary(entry.workspacePath, { probe });
        return {
            summary,
            stateToken: probe.stateToken,
            stateVersion: Date.now(),
        };
    }
    catch {
        return entry.homeGit;
    }
}
async function loadTaskWorkspaceMetadata(workspacePath, task, current) {
    const pathInfo = await getTaskWorkspacePathInfo({
        cwd: workspacePath,
        taskId: task.taskId,
        baseRef: task.baseRef,
    });
    if (!pathInfo.exists) {
        if (current &&
            current.data.exists === false &&
            current.data.path === pathInfo.path &&
            current.data.baseRef === pathInfo.baseRef) {
            return current;
        }
        return {
            data: {
                taskId: task.taskId,
                path: pathInfo.path,
                exists: false,
                baseRef: pathInfo.baseRef,
                branch: null,
                isDetached: false,
                headCommit: null,
                changedFiles: null,
                additions: null,
                deletions: null,
                stateVersion: Date.now(),
            },
            stateToken: null,
        };
    }
    try {
        const probe = await probeGitWorkspaceState(pathInfo.path);
        if (current &&
            current.stateToken === probe.stateToken &&
            current.data.path === pathInfo.path &&
            current.data.baseRef === pathInfo.baseRef) {
            return current;
        }
        const summary = await getGitSyncSummary(pathInfo.path, { probe });
        return {
            data: {
                taskId: task.taskId,
                path: pathInfo.path,
                exists: true,
                baseRef: pathInfo.baseRef,
                branch: probe.currentBranch,
                isDetached: probe.headCommit !== null && probe.currentBranch === null,
                headCommit: probe.headCommit,
                changedFiles: summary.changedFiles,
                additions: summary.additions,
                deletions: summary.deletions,
                stateVersion: Date.now(),
            },
            stateToken: probe.stateToken,
        };
    }
    catch {
        if (current) {
            return current;
        }
        return {
            data: {
                taskId: task.taskId,
                path: pathInfo.path,
                exists: true,
                baseRef: pathInfo.baseRef,
                branch: null,
                isDetached: false,
                headCommit: null,
                changedFiles: null,
                additions: null,
                deletions: null,
                stateVersion: Date.now(),
            },
            stateToken: null,
        };
    }
}
export function createWorkspaceMetadataMonitor(deps) {
    const workspaces = new Map();
    const stopWorkspaceTimer = (entry) => {
        if (!entry.pollTimer) {
            return;
        }
        clearInterval(entry.pollTimer);
        entry.pollTimer = null;
    };
    const refreshWorkspace = async (workspaceId) => {
        const entry = workspaces.get(workspaceId);
        if (!entry) {
            return createEmptyWorkspaceMetadata();
        }
        if (entry.refreshPromise) {
            return await entry.refreshPromise;
        }
        entry.refreshPromise = (async () => {
            const previousSnapshot = buildWorkspaceMetadataSnapshot(entry);
            entry.homeGit = await loadHomeGitMetadata(entry);
            const nextTaskEntries = await Promise.all(entry.trackedTasks.map(async (task) => {
                const current = entry.taskMetadataByTaskId.get(task.taskId) ?? null;
                const next = await loadTaskWorkspaceMetadata(entry.workspacePath, task, current);
                return next ? [task.taskId, next] : null;
            }));
            entry.taskMetadataByTaskId = new Map(nextTaskEntries.filter((candidate) => candidate !== null));
            const nextSnapshot = buildWorkspaceMetadataSnapshot(entry);
            if (!areWorkspaceMetadataEqual(previousSnapshot, nextSnapshot)) {
                deps.onMetadataUpdated(workspaceId, nextSnapshot);
            }
            return nextSnapshot;
        })().finally(() => {
            const current = workspaces.get(workspaceId);
            if (current) {
                current.refreshPromise = null;
            }
        });
        return await entry.refreshPromise;
    };
    const updateWorkspaceEntry = (input) => {
        const existing = workspaces.get(input.workspaceId) ?? createWorkspaceEntry(input.workspacePath);
        existing.workspacePath = input.workspacePath;
        existing.trackedTasks = collectTrackedTasks(input.board);
        workspaces.set(input.workspaceId, existing);
        return existing;
    };
    const ensureWorkspaceTimer = (workspaceId, entry) => {
        if (entry.pollTimer) {
            return;
        }
        const timer = setInterval(() => {
            void refreshWorkspace(workspaceId);
        }, WORKSPACE_METADATA_POLL_INTERVAL_MS);
        timer.unref();
        entry.pollTimer = timer;
    };
    return {
        connectWorkspace: async ({ workspaceId, workspacePath, board }) => {
            const entry = updateWorkspaceEntry({ workspaceId, workspacePath, board });
            entry.subscriberCount += 1;
            ensureWorkspaceTimer(workspaceId, entry);
            return await refreshWorkspace(workspaceId);
        },
        updateWorkspaceState: async ({ workspaceId, workspacePath, board }) => {
            const entry = updateWorkspaceEntry({ workspaceId, workspacePath, board });
            if (entry.subscriberCount === 0) {
                return buildWorkspaceMetadataSnapshot(entry);
            }
            return await refreshWorkspace(workspaceId);
        },
        disconnectWorkspace: (workspaceId) => {
            const entry = workspaces.get(workspaceId);
            if (!entry) {
                return;
            }
            entry.subscriberCount = Math.max(0, entry.subscriberCount - 1);
            if (entry.subscriberCount > 0) {
                return;
            }
            stopWorkspaceTimer(entry);
            workspaces.delete(workspaceId);
        },
        disposeWorkspace: (workspaceId) => {
            const entry = workspaces.get(workspaceId);
            if (!entry) {
                return;
            }
            stopWorkspaceTimer(entry);
            workspaces.delete(workspaceId);
        },
        close: () => {
            for (const entry of workspaces.values()) {
                stopWorkspaceTimer(entry);
            }
            workspaces.clear();
        },
    };
}
//# sourceMappingURL=workspace-metadata-monitor.js.map