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

const mocks = vi.hoisted(() => ({
  antiDetectPause: vi.fn(async () => {}),
  ensureSlideVerification: vi.fn(async () => false),
  humanClick: vi.fn(async (_page, locator) => {
    await locator.click?.();
  }),
  randomBetween: vi.fn(() => 1),
  waitForManualVerificationIfNeeded: vi.fn(async () => false),
}));
const clock = vi.hoisted(() => ({
  nowMs: 0,
}));

vi.mock("./human.js", () => ({
  antiDetectPause: mocks.antiDetectPause,
  ensureSlideVerification: mocks.ensureSlideVerification,
  humanClick: mocks.humanClick,
  randomBetween: mocks.randomBetween,
  waitForManualVerificationIfNeeded: mocks.waitForManualVerificationIfNeeded,
}));

vi.mock("node:timers/promises", () => ({
  setTimeout: vi.fn(async (ms?: number) => {
    clock.nowMs += Number(ms ?? 0);
  }),
  default: {
    setTimeout: vi.fn(async (ms?: number) => {
      clock.nowMs += Number(ms ?? 0);
    }),
  },
}));

import { ensure1688LoggedIn } from "./ensure-1688-login.js";

class FakeLocator {
  constructor(
    private readonly page: FakePage,
    private readonly kind: "body" | "passwordTab" | "loginButton" | "input" | "missing",
  ) {}

  first() {
    return this;
  }

  async waitFor() {}

  async click() {
    if (this.kind === "loginButton") {
      this.page.afterLoginClicked = true;
      this.page.bodyText = "安全验证 手机短信验证码 验证码已发送 请输入验证码";
    }
  }

  async isVisible() {
    return this.kind !== "missing";
  }

  async count() {
    return this.kind === "missing" ? 0 : 1;
  }

  async innerText() {
    return this.page.bodyText;
  }
}

class FakePage {
  currentUrl = "about:blank";
  bodyText = "";
  afterLoginClicked = false;
  closed = false;
  keyboard = {
    press: vi.fn(async () => {}),
    type: vi.fn(async () => {}),
  };

  constructor(private readonly contextRef: FakeContext) {}

  isClosed() {
    return this.closed;
  }

  url() {
    if (this.afterLoginClicked && clock.nowMs >= 6500) {
      return "https://i.taobao.com/my_itaobao";
    }
    return this.currentUrl;
  }

  async goto(url: string) {
    this.currentUrl = url;
    this.bodyText = url.includes("login.taobao.com") ? "密码登录" : "1688 首页";
  }

  async waitForLoadState() {}

  async bringToFront() {}

  context() {
    return this.contextRef;
  }

  locator(selector: string) {
    if (selector === "body") return new FakeLocator(this, "body");
    if (selector === "#fm-login-id" || selector === "#fm-login-password") return new FakeLocator(this, "input");
    if (selector === ".password-login" || selector.includes("submit")) return new FakeLocator(this, "loginButton");
    return new FakeLocator(this, "missing");
  }

  getByText(text: string) {
    return new FakeLocator(this, text === "密码登录" ? "passwordTab" : "missing");
  }

  getByRole(_role: string, options: { name?: RegExp }) {
    return new FakeLocator(this, options.name?.test("登录") ? "loginButton" : "missing");
  }

  async evaluate() {
    return this.bodyText;
  }
}

class FakeContext {
  page = new FakePage(this);
  cookieChecks = 0;

  pages() {
    return [this.page];
  }

  async newPage() {
    return this.page;
  }

  async cookies() {
    this.cookieChecks += 1;
    if (this.cookieChecks >= 2) {
      this.page.currentUrl = "https://i.taobao.com/my_itaobao";
    }
    return this.cookieChecks >= 3
      ? [{ name: "cookie2", value: "ok" }]
      : [];
  }
}

describe("ensure1688LoggedIn", () => {
  beforeEach(() => {
    clock.nowMs = 0;
    vi.spyOn(Date, "now").mockImplementation(() => clock.nowMs);
    mocks.antiDetectPause.mockClear();
    mocks.ensureSlideVerification.mockReset();
    mocks.humanClick.mockClear();
    mocks.waitForManualVerificationIfNeeded.mockReset();
    mocks.waitForManualVerificationIfNeeded.mockResolvedValue(false);
  });

  afterEach(() => {
    vi.restoreAllMocks();
  });

  it("keeps waiting for login cookies after SMS verification consumes the original timeout", async () => {
    const context = new FakeContext();
    mocks.ensureSlideVerification.mockImplementation(async (page: FakePage) => {
      if (page.afterLoginClicked && page.bodyText.includes("短信验证码")) {
        clock.nowMs = 5000;
        page.bodyText = "密码登录";
        page.currentUrl = "https://login.taobao.com/member/login.jhtml";
        return true;
      }
      return false;
    });

    const pending = ensure1688LoggedIn(context as never, {
      accountName: "user",
      password: "pass",
      timeoutMs: 3000,
    });

    await expect(pending).resolves.toMatchObject({
      ok: true,
      status: "logged_in",
    });
  });
});
