import { expect, test } from "vitest";
import { screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { http, HttpResponse } from "msw";
import { Routes, Route } from "react-router-dom";
import { server } from "../test/server";
import { renderApp } from "../test/render";
import { LoginPage } from "./login-page";

function tree() {
  return (
    <Routes>
      <Route path="/login" element={<LoginPage />} />
      <Route path="/objects" element={<div>objects landing</div>} />
      <Route path="/objects/:id" element={<div>object detail</div>} />
    </Routes>
  );
}

test("successful login navigates to /objects", async () => {
  renderApp(tree(), { route: "/login" });
  await userEvent.type(screen.getByLabelText(/email/i), "editor@example.com");
  await userEvent.type(screen.getByLabelText(/password/i), "pw-editor-123");
  await userEvent.click(screen.getByRole("button", { name: /sign in/i }));
  expect(await screen.findByText("objects landing")).toBeInTheDocument();
});

test("invalid credentials show an inline error", async () => {
  server.use(http.post("/api/admin/login", () => new HttpResponse(null, { status: 401 })));
  renderApp(tree(), { route: "/login" });
  await userEvent.type(screen.getByLabelText(/email/i), "x@y.se");
  await userEvent.type(screen.getByLabelText(/password/i), "wrong");
  await userEvent.click(screen.getByRole("button", { name: /sign in/i }));
  await waitFor(() =>
    expect(screen.getByText(/invalid email or password/i)).toBeInTheDocument(),
  );
});

test("shows the session-expired notice when reason=expired", async () => {
  renderApp(tree(), { route: "/login?reason=expired" });
  expect(await screen.findByText(/session expired/i)).toBeInTheDocument();
});

test("returns to the from path on success", async () => {
  renderApp(tree(), { route: "/login?from=%2Fobjects%2F123" });
  await userEvent.type(screen.getByLabelText(/email/i), "editor@example.com");
  await userEvent.type(screen.getByLabelText(/password/i), "pw-editor-123");
  await userEvent.click(screen.getByRole("button", { name: /sign in/i }));
  expect(await screen.findByText("object detail")).toBeInTheDocument();
});

test("rejects an off-site from and falls back to /objects", async () => {
  renderApp(tree(), { route: "/login?from=%2F%2Fevil.com" });
  await userEvent.type(screen.getByLabelText(/email/i), "editor@example.com");
  await userEvent.type(screen.getByLabelText(/password/i), "pw-editor-123");
  await userEvent.click(screen.getByRole("button", { name: /sign in/i }));
  expect(await screen.findByText("objects landing")).toBeInTheDocument();
});

test("disables submit until both fields are filled", async () => {
  renderApp(tree(), { route: "/login" });
  const button = screen.getByRole("button", { name: /sign in/i });
  expect(button).toBeDisabled();
  await userEvent.type(screen.getByLabelText(/email/i), "a@b.se");
  expect(button).toBeDisabled();
  await userEvent.type(screen.getByLabelText(/password/i), "pw");
  expect(button).toBeEnabled();
});
