import crypto from "node:crypto";
import { transitionEvidenceToTransitionedPayload } from "../task-state-events/event-payloads.js";
import { TASK_STATE_EVENT_ENVELOPE_SCHEMA_VERSION } from "../task-state-events/types.js";
import { taskVersionFromStore } from "./task-state-canonical-authority.js";
import { readRemoteTaskVersionMap } from "../task-state-git/remote-projection-versions.js";
import { resolveTaskStateGitRef } from "../task-state-git/git-io.js";
import { TASK_STATE_GIT_BRANCH } from "../task-state-git/constants.js";
const TASK_UPDATED_VALUE_FIELDS = [
    "title",
    "type",
    "status",
    "priority",
    "summary",
    "description",
    "risk",
    "approach",
    "dependsOn",
    "unblocks",
    "technicalScope",
    "acceptanceCriteria",
    "features",
    "ownership",
    "phase",
    "phaseKey",
    "metadata"
];
const TASK_RICH_CREATE_UPDATED_VALUE_FIELDS = TASK_UPDATED_VALUE_FIELDS.filter((field) => field !== "title" && field !== "type" && field !== "status");
function setTaskUpdatedValue(values, task, field, includeClears) {
    const value = task[field];
    if (field === "phase" || field === "phaseKey") {
        if (value !== undefined) {
            values[field] = String(value);
        }
        else if (includeClears) {
            values[field] = null;
        }
        return;
    }
    if (value !== undefined) {
        values[field] = value;
    }
}
function taskUpdatedValuesFromFields(task, fields, options) {
    const values = {};
    for (const field of fields) {
        setTaskUpdatedValue(values, task, field, options?.includeClears === true);
    }
    return Object.keys(values).length > 0 ? values : undefined;
}
export function taskUpdatedValuesForChangedFields(task, changedFields) {
    const fields = TASK_UPDATED_VALUE_FIELDS.filter((field) => changedFields.includes(field));
    return taskUpdatedValuesFromFields(task, fields, { includeClears: true });
}
export function taskUpdatedValuesForRichCreate(task) {
    return taskUpdatedValuesFromFields(task, TASK_RICH_CREATE_UPDATED_VALUE_FIELDS);
}
function baseActor(ctx) {
    return { id: ctx.actorId?.trim() || "workspace-kit", source: "system" };
}
function draftEnvelope(kind, payload, ctx, expectedTaskVersion) {
    const event = {
        schemaVersion: TASK_STATE_EVENT_ENVELOPE_SCHEMA_VERSION,
        eventId: `evt-${crypto.randomUUID()}`,
        sequence: 0,
        parentEventId: null,
        recordedAt: new Date().toISOString(),
        actor: baseActor(ctx),
        command: {
            name: ctx.commandName,
            moduleId: ctx.moduleId ?? "task-engine",
            invocationId: ctx.invocationId
        },
        kind,
        payload
    };
    if (ctx.clientMutationId?.trim()) {
        event.clientMutationId = ctx.clientMutationId.trim();
    }
    if (ctx.phaseKey?.trim() || ctx.gitHeadSha?.trim()) {
        event.workspace = {
            ...(ctx.gitHeadSha ? { gitHeadSha: ctx.gitHeadSha } : {}),
            ...(ctx.phaseKey ? { phaseKey: ctx.phaseKey } : {})
        };
    }
    if (expectedTaskVersion !== undefined && Number.isFinite(expectedTaskVersion)) {
        event.expectedTaskVersion =
            expectedTaskVersion;
    }
    return event;
}
function resolveExpectedVersion(taskId, store, workspacePath) {
    if (workspacePath) {
        const resolved = resolveTaskStateGitRef(workspacePath, TASK_STATE_GIT_BRANCH);
        if (!("missing" in resolved)) {
            const remote = readRemoteTaskVersionMap(workspacePath, resolved.ref, resolved.tipSha);
            const rv = remote.get(taskId);
            if (rv !== undefined) {
                return rv;
            }
        }
    }
    const version = taskVersionFromStore(store, taskId);
    return version > 0 ? version : undefined;
}
export function draftTransitionedEvent(evidence, ctx, store, workspacePath) {
    const payload = transitionEvidenceToTransitionedPayload(evidence);
    const version = resolveExpectedVersion(payload.taskId, store, workspacePath);
    return draftEnvelope("task.transitioned", payload, ctx, version);
}
export function draftCreatedEvent(task, ctx) {
    const payload = {
        taskId: task.id,
        initialStatus: task.status,
        title: task.title,
        type: task.type
    };
    return draftEnvelope("task.created", payload, ctx);
}
export function draftCreatedTaskEvents(task, ctx) {
    const created = draftCreatedEvent(task, ctx);
    const values = taskUpdatedValuesForRichCreate(task);
    if (!values) {
        return [created];
    }
    const changedFields = Object.keys(values);
    const payload = {
        taskId: task.id,
        changedFields,
        values
    };
    return [created, draftEnvelope("task.updated", payload, ctx, 1)];
}
export function draftUpdatedEvent(taskId, changedFields, store, ctx, values, workspacePath) {
    const version = resolveExpectedVersion(taskId, store, workspacePath);
    const payload = {
        taskId,
        changedFields,
        ...(values ? { values } : {})
    };
    return draftEnvelope("task.updated", payload, ctx, version);
}
export function draftEventsFromTransitionResult(input) {
    const events = [draftTransitionedEvent(input.primary, input.ctx, input.store, input.workspacePath)];
    for (const evidence of input.autoUnblocked) {
        events.push(draftTransitionedEvent(evidence, { ...input.ctx, commandName: "run-transition" }, input.store, input.workspacePath));
    }
    return events;
}
export function mutationEvidenceToDraftEvent(mutation, task, store, ctx) {
    if (mutation.mutationType === "create-task" || mutation.mutationType === "create-task-from-plan") {
        if (!task) {
            return null;
        }
        return draftCreatedEvent(task, ctx);
    }
    if (mutation.mutationType === "update-task") {
        const changed = mutation.details && typeof mutation.details === "object" && Array.isArray(mutation.details.changedFields)
            ? (mutation.details.changedFields)
            : ["metadata"];
        return draftUpdatedEvent(mutation.taskId, changed, store, ctx);
    }
    return null;
}
