import { describe, it, expect, vi, beforeEach } from "vitest";

vi.mock("~/models/user", () => ({
  isUserAdmin: vi.fn(),
}));

import * as schema from "~/database/schema";

vi.mock("~/database/context", () => ({
  database: vi.fn(),
}));

import { isCommissioner, hasCommissionerRecord, removeAllCommissionersByUserId } from "../commissioner";
import { isUserAdmin } from "~/models/user";
import { database } from "~/database/context";

const LEAGUE_ID = "league-1";
const USER_ID = "user-uuid-1";

function makeMockDb(commissionerRow: object | null) {
  return {
    query: {
      commissioners: {
        findFirst: vi.fn().mockResolvedValue(commissionerRow),
      },
    },
  };
}

beforeEach(() => {
  vi.clearAllMocks();
});

describe("isCommissioner", () => {
  it("returns true for a site admin without a commissioner record", async () => {
    vi.mocked(isUserAdmin).mockResolvedValue(true);
    vi.mocked(database).mockReturnValue(makeMockDb(null) as never);

    const result = await isCommissioner(LEAGUE_ID, USER_ID);
    expect(result).toBe(true);
  });

  it("returns true for a user with a commissioner record", async () => {
    vi.mocked(isUserAdmin).mockResolvedValue(false);
    vi.mocked(database).mockReturnValue(
      makeMockDb({ id: "comm-1", leagueId: LEAGUE_ID, userId: USER_ID }) as never
    );

    const result = await isCommissioner(LEAGUE_ID, USER_ID);
    expect(result).toBe(true);
  });

  it("returns true for a site admin who also has a commissioner record", async () => {
    vi.mocked(isUserAdmin).mockResolvedValue(true);
    vi.mocked(database).mockReturnValue(
      makeMockDb({ id: "comm-1", leagueId: LEAGUE_ID, userId: USER_ID }) as never
    );

    const result = await isCommissioner(LEAGUE_ID, USER_ID);
    expect(result).toBe(true);
  });

  it("returns false for a non-admin user without a commissioner record", async () => {
    vi.mocked(isUserAdmin).mockResolvedValue(false);
    vi.mocked(database).mockReturnValue(makeMockDb(null) as never);

    const result = await isCommissioner(LEAGUE_ID, USER_ID);
    expect(result).toBe(false);
  });

  it("runs the admin check and DB query in parallel", async () => {
    const order: string[] = [];
    vi.mocked(isUserAdmin).mockImplementation(async () => {
      order.push("admin");
      return false;
    });
    const db = makeMockDb(null);
    db.query.commissioners.findFirst = vi.fn().mockImplementation(async () => {
      order.push("db");
      return null;
    });
    vi.mocked(database).mockReturnValue(db as never);

    await isCommissioner(LEAGUE_ID, USER_ID);

    // Both should have been called; order is non-deterministic for parallel calls
    expect(order).toContain("admin");
    expect(order).toContain("db");
  });
});

describe("hasCommissionerRecord", () => {
  it("returns true when a commissioner record exists", async () => {
    vi.mocked(database).mockReturnValue(
      makeMockDb({ id: "comm-1", leagueId: LEAGUE_ID, userId: USER_ID }) as never
    );

    const result = await hasCommissionerRecord(LEAGUE_ID, USER_ID);
    expect(result).toBe(true);
  });

  it("returns false when no commissioner record exists", async () => {
    vi.mocked(database).mockReturnValue(makeMockDb(null) as never);

    const result = await hasCommissionerRecord(LEAGUE_ID, USER_ID);
    expect(result).toBe(false);
  });

  it("returns false for a site admin without a commissioner record", async () => {
    // hasCommissionerRecord must NOT consult the admin flag
    vi.mocked(database).mockReturnValue(makeMockDb(null) as never);

    const result = await hasCommissionerRecord(LEAGUE_ID, USER_ID);
    expect(result).toBe(false);
    expect(isUserAdmin).not.toHaveBeenCalled();
  });
});

describe("removeAllCommissionersByUserId", () => {
  it("deletes from the commissioners table for the given user", async () => {
    const whereFn = vi.fn().mockResolvedValue(undefined);
    const deleteFn = vi.fn().mockReturnValue({ where: whereFn });
    vi.mocked(database).mockReturnValue({ delete: deleteFn } as never);

    await removeAllCommissionersByUserId(USER_ID);

    expect(deleteFn).toHaveBeenCalledTimes(1);
    expect(deleteFn).toHaveBeenCalledWith(schema.commissioners);
    expect(whereFn).toHaveBeenCalledTimes(1);
  });
});
