import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
import { render } from "solid-js/web";
import { Router, Route } from "@solidjs/router";
import { MetaProvider } from "@solidjs/meta";
import type { JSX } from "solid-js";

import LoginPage from "./login";
import SignupPage from "./signup";
import ForgotPasswordPage from "./forgot-password";
import OnboardingPage from "./onboarding";

import * as auth from "~/lib/auth";

function mount(comp: () => JSX.Element): HTMLDivElement {
  const container = document.createElement("div");
  document.body.appendChild(container);
  render(() => comp(), container);
  return container;
}

beforeEach(() => {
  document.body.innerHTML = "";
  if (!globalThis.crypto) {
    Object.defineProperty(globalThis, "crypto", { value: {} });
  }
  (globalThis.crypto as unknown as Record<string, unknown>).randomUUID = vi.fn(
    () => "test-uuid-1234",
  );
});

afterEach(() => {
  document.body.innerHTML = "";
  vi.restoreAllMocks();
});

function setInputValue(input: HTMLInputElement, value: string) {
  input.value = value;
  input.dispatchEvent(
    new InputEvent("input", { bubbles: true, composed: true }),
  );
}

describe("LoginPage", () => {
  function WrappedLogin() {
    return (
      <MetaProvider>
        <Router>
          <Route path="/" component={LoginPage} />
        </Router>
      </MetaProvider>
    );
  }

  it("renders sign in form with email, password, and submit button", () => {
    mount(() => <WrappedLogin />);
    expect(document.body.textContent).toContain("Welcome back");
    expect(document.body.textContent).toContain("Email");
    expect(document.querySelector("input[type='email']")).toBeTruthy();
    expect(document.body.textContent).toContain("Sign In");
  });

  it("renders Remember me and Forgot password links", () => {
    mount(() => <WrappedLogin />);
    expect(document.body.textContent).toContain("Remember me");
    expect(document.body.textContent).toContain("Forgot password?");
    expect(document.body.textContent).toContain("Sign up");
    expect(document.body.textContent).toContain("Or continue with");
  });

  it("shows validation errors for empty fields on submit", () => {
    mount(() => <WrappedLogin />);
    const form = document.querySelector("form")!;
    form.dispatchEvent(
      new Event("submit", { bubbles: true, cancelable: true }),
    );
    expect(document.body.textContent).toContain("Email is required");
    expect(document.body.textContent).toContain("Password is required");
  });

  it("shows email format error for invalid email", () => {
    mount(() => <WrappedLogin />);
    const emailInput =
      document.querySelector<HTMLInputElement>("input[type='email']")!;
    setInputValue(emailInput, "not-an-email");
    const form = document.querySelector("form")!;
    form.dispatchEvent(
      new Event("submit", { bubbles: true, cancelable: true }),
    );
    expect(document.body.textContent).toContain("Invalid email format");
  });

  it("shows server error on failed login", async () => {
    vi.spyOn(auth, "login").mockRejectedValue(new Error("Invalid credentials"));
    mount(() => <WrappedLogin />);
    const emailInput =
      document.querySelector<HTMLInputElement>("input[type='email']")!;
    setInputValue(emailInput, "test@example.com");
    const passwordInput =
      document.querySelector<HTMLInputElement>(
        "input[type='password']",
      )!;
    setInputValue(passwordInput, "password123");
    const form = document.querySelector("form")!;
    form.dispatchEvent(
      new Event("submit", { bubbles: true, cancelable: true }),
    );
    await vi.waitFor(() => {
      expect(document.body.textContent).toContain("Invalid email or password");
    });
  });
});

describe("SignupPage", () => {
  function WrappedSignup() {
    return (
      <MetaProvider>
        <Router>
          <Route path="/" component={SignupPage} />
        </Router>
      </MetaProvider>
    );
  }

  it("renders sign up form with all fields", () => {
    mount(() => <WrappedSignup />);
    expect(document.body.textContent).toContain("Create your account");
    expect(document.body.textContent).toContain("Full name");
    expect(document.body.textContent).toContain("Email");
    expect(document.body.textContent).toContain("Password");
    expect(document.body.textContent).toContain("Confirm password");
    expect(document.body.textContent).toContain("Terms of Service");
    expect(document.body.textContent).toContain("Create Account");
  });

  it("shows validation errors for empty fields on submit", () => {
    mount(() => <WrappedSignup />);
    const form = document.querySelector("form")!;
    form.dispatchEvent(
      new Event("submit", { bubbles: true, cancelable: true }),
    );
    expect(document.body.textContent).toContain("Name is required");
    expect(document.body.textContent).toContain("Email is required");
    expect(document.body.textContent).toContain("Password is required");
  });

  it("shows password mismatch error", () => {
    mount(() => <WrappedSignup />);
    const inputs = document.querySelectorAll<HTMLInputElement>("input");
    const passwordInput = inputs[2];
    const confirmInput = inputs[3];
    setInputValue(passwordInput, "password123");
    setInputValue(confirmInput, "different");
    const form = document.querySelector("form")!;
    form.dispatchEvent(
      new Event("submit", { bubbles: true, cancelable: true }),
    );
    expect(document.body.textContent).toContain("Passwords do not match");
  });

  it("shows ToS error when checkbox is unchecked", () => {
    mount(() => <WrappedSignup />);
    const nameInput =
      document.querySelector<HTMLInputElement>("input[name='name']")!;
    const emailInput =
      document.querySelector<HTMLInputElement>("input[name='email']")!;
    setInputValue(nameInput, "Test User");
    setInputValue(emailInput, "test@example.com");
    const form = document.querySelector("form")!;
    form.dispatchEvent(
      new Event("submit", { bubbles: true, cancelable: true }),
    );
    expect(document.body.textContent).toContain("You must agree to the Terms");
  });

  it("renders Log in link and social buttons", () => {
    mount(() => <WrappedSignup />);
    expect(document.body.textContent).toContain("Log in");
    expect(document.body.textContent).toContain("Or continue with");
  });
});

describe("ForgotPasswordPage", () => {
  function WrappedForgot() {
    return (
      <MetaProvider>
        <Router>
          <Route path="/" component={ForgotPasswordPage} />
        </Router>
      </MetaProvider>
    );
  }

  it("renders forgot password form", () => {
    mount(() => <WrappedForgot />);
    expect(document.body.textContent).toContain("Forgot password?");
    expect(document.body.textContent).toContain("Send Reset Link");
    expect(document.body.textContent).toContain("Back to sign in");
  });

  it("shows validation error for empty email", () => {
    mount(() => <WrappedForgot />);
    const form = document.querySelector("form")!;
    form.dispatchEvent(
      new Event("submit", { bubbles: true, cancelable: true }),
    );
    expect(document.body.textContent).toContain("Email is required");
  });

  it("shows success state after submission", async () => {
    vi.spyOn(auth, "forgotPassword").mockResolvedValue(undefined);
    mount(() => <WrappedForgot />);
    const emailInput =
      document.querySelector<HTMLInputElement>("input[type='email']")!;
    setInputValue(emailInput, "test@example.com");
    const form = document.querySelector("form")!;
    form.dispatchEvent(
      new Event("submit", { bubbles: true, cancelable: true }),
    );
    await vi.waitFor(() => {
      expect(document.body.textContent).toContain("Check your email");
    });
  });
});

describe("OnboardingPage", () => {
  function WrappedOnboarding() {
    return (
      <MetaProvider>
        <Router>
          <Route path="/" component={OnboardingPage} />
        </Router>
      </MetaProvider>
    );
  }

  it("renders step 1 (Choose Plan) by default with plan cards", () => {
    mount(() => <WrappedOnboarding />);
    expect(document.body.textContent).toContain("Choose your plan");
    expect(document.body.textContent).toContain("Basic");
    expect(document.body.textContent).toContain("Plus");
    expect(document.body.textContent).toContain("Premium");
    expect(document.body.textContent).toContain("Popular");
  });

  it("advances to step 2 when Continue is clicked", () => {
    mount(() => <WrappedOnboarding />);
    const continueBtn = [...document.querySelectorAll("button")].find((b) =>
      b.textContent?.includes("Continue"),
    )!;
    continueBtn.dispatchEvent(new MouseEvent("click", { bubbles: true }));
    expect(document.body.textContent).toContain(
      "Add your first watchlist item",
    );
  });
});
