/**
 * Ticket #90 — the web "Panneaux" (WebWorkspace) and "Paramètres" (WebApp) menus.
 *
 * Both replace the previous ad-hoc navigation (a 3-tab tablist, a single
 * "Appareils" header toggle) with a full-screen {@link WebMenuSheet}: this pins
 * the new contract — entry list, active marker, disabled-with-reason state, and
 * that selecting an entry routes the main surface without ever crashing on a
 * desktop-only action.
 */
import { describe, it, expect } from "vitest";
import { fireEvent, render, screen } from "@testing-library/react";

import type { Gateways } from "@/ports";
import { DIProvider } from "@/app/di";
import { createMockGateways } from "@/adapters/mock";
import { WebSession } from "@/adapters/http";
import type { FetchLike } from "@/adapters/http/httpInvoker";
import type { FlagStore } from "@/adapters/http/webSession";
import { WebApp } from "./WebApp";

function memStore(): FlagStore {
  const map = new Map<string, string>();
  return {
    getItem: (k) => map.get(k) ?? null,
    setItem: (k, v) => void map.set(k, v),
    removeItem: (k) => void map.delete(k),
  };
}

const okFetch: FetchLike = async () => ({
  ok: true,
  status: 200,
  json: async () => ({ ok: true }),
  text: async () => "{}",
});

async function seededGateways(): Promise<Gateways> {
  const gateways = createMockGateways();
  await gateways.project.createProject("Demo", "/srv/demo");
  return gateways;
}

function renderPairedWebApp(gateways: Gateways) {
  const session = new WebSession({ baseUrl: "https://h", fetchImpl: okFetch, store: memStore() });
  session.markPaired();
  return render(
    <DIProvider gateways={gateways}>
      <WebApp session={session} />
    </DIProvider>,
  );
}

describe("WebWorkspace « Panneaux » menu (#90)", () => {
  it("only enables Projets while no project is open, with a help note", async () => {
    renderPairedWebApp(await seededGateways());

    fireEvent.click(await screen.findByRole("button", { name: "Panneaux : Projets" }));
    expect(
      await screen.findByText("Ouvrir un projet pour utiliser ce panneau."),
    ).toBeTruthy();

    const contextEntry = screen.getByRole("button", { name: "Contexte projet" });
    expect(contextEntry).toHaveProperty("disabled", true);
    const projectsEntry = screen.getByRole("button", { name: "Projets" });
    expect(projectsEntry).toHaveProperty("disabled", false);

    // A disabled entry does nothing.
    fireEvent.click(contextEntry);
    expect(screen.queryByText("Contexte projet")).toBeTruthy(); // sheet still open, menu entry still there
  });

  it("routes the main surface to the selected panel once a project is open", async () => {
    renderPairedWebApp(await seededGateways());

    fireEvent.click(await screen.findByText("Demo"));
    expect(await screen.findByRole("button", { name: "Panneaux : Travail" })).toBeTruthy();

    fireEvent.click(screen.getByRole("button", { name: "Panneaux : Travail" }));
    const agentsEntry = await screen.findByRole("button", { name: "Agents" });
    expect(agentsEntry).toHaveProperty("disabled", false);
    fireEvent.click(agentsEntry);

    expect(await screen.findByRole("button", { name: "Panneaux : Agents" })).toBeTruthy();
  });

  it("closes on Escape without changing the panel", async () => {
    renderPairedWebApp(await seededGateways());
    fireEvent.click(await screen.findByText("Demo"));
    await screen.findByRole("button", { name: "Panneaux : Travail" });

    fireEvent.click(screen.getByRole("button", { name: "Panneaux : Travail" }));
    await screen.findByRole("dialog", { name: "Panneaux" });
    fireEvent.keyDown(window, { key: "Escape" });

    expect(screen.queryByRole("dialog", { name: "Panneaux" })).toBeNull();
    expect(screen.getByRole("button", { name: "Panneaux : Travail" })).toBeTruthy();
  });
});

describe("WebProjectsPanel — web project creation (#90)", () => {
  it("creates a project via a manual path and opens it", async () => {
    renderPairedWebApp(await seededGateways());

    await screen.findByText("Demo");
    fireEvent.change(screen.getByLabelText("Nom du projet"), {
      target: { value: "Nouveau" },
    });
    fireEvent.change(screen.getByLabelText("Chemin du projet"), {
      target: { value: "/srv/nouveau" },
    });
    expect(
      screen.getByText("Saisir un chemin absolu accessible depuis le serveur IdeA."),
    ).toBeTruthy();

    fireEvent.click(screen.getByRole("button", { name: "Créer le projet" }));

    // Creating opens it — routes straight to the Travail panel, like opening
    // an existing project from the list.
    expect(await screen.findByRole("button", { name: "Panneaux : Travail" })).toBeTruthy();
  });
});

describe("WebApp « Paramètres » menu (#90)", () => {
  it("opens Profils IA and returns to the workspace via « ← Retour »", async () => {
    renderPairedWebApp(await seededGateways());

    fireEvent.click(await screen.findByRole("button", { name: "Paramètres" }));
    fireEvent.click(await screen.findByRole("button", { name: "Profils IA" }));

    expect(await screen.findByRole("heading", { name: "Profils IA" })).toBeTruthy();
    expect(screen.queryByRole("button", { name: /^Panneaux :/ })).toBeNull();

    fireEvent.click(screen.getByRole("button", { name: "← Retour" }));
    expect(await screen.findByRole("button", { name: /^Panneaux :/ })).toBeTruthy();
  });

  it("opens Appareils from the settings menu", async () => {
    renderPairedWebApp(await seededGateways());

    fireEvent.click(await screen.findByRole("button", { name: "Paramètres" }));
    fireEvent.click(await screen.findByRole("button", { name: "Appareils" }));

    expect(await screen.findByRole("button", { name: "← Retour" })).toBeTruthy();
  });

  it("shows Déploiement as disabled, labelled desktop-only, and does nothing on click", async () => {
    renderPairedWebApp(await seededGateways());

    fireEvent.click(await screen.findByRole("button", { name: "Paramètres" }));
    const deploymentEntry = await screen.findByRole("button", { name: /Déploiement/ });
    expect(deploymentEntry.textContent).toContain("Desktop uniquement");
    expect(deploymentEntry).toHaveProperty("disabled", true);

    fireEvent.click(deploymentEntry);
    // Still on the menu — no navigation happened.
    expect(screen.getByRole("dialog", { name: "Paramètres" })).toBeTruthy();
  });
});
