import { test } from "node:test";
import assert from "node:assert/strict";
import { JSDOM } from "jsdom";
import { createApp } from "../server.ts";
import { Store } from "../backend/store.ts";
import { Mailer } from "../backend/mail.ts";
import { Monitor } from "../backend/monitor.ts";
import { hashPassword } from "../backend/auth.ts";

test("dashboard flow: login, failed save retains inputs, add, history, truthful SMTP and logout", async (t) => {
  const store = new Store(":memory:");
  store.db
    .prepare("INSERT INTO admins VALUES(?,?)")
    .run("uitest", await hashPassword("UiTestPassword123!"));
  const mailer = new Mailer(store);
  mailer.configured = false;
  const monitor = new Monitor(store, mailer, 2, async (site) => ({
    url: site.url,
    hostname: new URL(site.url).hostname,
    status: "online",
    statusCode: 200,
    statusText: "HTTP 200",
    responseTimeMs: 120,
    isWordPress: true,
    restApiStatus: "healthy",
    ssl: { valid: true, checked: true, daysRemaining: 60 },
    checkedAt: new Date().toISOString(),
    wpErrorMessage: "Halaman boleh dicapai.",
  }));
  const app = createApp(store, monitor);
  const server = app.listen(0, "127.0.0.1");
  await new Promise<void>((r) => server.once("listening", r));
  const origin = `http://127.0.0.1:${(server.address() as { port: number }).port}`;
  const dom = new JSDOM("<!doctype html><html><body></body></html>", {
    url: origin,
  });
  Object.assign(globalThis, {
    window: dom.window,
    document: dom.window.document,
    HTMLElement: dom.window.HTMLElement,
    Element: dom.window.Element,
    Event: dom.window.Event,
    MouseEvent: dom.window.MouseEvent,
    localStorage: dom.window.localStorage,
    getComputedStyle: dom.window.getComputedStyle,
    IS_REACT_ACT_ENVIRONMENT: true,
  });
  Object.defineProperty(globalThis, "navigator", {
    value: dom.window.navigator,
    configurable: true,
  });
  const fetchOriginal = globalThis.fetch;
  let cookie = "";
  globalThis.fetch = async (input: any, init: RequestInit = {}) => {
    const headers = new Headers(init.headers);
    headers.set("Origin", origin);
    headers.set("Cookie", cookie);
    const r = await fetchOriginal(new URL(String(input), origin), {
      ...init,
      headers,
    });
    const setCookie = r.headers.get("set-cookie");
    if (setCookie) cookie = setCookie.split(";")[0];
    return r;
  };
  const React = await import("react");
  const { render, screen, cleanup, waitFor } =
    await import("@testing-library/react");
  const { default: userEvent } = await import("@testing-library/user-event");
  const { default: App } = await import("../src/App.tsx");
  const user = userEvent.setup();
  t.after(async () => {
    cleanup();
    globalThis.fetch = fetchOriginal;
    dom.window.close();
    monitor.stop();
    while (monitor.active.size) await new Promise<void>((r) => setImmediate(r));
    await new Promise<void>((r) => server.close(() => r()));
    store.close();
  });
  render(React.createElement(App));
  await user.type(await screen.findByLabelText("Nama pengguna"), "uitest");
  await user.type(screen.getByLabelText("Kata laluan"), "UiTestPassword123!");
  await user.click(screen.getByRole("button", { name: "Log masuk" }));
  await screen.findByText(
    "Tambah laman web WordPress klien pertama anda untuk memulakan pemantauan kesihatan.",
  );
  await user.click(screen.getByRole("button", { name: "Tambah Web" }));
  const name = screen.getByLabelText(/Nama Laman Web \/ Bisnes/);
  const url = screen.getByLabelText(/URL Laman Web WordPress/);
  await user.type(name, "Portal Test Client");
  await user.type(url, "http://127.0.0.1");
  await user.click(screen.getByRole("button", { name: "Tambah & Semak" }));
  await screen.findByRole("alert");
  assert.equal((name as HTMLInputElement).value, "Portal Test Client");
  assert.equal((url as HTMLInputElement).value, "http://127.0.0.1");
  await user.clear(url);
  await user.type(url, "https://8.8.8.8/staging/");
  await user.click(screen.getByRole("button", { name: "Tambah & Semak" }));
  await screen.findByRole("heading", {
    name: "Portal Test Client",
  });
  assert.equal(store.sites().length, 1);
  await waitFor(() =>
    assert.equal(store.sites()[0].lastResult?.status, "online"),
  );
  await user.click(screen.getByTitle("Lihat butiran kesihatan & diagnostik"));
  await screen.findByRole("heading", {
    name: "Sejarah semakan — Portal Test Client",
  });
  await user.click(screen.getByRole("button", { name: "Tutup" }));
  await user.click(screen.getByTitle("Tetapan Notifikasi & Auto-Check"));
  await user.click(screen.getByRole("button", { name: "Uji SMTP" }));
  await screen.findAllByText("SMTP belum dikonfigurasi. Tiada emel dihantar.");
  await user.click(screen.getByRole("button", { name: /Log emel/ }));
  await screen.findByText("SMTP belum disediakan");
  await user.click(screen.getByRole("button", { name: "Tutup" }));
  await user.click(screen.getByRole("button", { name: "Log keluar" }));
  await screen.findByLabelText("Nama pengguna");
  assert.equal(
    store.db.prepare("SELECT count(*) AS count FROM sessions").get()!.count,
    0,
  );
});
