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

import {
  decodeProjectIssueRequest,
  ProjectIssueTransitionError,
  ProjectIssueValidationError,
  projectIssueDraftFromSignal,
  queueProjectIssue,
  validateProjectIssueDraft,
} from "./project-issue";

describe("project issue primitives", () => {
  it("normalizes an explicit project request", () => {
    const request = Effect.runSync(
      decodeProjectIssueRequest({
        body: "  Investigate the staging failure.  ",
        kind: "explicit",
        projectId: "project-1",
        title: "  Staging failure  ",
      })
    );

    expect(request).toEqual({
      body: "Investigate the staging failure.",
      kind: "explicit",
      projectId: "project-1",
      title: "Staging failure",
    });
  });

  it("rejects invalid issue drafts before persistence", () => {
    const error = Effect.runSync(
      Effect.flip(
        validateProjectIssueDraft({
          body: "too short",
          title: "No",
        })
      )
    );

    expect(error).toBeInstanceOf(ProjectIssueValidationError);
    expect(error.reason).toBe("TitleTooShort");
  });

  it("projects a project Signal into the existing issue shape", () => {
    const draft = Effect.runSync(
      projectIssueDraftFromSignal({
        problemStatement: {
          constraints: ["Do not change production"],
          desiredOutcome: "Staging deploys successfully",
          summary: "The deploy fails during DNS resolution",
          title: "Fix staging deploy DNS failure",
        },
        signalId: "signal-1",
      })
    );

    expect(draft.title).toBe("Fix staging deploy DNS failure");
    expect(draft.body).toContain("The deploy fails during DNS resolution");
    expect(draft.body).toContain("Source Signal: signal-1");
  });

  it("queues retryable issue states and preserves active states", () => {
    expect(Effect.runSync(queueProjectIssue("open"))).toBe("queued");
    expect(Effect.runSync(queueProjectIssue("failed"))).toBe("queued");
    expect(Effect.runSync(queueProjectIssue("needs-input"))).toBe("queued");
    expect(Effect.runSync(queueProjectIssue("working"))).toBe("working");
  });

  it("does not reopen completed issues", () => {
    const error = Effect.runSync(Effect.flip(queueProjectIssue("completed")));

    expect(error).toBeInstanceOf(ProjectIssueTransitionError);
    expect(error.reason).toBe("CompletedIssue");
  });
});
