import { BadRequestException } from "@nestjs/common";
import { PoliciesService } from "./policies.service";

/**
 * Deleting a lookup row that policies still reference used to succeed and
 * silently blank the field on every one of them, because both FKs are
 * `ON DELETE SET NULL` (`0000_init`). That is not a hypothetical: it is how
 * the `M_EMPR` policy type disappeared from the dev database and left 5
 * policies with a null `policyTypeId`, found only by querying months later.
 *
 * These tests pin the refusal. They drive the service with a stub client
 * rather than a database because what is being asserted is the guard, not
 * Prisma — and a test that needed a live MySQL would not run in CI.
 */
function serviceWith(counts: {
  policies?: number;
  claims?: number;
}): { service: PoliciesService; deleted: string[] } {
  const deleted: string[] = [];
  const prisma = {
    policy: { count: async () => counts.policies ?? 0 },
    claim: { count: async () => counts.claims ?? 0 },
    insuranceProvider: {
      findUnique: async () => ({ id: "p1", name: "ANA SEGUROS" }),
      delete: async () => {
        deleted.push("provider");
        return { id: "p1" };
      },
    },
    policyType: {
      findUnique: async () => ({ id: "t1", name: "M_EMPR" }),
      delete: async () => {
        deleted.push("policyType");
        return { id: "t1" };
      },
    },
    adjuster: {
      findUnique: async () => ({ id: "a1", name: "JUAN PEREZ" }),
      delete: async () => {
        deleted.push("adjuster");
        return { id: "a1" };
      },
    },
  };
  const storage = {} as never;
  return {
    service: new PoliciesService(prisma as never, storage),
    deleted,
  };
}

describe("lookup deletes refuse while the row is in use", () => {
  it("refuses a policy type that policies still carry, and names the count", () => {
    const { service, deleted } = serviceWith({ policies: 5 });
    return service.removePolicyType("t1").then(
      () => {
        throw new Error("expected the delete to be refused");
      },
      (err: unknown) => {
        expect(err).toBeInstanceOf(BadRequestException);
        // The operator has to be told WHICH row and HOW MANY, or the message
        // is not actionable.
        expect((err as Error).message).toContain("M_EMPR");
        expect((err as Error).message).toContain("5");
        expect(deleted).toEqual([]);
      },
    );
  });

  it("refuses a carrier that policies still carry", async () => {
    const { service, deleted } = serviceWith({ policies: 738 });
    await expect(service.removeProvider("p1")).rejects.toBeInstanceOf(
      BadRequestException,
    );
    expect(deleted).toEqual([]);
  });

  it("refuses an adjuster still assigned to claims", async () => {
    // Same `ON DELETE SET NULL` trap, on `claims.adjusterId`.
    const { service, deleted } = serviceWith({ claims: 2 });
    await expect(service.removeAdjuster("a1")).rejects.toBeInstanceOf(
      BadRequestException,
    );
    expect(deleted).toEqual([]);
  });

  it("allows the delete once nothing references the row", async () => {
    const { service, deleted } = serviceWith({ policies: 0, claims: 0 });
    await service.removePolicyType("t1");
    await service.removeProvider("p1");
    await service.removeAdjuster("a1");
    expect(deleted).toEqual(["policyType", "provider", "adjuster"]);
  });
});
