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

// --- mock helpers ---

function makeResponse(status: number) {
  return { status: () => status };
}

function makePage(overrides: {
  currentUrl?: string;
  postStatus?: number;
  loginTextVisible?: boolean;
} = {}) {
  const currentUrl = overrides.currentUrl ?? "http://localhost:5180/login";
  const postStatus = overrides.postStatus ?? 200;
  const loginTextVisible = overrides.loginTextVisible ?? false;

  const locatorMock = {
    isVisible: vi.fn().mockResolvedValue(loginTextVisible),
  };

  return {
    url: vi.fn().mockReturnValue(currentUrl),
    request: {
      post: vi.fn().mockResolvedValue(makeResponse(postStatus)),
    },
    goto: vi.fn().mockResolvedValue(undefined),
    waitForLoadState: vi.fn().mockResolvedValue(undefined),
    waitForSelector: vi.fn().mockResolvedValue(undefined),
    locator: vi.fn().mockReturnValue(locatorMock),
    _locatorMock: locatorMock,
  };
}

// --- tests ---

describe("pw_kanban_login", () => {
  it("happy path", async () => {
    const page = makePage({ postStatus: 200, loginTextVisible: false });

    await pw_kanban_login(page as any, {
      username: "egutierrez",
      password: "secret",
    });

    // Should POST to derived origin + /api/login with correct body
    expect(page.request.post).toHaveBeenCalledWith(
      "http://localhost:5180/api/login",
      { data: { username: "egutierrez", password: "secret" } },
    );

    // Should navigate to root
    expect(page.goto).toHaveBeenCalledWith("http://localhost:5180/");

    // Should wait for page load
    expect(page.waitForLoadState).toHaveBeenCalledWith("networkidle");
    expect(page.waitForSelector).toHaveBeenCalledWith("body", { state: "attached" });
  });

  it("rejects 401", async () => {
    const page = makePage({ postStatus: 401 });

    await expect(
      pw_kanban_login(page as any, { username: "bad", password: "wrong" }),
    ).rejects.toThrow("kanban login failed: 401");

    // Should NOT navigate after failed login
    expect(page.goto).not.toHaveBeenCalled();
  });

  it("rejects 500", async () => {
    const page = makePage({ postStatus: 500 });

    await expect(
      pw_kanban_login(page as any, { username: "u", password: "p" }),
    ).rejects.toThrow("kanban login failed: 500");
  });

  it("rejects when login page still visible", async () => {
    // Simulate server returns 200 but login page is still showing (e.g. cookie not set)
    const page = makePage({ postStatus: 200, loginTextVisible: true });

    await expect(
      pw_kanban_login(page as any, { username: "egutierrez", password: "secret" }),
    ).rejects.toThrow("kanban login failed: login page still visible after authentication");
  });

  it("uses explicit baseUrl over page origin", async () => {
    const page = makePage({ currentUrl: "http://localhost:5180/login", postStatus: 200 });

    await pw_kanban_login(page as any, {
      username: "egutierrez",
      password: "secret",
      baseUrl: "http://custom-host:9000",
    });

    expect(page.request.post).toHaveBeenCalledWith(
      "http://custom-host:9000/api/login",
      expect.any(Object),
    );
    expect(page.goto).toHaveBeenCalledWith("http://custom-host:9000/");
  });
});
