import type { CommandContext } from "@tailor-platform/erp-kit/core";
import { createKyselyMock } from "@tailor-platform/sdk/vitest";
import { describe, expect, it } from "vitest";
import type { Namespace } from "../generated/kysely-tailordb";
import { CommentNotFoundError, ForbiddenError } from "../lib/errors.generated";
import { basePipelineItemComment } from "../testing/fixtures";
import { run, type DeletePipelineItemCommentInput } from "./deletePipelineItemComment";

describe("deletePipelineItemComment", () => {
  const ctx: CommandContext = {
    actorId: basePipelineItemComment.authorUserId,
    permissions: ["pipeline-management:pipelineItemComment:deletePipelineItemComment"],
  };

  const input: DeletePipelineItemCommentInput = {
    commentId: basePipelineItemComment.id,
  };

  it("author can delete their own comment", async () => {
    const mock = createKyselyMock<Namespace["main-db"]>();
    mock.enqueueResults([basePipelineItemComment]);

    const result = await mock.withTx((trx) => run(trx, input, ctx));

    expect(result.ok).toBe(true);
    expect(mock.deletes.length).toBeGreaterThan(0);
  });

  it("returns error when comment does not exist", async () => {
    const mock = createKyselyMock<Namespace["main-db"]>();
    mock.enqueueResults([]);

    const result = await mock.withTx((trx) => run(trx, input, ctx));

    expect(result.ok).toBe(false);
    if (!result.ok) {
      expect(result.error).toBeInstanceOf(CommentNotFoundError);
    }
  });

  it("non-author delete is rejected with FORBIDDEN", async () => {
    const mock = createKyselyMock<Namespace["main-db"]>();
    mock.enqueueResults([basePipelineItemComment]);

    const result = await mock.withTx((trx) => run(trx, input, { ...ctx, actorId: "other-user" }));

    expect(result.ok).toBe(false);
    if (!result.ok) {
      expect(result.error).toBeInstanceOf(ForbiddenError);
    }
  });

  it("deleted comment is removed from subsequent list queries", async () => {
    const mock = createKyselyMock<Namespace["main-db"]>();
    mock.enqueueResults([basePipelineItemComment]);

    const result = await mock.withTx((trx) => run(trx, input, ctx));

    expect(result.ok).toBe(true);
    expect(mock.deletes.length).toBeGreaterThan(0);
  });
});
