import { createDocumentStore } from "./state-backend.js";
const DEFAULT_MAX_JOBS = 1000;
export class UnifiedJobStore {
    maxJobs;
    store;
    constructor(workspace, backend = "json", maxJobs = DEFAULT_MAX_JOBS) {
        this.maxJobs = maxJobs;
        this.store = createDocumentStore({
            workspace,
            backend,
            fileName: "unified-jobs.json",
            sqliteKey: "unified-jobs",
        });
    }
    list(limit = 200) {
        return this.readPayload().jobs
            .sort((left, right) => Date.parse(right.updatedAt) - Date.parse(left.updatedAt))
            .slice(0, Math.max(1, Math.min(this.maxJobs, limit)));
    }
    get(id) {
        return this.readPayload().jobs.find((job) => job.id === id) ?? null;
    }
    upsert(job) {
        const normalized = normalizeJob(job);
        this.store.update((current) => {
            const payload = this.normalizePayload(current);
            const index = payload.jobs.findIndex((candidate) => candidate.id === normalized.id);
            if (index >= 0) {
                payload.jobs[index] = {
                    ...payload.jobs[index],
                    ...normalized,
                };
            }
            else {
                payload.jobs.push(normalized);
            }
            payload.jobs = trimJobs(payload.jobs, this.maxJobs);
            return payload;
        });
        return normalized;
    }
    upsertMany(jobs) {
        if (jobs.length === 0) {
            return this.list();
        }
        const payload = this.store.update((current) => {
            const payload = this.normalizePayload(current);
            const byId = new Map(payload.jobs.map((job) => [job.id, job]));
            for (const job of jobs) {
                const normalized = normalizeJob(job);
                byId.set(normalized.id, {
                    ...byId.get(normalized.id),
                    ...normalized,
                });
            }
            payload.jobs = trimJobs([...byId.values()], this.maxJobs);
            return payload;
        });
        return payload.jobs;
    }
    patch(id, patch) {
        let updated = null;
        this.store.update((current) => {
            const payload = this.normalizePayload(current);
            const index = payload.jobs.findIndex((job) => job.id === id);
            if (index < 0) {
                return payload;
            }
            updated = normalizeJob({
                ...payload.jobs[index],
                ...patch,
                id,
                updatedAt: patch.updatedAt ?? new Date().toISOString(),
            });
            payload.jobs[index] = updated;
            return payload;
        });
        return updated;
    }
    remove(id) {
        let removed = false;
        this.store.update((current) => {
            const payload = this.normalizePayload(current);
            const next = payload.jobs.filter((job) => job.id !== id);
            removed = next.length !== payload.jobs.length;
            payload.jobs = next;
            return payload;
        });
        return removed;
    }
    readPayload() {
        return this.normalizePayload(this.store.read());
    }
    normalizePayload(payload) {
        if (!payload || payload.version !== 1 || !Array.isArray(payload.jobs)) {
            return { version: 1, jobs: [] };
        }
        return {
            version: 1,
            jobs: trimJobs(payload.jobs.filter(isUnifiedJobDto).map(normalizeJob), this.maxJobs),
        };
    }
}
function trimJobs(jobs, maxJobs) {
    return jobs
        .sort((left, right) => Date.parse(right.updatedAt) - Date.parse(left.updatedAt))
        .slice(0, maxJobs);
}
function normalizeJob(job) {
    return {
        ...job,
        startedAt: validDateString(job.startedAt) ?? new Date().toISOString(),
        updatedAt: validDateString(job.updatedAt) ?? new Date().toISOString(),
        finishedAt: validDateString(job.finishedAt),
        canCancel: Boolean(job.canCancel),
        canRetry: Boolean(job.canRetry),
        canReadLog: Boolean(job.canReadLog),
    };
}
function validDateString(value) {
    if (!value) {
        return undefined;
    }
    return Number.isFinite(Date.parse(value)) ? value : undefined;
}
function isUnifiedJobDto(value) {
    if (!value || typeof value !== "object" || Array.isArray(value)) {
        return false;
    }
    const candidate = value;
    return typeof candidate.id === "string" &&
        typeof candidate.kind === "string" &&
        typeof candidate.title === "string" &&
        typeof candidate.status === "string" &&
        typeof candidate.source === "string" &&
        typeof candidate.startedAt === "string" &&
        typeof candidate.updatedAt === "string";
}
