// @vitest-environment jsdom

import { cleanup, fireEvent, render, screen, waitFor } from "@testing-library/react";
import type { ReactNode } from "react";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { jsonError, jsonOk } from "@/test/api-mock";
import ObservePage from "./page";
import {
  makeLogsPayload,
  makeSummaryPayload,
  makeTrendMetric,
  makeTrendsPayload,
  makeTrendsRegion,
  mockObserveApis,
} from "./test-helpers";

let searchParams = new URLSearchParams("");
const lineRenderSpy = vi.hoisted(() => vi.fn());

vi.mock("next/navigation", () => ({
  useSearchParams: () => searchParams,
}));

vi.mock("recharts", () => ({
  ResponsiveContainer: ({ children }: { children: ReactNode }) => (
    <div data-testid="responsive-container">{children}</div>
  ),
  LineChart: ({ children }: { children: ReactNode }) => <div>{children}</div>,
  Line: ({ name }: { name: string }) => {
    lineRenderSpy(name);
    return <div>{name}</div>;
  },
  XAxis: () => <div />,
  YAxis: () => <div />,
  CartesianGrid: () => <div />,
  Tooltip: () => <div />,
}));

describe("ObservePage smoke", () => {
  beforeEach(() => {
    cleanup();
    vi.restoreAllMocks();
    lineRenderSpy.mockClear();
    searchParams = new URLSearchParams("");
  });

  it("shows region selection guidance when no region is selected", () => {
    render(<ObservePage />);

    expect(screen.getByText("Observe")).toBeInTheDocument();
    expect(screen.getByText("Select regions first")).toBeInTheDocument();
    const guidance = screen.getByText("Choose regions on the Regions page, then return to this workflow.");
    expect(guidance).toBeInTheDocument();
    expect(guidance.closest("section")).toHaveClass("max-w-lg");
    expect(guidance.closest("section")).not.toHaveClass("max-w-2xl");
    expect(screen.getByRole("link", { name: "Go to Regions" })).toHaveAttribute("href", "/regions");
  });

  it("renders summary, trends and logs sections for selected regions", async () => {
    searchParams = new URLSearchParams(
      `regions=${encodeURIComponent("nextgen:aws:prod:prod-aws-us-west-2-ng")}`
    );
    mockObserveApis({
      summary: makeSummaryPayload(),
      trends: makeTrendsPayload({
        regions: [
          makeTrendsRegion({
            regionId: "nextgen:aws:prod:prod-aws-us-west-2-ng",
            regionName: "us-west-2-ng",
            status: "ready",
          }),
        ],
        metrics: [makeTrendMetric({ metricKey: "cpuRequestUsage" })],
      }),
      logs: makeLogsPayload(),
    });

    render(<ObservePage />);

    const switcher = screen.getByRole("navigation", { name: "Observe views" });
    expect(switcher).toBeInTheDocument();
    expect(screen.getByRole("link", { name: "Observe" })).toHaveAttribute("aria-current", "page");
    expect(screen.getByRole("link", { name: "Agents" })).toHaveAttribute(
      "href",
      `/agents?regions=${encodeURIComponent("nextgen:aws:prod:prod-aws-us-west-2-ng")}`
    );
    expect(screen.queryByRole("link", { name: "View Agents" })).not.toBeInTheDocument();

    await waitFor(() => {
      expect(screen.getByTestId("summary-section")).toBeInTheDocument();
      expect(screen.getByTestId("trends-section")).toBeInTheDocument();
      expect(screen.getByTestId("logs-section")).toBeInTheDocument();
    });

    expect(screen.getByRole("button", { name: "Refresh Summary" })).toBeInTheDocument();
    expect(screen.getByRole("button", { name: "Refresh Trends" })).toBeInTheDocument();
    expect(screen.getByRole("button", { name: "Refresh Logs" })).toBeInTheDocument();
  });

  it("shows section request error banners independently", async () => {
    searchParams = new URLSearchParams(
      `regions=${encodeURIComponent("nextgen:aws:prod:prod-aws-us-west-2-ng")}`
    );

    vi.stubGlobal(
      "fetch",
      vi.fn(async (input: RequestInfo | URL) => {
        const inputText = String(input);
        if (inputText.endsWith("/api/observe/acs/summary")) {
          return jsonError("INTERNAL", "summary failed");
        }
        if (inputText.endsWith("/api/observe/acs/resource-trends")) {
          return jsonError("INTERNAL", "trends failed");
        }
        if (inputText.endsWith("/api/observe/acs/logs")) {
          return jsonError("INTERNAL", "logs failed");
        }
        return jsonOk({});
      })
    );

    render(<ObservePage />);

    await waitFor(() => {
      expect(screen.getByText("Failed to load Summary")).toBeInTheDocument();
      expect(screen.getByText("summary failed")).toBeInTheDocument();
      expect(screen.getByText("Failed to load Trends")).toBeInTheDocument();
      expect(screen.getByText("trends failed")).toBeInTheDocument();
      expect(screen.getByText("Failed to load Logs")).toBeInTheDocument();
      expect(screen.getByText("logs failed")).toBeInTheDocument();
    });
  });

  it("keeps other observe blocks visible while summary is still loading", async () => {
    searchParams = new URLSearchParams(
      `regions=${encodeURIComponent("nextgen:aws:prod:prod-aws-us-west-2-ng")}`
    );

    vi.stubGlobal(
      "fetch",
      vi.fn(async (input: RequestInfo | URL) => {
        const inputText = String(input);
        if (inputText.endsWith("/api/observe/acs/summary")) {
          return new Promise<Response>(() => {});
        }
        if (inputText.endsWith("/api/observe/acs/resource-trends")) {
          return new Response(
            JSON.stringify({
              ok: true,
              data: makeTrendsPayload({
                regions: [
                  makeTrendsRegion({
                    regionId: "nextgen:aws:prod:prod-aws-us-west-2-ng",
                    regionName: "us-west-2-ng",
                    status: "ready",
                  }),
                ],
                metrics: [makeTrendMetric({ metricKey: "cpuRequestUsage" })],
              }),
            }),
            { status: 200, headers: { "Content-Type": "application/json" } }
          );
        }
        if (inputText.endsWith("/api/observe/acs/logs")) {
          return jsonOk(makeLogsPayload());
        }
        return jsonOk({});
      })
    );

    render(<ObservePage />);

    expect(screen.getByTestId("summary-loading")).toContainElement(
      screen.getByRole("progressbar", { name: "Loading Summary" })
    );
    expect(screen.queryByText("Loading Summary")).not.toBeInTheDocument();
    expect(
      screen.queryByText("Summary metrics are still loading. Other observe blocks can continue independently.")
    ).not.toBeInTheDocument();
    await waitFor(() => {
      expect(screen.getByTestId("trends-section")).toBeInTheDocument();
      expect(screen.getByText("CPU Request Usage")).toBeInTheDocument();
      expect(screen.getByTestId("logs-section")).toBeInTheDocument();
      expect(screen.getByText("LogQL")).toBeInTheDocument();
    });
  });

  it("wires logs filter controls to refresh payload", async () => {
    searchParams = new URLSearchParams(
      `regions=${encodeURIComponent("nextgen:aws:prod:prod-aws-us-west-2-ng")}`
    );
    const fetchMock = mockObserveApis({
      summary: makeSummaryPayload(),
      trends: makeTrendsPayload(),
      logs: makeLogsPayload(),
    });

    render(<ObservePage />);

    await waitFor(() => {
      expect(screen.getByTestId("logs-section")).toBeInTheDocument();
    });

    fireEvent.change(screen.getByLabelText("Logs filter mode"), {
      target: { value: "exclude" },
    });
    fireEvent.change(screen.getByLabelText("Logs filter keyword"), {
      target: { value: "timeout" },
    });
    fireEvent.click(screen.getByRole("button", { name: "Refresh Logs" }));

    await waitFor(() => {
      expect(
        fetchMock.mock.calls.some(([input, init]) => {
          const body = init?.body ? JSON.parse(String(init.body)) : {};
          return (
            String(input).endsWith("/api/observe/acs/logs") &&
            body.lineFilterMode === "exclude" &&
            body.lineFilterKeyword === "timeout"
          );
        })
      ).toBe(true);
    });
  });

  it("does not rerender trends while typing in the logs keyword filter", async () => {
    searchParams = new URLSearchParams(
      `regions=${encodeURIComponent("nextgen:aws:prod:prod-aws-us-west-2-ng")}`
    );
    mockObserveApis({
      summary: makeSummaryPayload(),
      trends: makeTrendsPayload({
        regions: [
          makeTrendsRegion({
            regionId: "nextgen:aws:prod:prod-aws-us-west-2-ng",
            regionName: "us-west-2-ng",
            status: "ready",
          }),
        ],
        metrics: [makeTrendMetric({ metricKey: "cpuRequestUsage" })],
      }),
      logs: makeLogsPayload(),
    });

    render(<ObservePage />);

    await waitFor(() => {
      expect(screen.getByText("CPU Request Usage")).toBeInTheDocument();
      expect(screen.getByTestId("logs-section")).toBeInTheDocument();
    });

    lineRenderSpy.mockClear();
    fireEvent.change(screen.getByLabelText("Logs filter keyword"), {
      target: { value: "timeout" },
    });

    expect(lineRenderSpy).not.toHaveBeenCalled();
  });
});
