// @vitest-environment jsdom

import { cleanup, fireEvent, render, screen, waitFor } from "@testing-library/react";
import { beforeEach, describe, expect, it, vi } from "vitest";
import DashboardPage from "./page";

let fetchMock: ReturnType<typeof vi.fn>;

const regionsFixture = [
  {
    id: "r-prod-a",
    architecture: "nextgen",
    environment: "prod",
    provider: "aws",
    regionName: "prod-a",
    directoryPath: "envs/prod-a",
    currentTag: "42eb00e",
    imageRegistry: "registry",
    componentTags: { acs: "42eb00e", vector: "v2", vmagent: "m2" },
  },
  {
    id: "r-prod-b",
    architecture: "nextgen",
    environment: "prod",
    provider: "gcp",
    regionName: "prod-b",
    directoryPath: "envs/prod-b",
    currentTag: "42eb00e",
    imageRegistry: "registry",
    componentTags: { acs: "42eb00e", vector: null, vmagent: "m2" },
  },
  {
    id: "r-prod-c",
    architecture: "nextgen",
    environment: "prod",
    provider: "azure",
    regionName: "prod-c",
    directoryPath: "envs/prod-c",
    currentTag: "42eb00e",
    imageRegistry: "registry",
    componentTags: { acs: null, vector: "v2", vmagent: "m2" },
  },
  {
    id: "r-staging-a",
    architecture: "nextgen",
    environment: "staging",
    provider: "aws",
    regionName: "staging-a",
    directoryPath: "envs/staging-a",
    currentTag: "42eb00e",
    imageRegistry: "registry",
    componentTags: { acs: "42eb00e", vector: "v1", vmagent: "m1" },
  },
  {
    id: "r-dev-a",
    architecture: "nextgen",
    environment: "dev",
    provider: "aws",
    regionName: "dev-a",
    directoryPath: "envs/dev-a",
    currentTag: "42eb00e",
    imageRegistry: "registry",
    componentTags: { acs: "42eb00e", vector: null, vmagent: null },
  },
];

describe("Dashboard version stats", () => {
  beforeEach(() => {
    cleanup();
    vi.restoreAllMocks();

    fetchMock = vi.fn(async (input: RequestInfo | URL) => {
      const url = String(input);

      if (url.includes("/api/git/status")) {
        return new Response(
          JSON.stringify({
            ok: true,
            data: {
              currentBranch: "main",
              isDirty: false,
              ahead: 0,
              behind: 0,
              remoteBranch: "origin/main",
              remoteCommit: "abc1234",
              repoPath: "/repo",
              lastCommit: { hash: "abc1234", message: "msg", date: new Date().toISOString() },
            },
          }),
          { status: 200, headers: { "Content-Type": "application/json" } }
        );
      }

      if (url.includes("/api/regions")) {
        return new Response(
          JSON.stringify({
            ok: true,
            data: {
              regions: regionsFixture,
              scannedAt: new Date().toISOString(),
              totalRegions: regionsFixture.length,
            },
          }),
          { status: 200, headers: { "Content-Type": "application/json" } }
        );
      }

      if (url.includes("/api/version-stats")) {
        return new Response(
          JSON.stringify({
            ok: true,
            data: {
              scannedAt: new Date().toISOString(),
              stats: {
                acs: {
                  prod: {
                    totalRegions: 3,
                    unknownCount: 1,
                    versions: [
                      { version: "42eb00e", count: 2, ratio: 2 / 3 },
                    ],
                  },
                  staging: { totalRegions: 1, unknownCount: 0, versions: [{ version: "42eb00e", count: 1, ratio: 1 }] },
                  dev: { totalRegions: 1, unknownCount: 0, versions: [{ version: "42eb00e", count: 1, ratio: 1 }] },
                },
                vector: {
                  prod: { totalRegions: 3, unknownCount: 1, versions: [{ version: "v2", count: 2, ratio: 2 / 3 }] },
                  staging: { totalRegions: 1, unknownCount: 0, versions: [{ version: "v1", count: 1, ratio: 1 }] },
                  dev: { totalRegions: 1, unknownCount: 1, versions: [] },
                },
                vmagent: {
                  prod: { totalRegions: 3, unknownCount: 0, versions: [{ version: "m2", count: 3, ratio: 1 }] },
                  staging: { totalRegions: 1, unknownCount: 0, versions: [{ version: "m1", count: 1, ratio: 1 }] },
                  dev: { totalRegions: 1, unknownCount: 1, versions: [] },
                },
              },
            },
          }),
          { status: 200, headers: { "Content-Type": "application/json" } }
        );
      }

      return new Response(
        JSON.stringify({ ok: false, error: { code: "NOT_MOCKED", message: "not mocked" } }),
        { status: 500, headers: { "Content-Type": "application/json" } }
      );
    });

    vi.stubGlobal(
      "fetch",
      fetchMock
    );
  });

  it("keeps dashboard stat labels inline with their values", async () => {
    render(<DashboardPage />);

    await waitFor(() => {
      expect(screen.getByText("Version Stats")).toBeInTheDocument();
    });

    for (const label of ["Total Regions", "Dedicated", "NextGen", "Serverless"]) {
      const statLabel = screen.getByText(label);
      const statValue = statLabel.parentElement?.querySelector(".text-3xl");

      if (!statValue) {
        throw new Error(`Expected ${label} value to render`);
      }

      expect(statLabel).toHaveClass("text-xs", "uppercase");
      expect(statValue).toHaveClass("text-3xl");
      expect(statLabel.parentElement).toBe(statValue.parentElement);
      expect(statLabel.parentElement).toHaveClass("flex", "items-baseline", "gap-2");
      expect(statLabel).not.toHaveClass("mt-1");
      expect(statLabel.closest(".bg-surface-0")).toHaveClass("px-4", "py-3");
    }
  });

  it("shows the current branch latest commit time in the sync row", async () => {
    fetchMock.mockImplementation(async (input: RequestInfo | URL) => {
      const url = String(input);

      if (url.includes("/api/git/status")) {
        return new Response(
          JSON.stringify({
            ok: true,
            data: {
              currentBranch: "main",
              isDirty: false,
              ahead: 0,
              behind: 0,
              remoteBranch: "origin/main",
              remoteCommit: "abc1234",
              repoPath: "/repo",
              lastCommit: {
                hash: "abc1234",
                message: "msg",
                date: "2026-06-04T03:15:30.000Z",
              },
            },
          }),
          { status: 200, headers: { "Content-Type": "application/json" } }
        );
      }

      if (url.includes("/api/regions")) {
        return new Response(
          JSON.stringify({
            ok: true,
            data: {
              regions: regionsFixture,
              scannedAt: new Date().toISOString(),
              totalRegions: regionsFixture.length,
            },
          }),
          { status: 200, headers: { "Content-Type": "application/json" } }
        );
      }

      if (url.includes("/api/version-stats")) {
        return new Response(
          JSON.stringify({
            ok: true,
            data: {
              scannedAt: new Date().toISOString(),
              stats: {
                acs: {
                  prod: { totalRegions: 0, unknownCount: 0, versions: [] },
                  staging: { totalRegions: 0, unknownCount: 0, versions: [] },
                  dev: { totalRegions: 0, unknownCount: 0, versions: [] },
                },
                vector: {
                  prod: { totalRegions: 0, unknownCount: 0, versions: [] },
                  staging: { totalRegions: 0, unknownCount: 0, versions: [] },
                  dev: { totalRegions: 0, unknownCount: 0, versions: [] },
                },
                vmagent: {
                  prod: { totalRegions: 0, unknownCount: 0, versions: [] },
                  staging: { totalRegions: 0, unknownCount: 0, versions: [] },
                  dev: { totalRegions: 0, unknownCount: 0, versions: [] },
                },
              },
            },
          }),
          { status: 200, headers: { "Content-Type": "application/json" } }
        );
      }

      return new Response(
        JSON.stringify({ ok: false, error: { code: "NOT_MOCKED", message: "not mocked" } }),
        { status: 500, headers: { "Content-Type": "application/json" } }
      );
    });

    render(<DashboardPage />);

    await waitFor(() => {
      expect(screen.getByText("2026-06-04 11:15 UTC+8")).toBeInTheDocument();
    });
    const timeLabel = screen.getByText("Time");
    const messageLabel = screen.getByText("Message");
    expect(timeLabel).toBeInTheDocument();
    expect(timeLabel.compareDocumentPosition(messageLabel)).toBe(Node.DOCUMENT_POSITION_FOLLOWING);
    expect(screen.queryByText("Latest")).not.toBeInTheDocument();
    expect(screen.queryByText("commit time")).not.toBeInTheDocument();
    expect(screen.queryByText("Latest commit:")).not.toBeInTheDocument();
    expect(screen.queryByText("Sync", { selector: "span" })).not.toBeInTheDocument();
    expect(screen.queryByText("Up to date with origin/main")).not.toBeInTheDocument();
    expect(screen.getByRole("button", { name: "Sync" })).toBeInTheDocument();
    expect(screen.getByText("msg")).toHaveClass("text-text-secondary");
  });

  it("syncs repository status without rendering origin main divergence text", async () => {
    fetchMock.mockImplementation(async (input: RequestInfo | URL, init?: RequestInit) => {
      const url = String(input);

      if (url.includes("/api/git/status")) {
        return new Response(
          JSON.stringify({
            ok: true,
            data: {
              currentBranch: "main",
              isDirty: false,
              ahead: 0,
              behind: 3,
              remoteBranch: "origin/main",
              remoteCommit: "def5678",
              repoPath: "/repo",
              lastCommit: { hash: "abc1234", message: "msg", date: "2026-06-04T03:15:30.000Z" },
            },
          }),
          { status: 200, headers: { "Content-Type": "application/json" } }
        );
      }

      if (url.includes("/api/git/sync") && init?.method === "POST") {
        return new Response(
          JSON.stringify({
            ok: true,
            data: {
              currentBranch: "main",
              isDirty: false,
              ahead: 0,
              behind: 0,
              remoteBranch: "origin/main",
              remoteCommit: "def5678",
              repoPath: "/repo",
              lastCommit: { hash: "def5678", message: "remote msg", date: "2026-06-04T04:20:30.000Z" },
            },
          }),
          { status: 200, headers: { "Content-Type": "application/json" } }
        );
      }

      if (url.includes("/api/regions")) {
        return new Response(
          JSON.stringify({
            ok: true,
            data: {
              regions: regionsFixture,
              scannedAt: new Date().toISOString(),
              totalRegions: regionsFixture.length,
            },
          }),
          { status: 200, headers: { "Content-Type": "application/json" } }
        );
      }

      if (url.includes("/api/version-stats")) {
        return new Response(
          JSON.stringify({
            ok: true,
            data: {
              scannedAt: new Date().toISOString(),
              stats: {
                acs: {
                  prod: { totalRegions: 0, unknownCount: 0, versions: [] },
                  staging: { totalRegions: 0, unknownCount: 0, versions: [] },
                  dev: { totalRegions: 0, unknownCount: 0, versions: [] },
                },
                vector: {
                  prod: { totalRegions: 0, unknownCount: 0, versions: [] },
                  staging: { totalRegions: 0, unknownCount: 0, versions: [] },
                  dev: { totalRegions: 0, unknownCount: 0, versions: [] },
                },
                vmagent: {
                  prod: { totalRegions: 0, unknownCount: 0, versions: [] },
                  staging: { totalRegions: 0, unknownCount: 0, versions: [] },
                  dev: { totalRegions: 0, unknownCount: 0, versions: [] },
                },
              },
            },
          }),
          { status: 200, headers: { "Content-Type": "application/json" } }
        );
      }

      return new Response(
        JSON.stringify({ ok: false, error: { code: "NOT_MOCKED", message: "not mocked" } }),
        { status: 500, headers: { "Content-Type": "application/json" } }
      );
    });

    render(<DashboardPage />);

    await waitFor(() => {
      expect(screen.getByText("2026-06-04 11:15 UTC+8")).toBeInTheDocument();
    });
    expect(screen.queryByText("3 commits behind origin/main")).not.toBeInTheDocument();
    expect(screen.getByText("origin/main@def5678")).toBeInTheDocument();

    fireEvent.click(screen.getByRole("button", { name: "Sync" }));

    await waitFor(() => {
      expect(screen.getByText("2026-06-04 12:20 UTC+8")).toBeInTheDocument();
    });
    expect(screen.queryByText("Up to date with origin/main")).not.toBeInTheDocument();
    expect(screen.queryByText("Synced with origin/main")).not.toBeInTheDocument();

    expect(
      fetchMock.mock.calls.some(([input, init]) => String(input).includes("/api/git/sync") && init?.method === "POST")
    ).toBe(true);
  });

  it("renders component x environment version distributions", async () => {
    render(<DashboardPage />);

    await waitFor(() => {
      expect(screen.getByText("Version Stats")).toBeInTheDocument();
    });

    expect(screen.getByText("ACS")).toBeInTheDocument();
    expect(screen.getByText("Vector")).toBeInTheDocument();
    expect(screen.getByText("VMagent")).toBeInTheDocument();

    expect(screen.getAllByText("prod").length).toBeGreaterThan(0);
    expect(screen.getAllByText("staging").length).toBeGreaterThan(0);
    expect(screen.getAllByText("dev").length).toBeGreaterThan(0);

    expect(screen.getAllByText("42eb00e").length).toBeGreaterThan(0);
    expect(screen.getAllByLabelText(/Show regions for .* unknown/).length).toBeGreaterThan(0);
    expect(screen.getAllByLabelText(/Coverage for .+/).length).toBeGreaterThan(0);
  });

  it("expands selected version regions inline inside the version stats card", async () => {
    render(<DashboardPage />);

    await waitFor(() => {
      expect(screen.getByText("Version Stats")).toBeInTheDocument();
    });

    const versionButton = screen.getByLabelText("Show regions for vector prod version v2");
    fireEvent.click(versionButton);

    await waitFor(() => {
      expect(screen.getByText("prod-a")).toBeInTheDocument();
    });
    expect(versionButton).toHaveClass("bg-success/10", "border-l-4", "border-l-success");
    expect(versionButton).toHaveClass("px-1.5", "py-1");
    expect(versionButton).not.toHaveClass("border-accent/40");
    expect(
      Array.from(versionButton.querySelectorAll("span"))
        .some((element) =>
          element.className.includes("bg-success/10") && element.className.includes("text-success")
        )
    ).toBe(true);
    expect(screen.getByLabelText("Coverage for vector prod v2")).toHaveClass("bg-success/80");
    expect(screen.getByLabelText("Coverage for vector prod v2").parentElement).toHaveClass("mt-1");
    expect(screen.getByRole("columnheader", { name: "Architecture" })).toHaveClass("uppercase", "text-text-muted", "text-[11px]");
    expect(screen.getByRole("columnheader", { name: "Architecture" })).toHaveClass("py-1.5");
    expect(screen.getByRole("columnheader", { name: "Provider" })).toBeInTheDocument();
    expect(screen.getByRole("columnheader", { name: "Region" })).toBeInTheDocument();
    expect(screen.queryByRole("columnheader", { name: "Path" })).not.toBeInTheDocument();
    expect(screen.queryByRole("columnheader", { name: "Region ID" })).not.toBeInTheDocument();
    expect(screen.queryByRole("columnheader", { name: "Name" })).not.toBeInTheDocument();
    expect(screen.queryByText("Vector / prod / v2")).not.toBeInTheDocument();
    expect(screen.queryByLabelText("Close region drilldown")).not.toBeInTheDocument();
    expect(
      screen
        .getAllByText("nextgen")
        .some((element) =>
          element.className.includes("rounded-md") &&
          element.className.includes("border-arch-nextgen/30") &&
          element.className.includes("uppercase") &&
          element.className.includes("text-[11px]")
        )
    ).toBe(true);
    expect(screen.getByText("aws")).not.toHaveClass("rounded-md", "border-surface-2", "uppercase");
    expect(screen.getByText("azure")).not.toHaveClass("rounded-md", "border-surface-2", "uppercase");
    expect(screen.getByText("prod-c")).not.toHaveClass("rounded-md", "border-accent/30");
    expect(screen.getByText("aws").closest("td")).toHaveClass("font-mono", "text-text-secondary");
    expect(screen.getByText("prod-c").closest("td")).toHaveClass("font-mono", "text-text-secondary");
    expect(screen.getByText("aws").closest("table")).toHaveClass("text-xs");
    expect(screen.getByText("prod-a").closest("tr")).toHaveClass("hover:bg-surface-1");
    expect(screen.getByText("prod-a").closest("td")).toHaveClass("py-1.5");
    expect(screen.getByText("prod-a").closest("div")).toHaveClass("max-h-[164px]");
    expect(screen.queryByText("envs/prod-a")).not.toBeInTheDocument();
    expect(screen.queryByText("envs/prod-c")).not.toBeInTheDocument();
    expect(screen.queryByText("prod-b")).not.toBeInTheDocument();

    const unknownButton = screen.getByLabelText("Show regions for vector prod unknown");
    expect(unknownButton).toHaveClass("bg-warning/12", "border-warning/30", "text-warning");
    fireEvent.click(unknownButton);

    await waitFor(() => {
      expect(screen.getByText("prod-b")).toBeInTheDocument();
    });
    expect(unknownButton).toHaveClass("bg-warning/15", "border-warning/40");
    expect(screen.queryByText("Vector / prod / Unknown")).not.toBeInTheDocument();
    expect(screen.queryByText("prod-a")).not.toBeInTheDocument();
  });

  it("retries dashboard load by refetching APIs instead of page reload", async () => {
    let gitStatusCallCount = 0;
    fetchMock.mockImplementation(async (input: RequestInfo | URL) => {
      const url = String(input);
      if (url.includes("/api/git/status")) {
        gitStatusCallCount += 1;
        if (gitStatusCallCount === 1) {
          return new Response(
            JSON.stringify({
              ok: false,
              error: { code: "INTERNAL", message: "git failed" },
            }),
            { status: 500, headers: { "Content-Type": "application/json" } }
          );
        }
        return new Response(
          JSON.stringify({
            ok: true,
            data: {
              currentBranch: "main",
              isDirty: false,
              ahead: 0,
              behind: 0,
              remoteBranch: "origin/main",
              remoteCommit: "abc1234",
              repoPath: "/repo",
              lastCommit: { hash: "abc1234", message: "msg", date: new Date().toISOString() },
            },
          }),
          { status: 200, headers: { "Content-Type": "application/json" } }
        );
      }

      if (url.includes("/api/regions")) {
        return new Response(
          JSON.stringify({
            ok: true,
            data: {
              regions: regionsFixture,
              scannedAt: new Date().toISOString(),
              totalRegions: regionsFixture.length,
            },
          }),
          { status: 200, headers: { "Content-Type": "application/json" } }
        );
      }

      if (url.includes("/api/version-stats")) {
        return new Response(
          JSON.stringify({
            ok: true,
            data: {
              scannedAt: new Date().toISOString(),
              stats: {
                acs: {
                  prod: {
                    totalRegions: 3,
                    unknownCount: 1,
                    versions: [{ version: "42eb00e", count: 2, ratio: 2 / 3 }],
                  },
                  staging: {
                    totalRegions: 1,
                    unknownCount: 0,
                    versions: [{ version: "42eb00e", count: 1, ratio: 1 }],
                  },
                  dev: {
                    totalRegions: 1,
                    unknownCount: 0,
                    versions: [{ version: "42eb00e", count: 1, ratio: 1 }],
                  },
                },
                vector: {
                  prod: {
                    totalRegions: 3,
                    unknownCount: 1,
                    versions: [{ version: "v2", count: 2, ratio: 2 / 3 }],
                  },
                  staging: {
                    totalRegions: 1,
                    unknownCount: 0,
                    versions: [{ version: "v1", count: 1, ratio: 1 }],
                  },
                  dev: { totalRegions: 1, unknownCount: 1, versions: [] },
                },
                vmagent: {
                  prod: {
                    totalRegions: 3,
                    unknownCount: 0,
                    versions: [{ version: "m2", count: 3, ratio: 1 }],
                  },
                  staging: {
                    totalRegions: 1,
                    unknownCount: 0,
                    versions: [{ version: "m1", count: 1, ratio: 1 }],
                  },
                  dev: { totalRegions: 1, unknownCount: 1, versions: [] },
                },
              },
            },
          }),
          { status: 200, headers: { "Content-Type": "application/json" } }
        );
      }

      return new Response(
        JSON.stringify({ ok: false, error: { code: "NOT_MOCKED", message: "not mocked" } }),
        { status: 500, headers: { "Content-Type": "application/json" } }
      );
    });

    render(<DashboardPage />);

    expect(await screen.findByText("git failed")).toBeInTheDocument();

    fireEvent.click(screen.getByRole("button", { name: "Try again" }));

    await waitFor(() => {
      expect(screen.getByText("Version Stats")).toBeInTheDocument();
    });

    const dashboardCalls = fetchMock.mock.calls
      .map(([input]) => String(input))
      .filter(
        (url) =>
          url.includes("/api/git/status") ||
          url.includes("/api/regions") ||
          url.includes("/api/version-stats")
      );
    expect(dashboardCalls.length).toBeGreaterThanOrEqual(6);
  });
});
