import { XProvider } from "@ant-design/x";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { render } from "@testing-library/react";
import { App } from "antd";
import { mock } from "bun:test";
import { createElement, StrictMode } from "react";
import { MemoryRouter } from "react-router";

import { ErrorBoundary } from "../../src/web/shared/components/ErrorBoundary";

const REAL_FETCH = globalThis.fetch.bind(globalThis);

// Mock recharts BEFORE any component imports
void mock.module("recharts", () => ({
  Area: () => null,
  CartesianGrid: () => null,
  Line: () => null,
  LineChart: ({ children }: { children: unknown }) => children,
  ResponsiveContainer: ({ children }: { children: unknown }) => children,
  Tooltip: () => null,
  XAxis: () => null,
  YAxis: () => null,
}));

export interface FetchMockCall {
  body?: BodyInit | null;
  method: string;
  url: string;
}

export interface RenderWithProvidersOptions {
  initialRoute?: string;
}

export function installFetchMock(handler: (call: FetchMockCall) => Promise<Response> | Response): FetchMockCall[] {
  const calls: FetchMockCall[] = [];
  const mocked = (async (input: RequestInfo | URL, init?: RequestInit) => {
    const request = input instanceof Request ? input : undefined;
    const url = request?.url ?? (typeof input === "string" ? input : input instanceof URL ? input.href : input.url);
    if (url.startsWith("http://") || url.startsWith("https://")) return REAL_FETCH(input, init);
    const call: FetchMockCall = {
      body: init?.body ?? null,
      method: init?.method ?? request?.method ?? "GET",
      url,
    };
    calls.push(call);
    return handler(call);
  }) as typeof fetch;

  globalThis.fetch = mocked;
  window.fetch = mocked;
  return calls;
}

export function jsonResponse(body: unknown, init?: ResponseInit): Response {
  const headers = new Headers(init?.headers);
  if (!headers.has("Content-Type")) headers.set("Content-Type", "application/json");
  return new Response(JSON.stringify(body), {
    headers,
    status: init?.status ?? 200,
  });
}

export function mockMetaResponse(): Response {
  return jsonResponse({ ok: true, service: "test-app", timestamp: "2024-01-01T00:00:00.000Z", version: "0.1.0" });
}

export function renderWithProviders(ui: React.ReactElement, options?: RenderWithProvidersOptions) {
  const queryClient = createTestQueryClient();
  const initialRoute = options?.initialRoute ?? "/";

  return render(
    createElement(
      StrictMode,
      null,
      createElement(
        ErrorBoundary,
        null,
        createElement(
          QueryClientProvider,
          { client: queryClient },
          createElement(
            MemoryRouter,
            { initialEntries: [initialRoute] },
            createElement(XProvider, null, createElement(App, null, ui)),
          ),
        ),
      ),
    ),
  );
}

function createTestQueryClient() {
  return new QueryClient({
    defaultOptions: {
      queries: {
        retry: false,
        staleTime: 0,
      },
    },
  });
}
