import { Effect } from "effect";
import { describe, expect, test } from "vitest";

import {
  projectWorkNotices,
  signalAttachedEvent,
  workDraftFromSignal,
  workProposedEventFromSignal,
} from "./work";

describe("workDraftFromSignal", () => {
  test("creates a proposed Work draft from Signal meaning", async () => {
    const draft = await Effect.runPromise(
      workDraftFromSignal({
        desiredOutcome: "The phone flow is usable.",
        summary: "The current mobile workspace is hard to test.",
        title: "Make Slice 1 phone-testable",
      })
    );

    expect(draft).toEqual({
      objective: "The phone flow is usable.",
      title: "Make Slice 1 phone-testable",
    });
  });

  test("rejects empty Signal meaning", async () => {
    await expect(
      Effect.runPromise(
        workDraftFromSignal({ desiredOutcome: "", summary: "", title: "" })
      )
    ).rejects.toMatchObject({ reason: "InvalidInput" });
  });

  test("constructs stable proposed and attached event drafts", async () => {
    const proposed = await Effect.runPromise(
      workProposedEventFromSignal({
        organizationId: "org-1",
        projectId: "project-1",
        signalId: "signal-1",
        title: "  Improve the phone flow  ",
      })
    );
    const attached = await Effect.runPromise(
      signalAttachedEvent({
        signal: {
          organizationId: "org-1",
          projectId: "project-1",
          signalId: "signal-2",
          title: "Reuse the existing outcome",
        },
        work: {
          organizationId: "org-1",
          projectId: "project-1",
          workId: "work-1",
        },
      })
    );

    expect(proposed).toEqual({
      data: { signalId: "signal-1", title: "Improve the phone flow" },
      idempotencyKey: "proposed:signal-1",
      kind: "work.proposed",
    });
    expect(attached).toEqual({
      data: { signalId: "signal-2", title: "Reuse the existing outcome" },
      idempotencyKey: "signal:signal-2",
      kind: "signal.attached",
    });
  });

  test("rejects a cross-project attachment", async () => {
    await expect(
      Effect.runPromise(
        signalAttachedEvent({
          signal: {
            organizationId: "org-1",
            projectId: "project-2",
            signalId: "signal-1",
            title: "Cross project",
          },
          work: {
            organizationId: "org-1",
            projectId: "project-1",
            workId: "work-1",
          },
        })
      )
    ).rejects.toMatchObject({ reason: "ProjectMismatch" });
  });

  test("projects proposed Work events into chronological notices", () => {
    expect(
      projectWorkNotices([
        {
          _id: "work-2",
          events: [{ _id: "event-2", createdAt: 20, kind: "work.proposed" }],
          signals: [
            {
              sources: [{ messageId: "message-2", rawText: "Second" }],
            },
          ],
        },
        {
          _id: "work-1",
          events: [
            { _id: "event-1", createdAt: 10, kind: "work.proposed" },
            { _id: "event-3", createdAt: 30, kind: "signal.attached" },
          ],
          signals: [
            {
              sources: [{ messageId: "message-1", rawText: "First" }],
            },
          ],
        },
      ])
    ).toEqual([
      {
        createdAt: 10,
        eventId: "event-1",
        sourceMessageIds: ["message-1"],
        sourceTexts: ["First"],
        workId: "work-1",
      },
      {
        createdAt: 20,
        eventId: "event-2",
        sourceMessageIds: ["message-2"],
        sourceTexts: ["Second"],
        workId: "work-2",
      },
    ]);
  });
});
