// @vitest-environment jsdom

import { cleanup, fireEvent, render, screen, waitFor } from "@testing-library/react";
import { beforeEach, describe, expect, it, vi } from "vitest";
import BumpPage from "./page";
import {
  makeRegion,
  makeRegionsPayload,
  mockBumpApis,
  sseCompleteResponse,
} from "./test-helpers";

const navigationMock = vi.hoisted(() => ({
  searchParams: new URLSearchParams(""),
}));

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

describe("BumpPage smoke", () => {
  beforeEach(() => {
    cleanup();
    vi.restoreAllMocks();
    navigationMock.searchParams = new URLSearchParams("");
  });

  it("shows empty state when regions are not selected", async () => {
    mockBumpApis({
      regions: makeRegionsPayload([
        makeRegion({ id: "r-source", regionName: "us-west-2" }),
      ]),
    });

    render(<BumpPage />);

    await waitFor(() => {
      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("runs a minimal image bump preview path for selected regions", async () => {
    navigationMock.searchParams = new URLSearchParams("regions=r-source,r-target");

    const fetchMock = mockBumpApis({
      regions: makeRegionsPayload([
        makeRegion({
          id: "r-source",
          architecture: "nextgen",
          environment: "prod",
          provider: "aws",
          regionName: "us-west-2",
          currentTag: "sha1",
          componentTags: { acs: "sha1", vector: "v1", vmagent: "m1" },
        }),
        makeRegion({
          id: "r-target",
          architecture: "dedicated",
          environment: "staging",
          provider: "gcp",
          regionName: "us-central-1",
          currentTag: "sha2",
          componentTags: { acs: "sha2", vector: "v2", vmagent: "m2" },
        }),
      ]),
      preview: {
        ok: true,
        data: {
          diffs: [
            {
              regionId: "r-source",
              filePath: "envs/prod-aws-us-west-2/values.yaml",
              oldTag: "sha1",
              newTag: "42eb00ed5e35798039d87f78c71a3a43d2eb9acb",
              patch: "@@ -1 +1 @@",
            },
          ],
          filesAffected: 1,
          regionsAffected: 1,
          previewToken: "ptok",
          previewHash: "phash",
        },
      },
      bump: sseCompleteResponse("creating pr"),
    });

    render(<BumpPage />);

    await waitFor(() => {
      expect(screen.getByText("Select the component to bump:")).toBeInTheDocument();
    });

    fireEvent.click(screen.getByRole("button", { name: /ACS Agent Control Server/i }));

    await waitFor(() => {
      expect(screen.getByLabelText("Target Version (ACS)")).toBeInTheDocument();
    });

    fireEvent.change(screen.getByLabelText("Target Version (ACS)"), {
      target: { value: "42eb00ed5e35798039d87f78c71a3a43d2eb9acb" },
    });
    fireEvent.click(screen.getByRole("button", { name: "Preview Changes" }));

    await waitFor(() => {
      expect(screen.getByText("PR Summary")).toBeInTheDocument();
    });

    fireEvent.click(screen.getByRole("button", { name: "Confirm & Create PR" }));

    await waitFor(() => {
      expect(
        fetchMock.mock.calls.some(([input]) => String(input).includes("/api/bump"))
      ).toBe(true);
    });

    const previewCall = fetchMock.mock.calls.find(([input]) =>
      String(input).includes("/api/preview")
    );
    const bumpCall = fetchMock.mock.calls.find(([input]) =>
      String(input).includes("/api/bump")
    );

    expect(JSON.parse(String(previewCall?.[1]?.body))).toMatchObject({
      regionIds: ["r-source", "r-target"],
      targetTag: "42eb00ed5e35798039d87f78c71a3a43d2eb9acb",
      component: "acs",
      updateVariants: true,
    });
    expect(JSON.parse(String(bumpCall?.[1]?.body))).toMatchObject({
      regionIds: ["r-source", "r-target"],
      targetTag: "42eb00ed5e35798039d87f78c71a3a43d2eb9acb",
      component: "acs",
    });
  });

  it("wires file sync source, preview, and execute target set", async () => {
    navigationMock.searchParams = new URLSearchParams("regions=r-source,r-target");

    const fetchMock = mockBumpApis({
      regions: makeRegionsPayload([
        makeRegion({ id: "r-source", regionName: "us-west-2" }),
        makeRegion({ id: "r-target", regionName: "us-east-1" }),
      ]),
      fileSyncSourceStatus: {
        ok: true,
        data: {
          sourceRegionId: "r-source",
          files: [
            {
              sourceFile: "config.yaml",
              hasDiff: true,
              sourceBeforeHash: "before",
              sourceAfterHash: "after",
            },
          ],
        },
      },
      fileSyncPreview: {
        ok: true,
        data: {
          previewToken: {
            id: "config-token",
            sourceAfterHash: { "config.yaml": "after" },
          },
          perRegionPreview: [
            {
              regionId: "r-target",
              ok: true,
              diffs: [
                {
                  filePath: "envs/r-target/config.yaml",
                  path: "agent.replicas",
                  op: "replace",
                  oldValue: 1,
                  newValue: 2,
                },
              ],
            },
          ],
          summary: {
            totalTargets: 1,
            applicableTargets: 1,
            failedTargets: 0,
            totalChanges: 1,
          },
        },
      },
      fileSyncExecute: sseCompleteResponse("applying config"),
    });

    render(<BumpPage />);

    fireEvent.click(await screen.findByRole("button", { name: "File Sync" }));
    fireEvent.click(await screen.findByRole("option", { name: /us-west-2/i }));

    await waitFor(() => {
      expect(screen.getByText("Has supported diff")).toBeInTheDocument();
    });

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

    await waitFor(() => {
      expect(screen.getByText("Confirm & Apply")).toBeInTheDocument();
    });

    fireEvent.click(screen.getByRole("button", { name: "Confirm & Apply" }));

    await waitFor(() => {
      expect(
        fetchMock.mock.calls.some(([input]) =>
          String(input).includes("/api/file-sync/execute")
        )
      ).toBe(true);
    });

    const sourceStatusCall = fetchMock.mock.calls.find(([input]) =>
      String(input).includes("/api/file-sync/source-status")
    );
    const previewCall = fetchMock.mock.calls.find(([input]) =>
      String(input).includes("/api/file-sync/preview")
    );
    const executeCall = fetchMock.mock.calls.find(([input]) =>
      String(input).includes("/api/file-sync/execute")
    );

    expect(String(sourceStatusCall?.[0])).toContain("sourceRegionId=r-source");
    expect(JSON.parse(String(previewCall?.[1]?.body))).toMatchObject({
      sourceRegionId: "r-source",
      targetRegionIds: ["r-target"],
      selectedFiles: ["config.yaml"],
    });
    expect(JSON.parse(String(executeCall?.[1]?.body))).toMatchObject({
      previewTokenId: "config-token",
      targetRegionIds: ["r-target"],
    });
  });

  it("wires file sync execute for deployment.yaml", async () => {
    navigationMock.searchParams = new URLSearchParams("regions=r-source,r-target");

    const fetchMock = mockBumpApis({
      regions: makeRegionsPayload([
        makeRegion({ id: "r-source", regionName: "us-west-2" }),
        makeRegion({ id: "r-target", regionName: "us-east-1" }),
      ]),
      fileSyncSourceStatus: {
        ok: true,
        data: {
          sourceRegionId: "r-source",
          files: [
            {
              sourceFile: "deployment.yaml",
              hasDiff: true,
              sourceBeforeHash: "before",
              sourceAfterHash: "after",
            },
          ],
        },
      },
      fileSyncPreview: {
        ok: true,
        data: {
          previewToken: {
            id: "deployment-token",
            sourceAfterHash: { "deployment.yaml": "after" },
            imageTagCheckApplicable: true,
            acsImageTagAfter: "42eb00ed5e35798039d87f78c71a3a43d2eb9acb",
          },
          perRegionPreview: [
            {
              regionId: "r-target",
              ok: true,
              diffs: [
                {
                  filePath: "envs/r-target/deployment.yaml",
                  path: "spec.template.spec.containers[0].image",
                  op: "replace",
                  oldValue: "old",
                  newValue: "new",
                },
              ],
            },
          ],
          summary: {
            totalTargets: 1,
            applicableTargets: 1,
            failedTargets: 0,
            totalChanges: 1,
          },
        },
      },
      fileSyncExecute: sseCompleteResponse("applying deployment"),
    });

    render(<BumpPage />);

    fireEvent.click(await screen.findByRole("button", { name: "File Sync" }));
    fireEvent.click(await screen.findByRole("option", { name: /us-west-2/i }));

    await waitFor(() => {
      expect(screen.getByText("Has supported diff")).toBeInTheDocument();
    });

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

    await waitFor(() => {
      expect(screen.getByText("Confirm & Apply")).toBeInTheDocument();
    });

    fireEvent.click(screen.getByRole("button", { name: "Confirm & Apply" }));

    await waitFor(() => {
      expect(
        fetchMock.mock.calls.some(([input]) =>
          String(input).includes("/api/file-sync/execute")
        )
      ).toBe(true);
    });

    const previewCall = fetchMock.mock.calls.find(([input]) =>
      String(input).includes("/api/file-sync/preview")
    );
    const executeCall = fetchMock.mock.calls.find(([input]) =>
      String(input).includes("/api/file-sync/execute")
    );

    expect(JSON.parse(String(previewCall?.[1]?.body))).toMatchObject({
      sourceRegionId: "r-source",
      targetRegionIds: ["r-target"],
      selectedFiles: ["deployment.yaml"],
    });
    expect(JSON.parse(String(executeCall?.[1]?.body))).toMatchObject({
      previewTokenId: "deployment-token",
      targetRegionIds: ["r-target"],
    });
  });
});
