import type { EventId, OutboxMessageId, ProjectId, TaskId } from "@awp/contracts";
import type { MutationContext } from "@awp/contracts";
import { moveTaskToPosition } from "@awp/domain";
import type { Clock, IdGenerator } from "./ports/runtime.js";
import type { UnitOfWork } from "./ports/repositories.js";
export interface ReorderQueueCommand {
  readonly projectId: ProjectId;
  readonly taskId: TaskId;
  readonly desiredPosition: number;
  readonly currentOrder: readonly TaskId[];
  readonly context: MutationContext;
}
export class ReorderQueueHandler {
  constructor(
    private readonly uow: UnitOfWork,
    private readonly ids: IdGenerator,
    private readonly clock: Clock,
  ) {}
  async execute(command: ReorderQueueCommand): Promise<readonly TaskId[]> {
    return this.uow.transaction(async (tx) => {
      const project = await tx.projects.getById(command.projectId);
      if (!project) throw new Error(`Unknown Project ${command.projectId}`);
      const tasks = await tx.tasks.listByProject(command.projectId);
      const order = moveTaskToPosition(
        command.currentOrder,
        command.taskId,
        command.desiredPosition,
        tasks,
      );
      const now = this.clock.now().toISOString();
      await tx.events.append({
        id: this.ids.next<EventId>(),
        type: "QueueEntryMoved",
        schemaVersion: 1,
        occurredAt: now,
        aggregateType: "Project",
        aggregateId: command.projectId,
        aggregateRevision: project.revision,
        projectId: command.projectId,
        principalId: command.context.authority.principal.id,
        correlationId: command.context.correlationId,
        payload: { taskId: command.taskId, desiredPosition: command.desiredPosition, order },
      });
      await tx.audit.append({
        id: this.ids.next(),
        occurredAt: now,
        principalId: command.context.authority.principal.id,
        action: "queue.move",
        targetType: "Task",
        targetId: command.taskId,
        projectId: command.projectId,
        disposition: "allowed",
        correlationId: command.context.correlationId,
        safeMetadata: { desiredPosition: command.desiredPosition },
      });
      await tx.outbox.append({
        id: this.ids.next<OutboxMessageId>(),
        topic: "QueueEntryMoved",
        payload: { projectId: command.projectId, taskId: command.taskId, order },
        occurredAt: now,
      });
      return order;
    });
  }
}
