import { Repository } from "typeorm";

import { CompanyChangeRequestRepository } from "./company-change-request.repository";
import {
  ChangeRequestStatus,
  CompanyChangeRequest,
} from "./entities/company-change-request.entity";

type Row = Pick<CompanyChangeRequest, "id" | "status"> & { createdAt: Date };

const COMPANY_ID = "company-1";

/**
 * Stands in for the TypeORM repository over a fixed set of rows, honouring the
 * `where.status` filter and the `createdAt DESC` ordering findOne relies on.
 */
function mockRepositoryOver(rows: Row[]) {
  return {
    findOne: jest.fn(
      ({ where }: { where: Partial<Row> & { companyId: string } }) =>
        Promise.resolve(
          rows
            .filter(
              (row) =>
                where.companyId === COMPANY_ID &&
                (where.status === undefined || row.status === where.status),
            )
            .sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime())[0] ??
            null,
        ),
    ),
  } as unknown as Repository<CompanyChangeRequest>;
}

function subject(rows: Row[]) {
  return new CompanyChangeRequestRepository(mockRepositoryOver(rows));
}

describe("CompanyChangeRequestRepository.findLatestOpenByCompanyId", () => {
  const rejected: Row = {
    id: "rejected",
    status: ChangeRequestStatus.Rejected,
    createdAt: new Date("2026-01-01T00:00:00.000Z"),
  };

  it("returns the pending request when one is open", async () => {
    const pending: Row = {
      id: "pending",
      status: ChangeRequestStatus.Pending,
      createdAt: new Date("2026-01-02T00:00:00.000Z"),
    };

    const result = await subject([rejected, pending]).findLatestOpenByCompanyId(
      COMPANY_ID,
    );

    expect(result?.id).toBe("pending");
  });

  it("returns the latest rejected request when nothing is pending", async () => {
    const result = await subject([rejected]).findLatestOpenByCompanyId(
      COMPANY_ID,
    );

    expect(result?.id).toBe("rejected");
  });

  it("returns null once a resubmit of a rejected request is approved", async () => {
    const approved: Row = {
      id: "approved",
      status: ChangeRequestStatus.Approved,
      createdAt: new Date("2026-01-02T00:00:00.000Z"),
    };

    const result = await subject([
      rejected,
      approved,
    ]).findLatestOpenByCompanyId(COMPANY_ID);

    expect(result).toBeNull();
  });

  it("returns null when the company has no requests", async () => {
    const result = await subject([]).findLatestOpenByCompanyId(COMPANY_ID);

    expect(result).toBeNull();
  });
});
