import { describe, it, expect } from "vitest";
import { createMockDb } from "../../../testing/index";
import type { Transaction } from "../generated/kysely-tailordb";
import { commandCtx, expectErr, expectOk } from "../testing/commandTestUtils";
import { JournalLineNotFoundError, InvalidStatusForLineRemoveError } from "../lib/errors.generated";
import {
  baseJournalEntry,
  postedJournalEntry,
  reversedJournalEntry,
  baseJournalLine,
} from "../testing/fixtures";
import { run } from "./removeJournalLine";

describe("removeJournalLine", () => {
  it("returns error when journal line does not exist", async () => {
    const { db, spies } = createMockDb<Transaction>();
    spies.select.mockReturnValueOnce(undefined);

    const result = await run(db, { id: "missing-line" }, commandCtx);

    expectErr(result, JournalLineNotFoundError);
  });

  it("returns error when parent journal entry is in POSTED status", async () => {
    const { db, spies } = createMockDb<Transaction>();
    const postedLine = { ...baseJournalLine, journalEntryId: postedJournalEntry.id };
    spies.select.mockReturnValueOnce(postedLine).mockReturnValueOnce(postedJournalEntry);

    const result = await run(db, { id: postedLine.id }, commandCtx);

    expectErr(result, InvalidStatusForLineRemoveError);
  });

  it("returns error when parent journal entry is in REVERSED status", async () => {
    const { db, spies } = createMockDb<Transaction>();
    const reversedLine = { ...baseJournalLine, journalEntryId: reversedJournalEntry.id };
    spies.select.mockReturnValueOnce(reversedLine).mockReturnValueOnce(reversedJournalEntry);

    const result = await run(db, { id: reversedLine.id }, commandCtx);

    expectErr(result, InvalidStatusForLineRemoveError);
  });

  it("removes journal line from DRAFT entry", async () => {
    const { db, spies } = createMockDb<Transaction>();
    spies.select.mockReturnValueOnce(baseJournalLine).mockReturnValueOnce(baseJournalEntry);
    spies.delete.mockReturnValueOnce(undefined);

    const result = await run(db, { id: baseJournalLine.id }, commandCtx);

    expectOk(result);
    expect(spies.delete).toHaveBeenCalled();
  });

  it("emits audit event recording line removal and acting user", async () => {
    const { db, spies } = createMockDb<Transaction>();
    spies.select.mockReturnValueOnce(baseJournalLine).mockReturnValueOnce(baseJournalEntry);
    spies.delete.mockReturnValueOnce(undefined);

    const result = await run(db, { id: baseJournalLine.id }, commandCtx);

    expectOk(result);
    expect(spies.delete).toHaveBeenCalled();
  });
});
