import { cleanup } from "@testing-library/react";
import { afterEach, vi } from "vitest";
import "@testing-library/jest-dom/vitest";
import React from "react";

afterEach(() => {
  cleanup();
});

// ---------------------------------------------------------------------------
// Global mocks for heavy / browser-only libraries so components render in jsdom.
// (vi.mock in a setup file applies to every test file in the component project.)
// ---------------------------------------------------------------------------

vi.mock("framer-motion", () => {
  const passthrough = (tag: string) =>
    React.forwardRef(function MotionMock(
      { children, ...props }: Record<string, unknown> & { children?: React.ReactNode },
      ref: React.Ref<unknown>,
    ) {
      const domProps: Record<string, unknown> = {};
      for (const [key, value] of Object.entries(props)) {
        // Drop motion-only props that would warn as unknown DOM attributes.
        if (
          /^(initial|animate|exit|transition|variants|whileHover|whileTap|whileInView|whileFocus|whileDrag|drag|layout|layoutId|viewport|custom|onAnimationComplete|style)$/.test(
            key,
          )
        ) {
          if (key === "style") domProps.style = value;
          continue;
        }
        domProps[key] = value;
      }
      return React.createElement(tag, { ...domProps, ref }, children as React.ReactNode);
    });

  const motion = new Proxy(
    {},
    {
      get: (_target, tag: string) => passthrough(tag),
    },
  );

  return {
    motion,
    AnimatePresence: ({ children }: { children?: React.ReactNode }) =>
      React.createElement(React.Fragment, null, children),
    useReducedMotion: () => true,
    useInView: () => true,
    useScroll: () => ({ scrollYProgress: { on: () => () => {}, get: () => 0 } }),
    useTransform: () => 0,
    useMotionValue: (value: unknown) => ({ get: () => value, set: () => {}, on: () => () => {} }),
    useAnimate: () => [React.useRef(null), () => Promise.resolve()],
  };
});

vi.mock("gsap", () => {
  const tween = { kill: () => {}, play: () => {}, pause: () => {}, progress: () => {} };
  const gsap = {
    to: () => tween,
    from: () => tween,
    fromTo: () => tween,
    set: () => tween,
    timeline: () => ({
      to: () => ({}),
      from: () => ({}),
      fromTo: () => ({}),
      add: () => ({}),
      kill: () => {},
    }),
    registerPlugin: () => {},
    context: (fn: () => void) => {
      if (typeof fn === "function") fn();
      return { revert: () => {}, kill: () => {} };
    },
    matchMedia: () => ({ add: () => {}, revert: () => {} }),
    utils: { toArray: (v: unknown) => (Array.isArray(v) ? v : [v]) },
  };
  return { gsap, default: gsap };
});

vi.mock("@gsap/react", () => ({
  useGSAP: () => ({ context: {}, contextSafe: (fn: unknown) => fn }),
}));

vi.mock("next/link", () => ({
  default: React.forwardRef(function LinkMock(
    { href, children, ...props }: Record<string, unknown> & { href?: unknown; children?: React.ReactNode },
    ref: React.Ref<HTMLAnchorElement>,
  ) {
    return React.createElement("a", { href: String(href ?? ""), ref, ...props }, children as React.ReactNode);
  }),
}));

vi.mock("next/image", () => ({
  default: ({ src, alt, ...props }: Record<string, unknown> & { src?: unknown; alt?: string }) =>
    React.createElement("img", { src: String(src ?? ""), alt: alt ?? "", ...props }),
}));

vi.mock("next/navigation", () => ({
  usePathname: () => "/",
  useRouter: () => ({
    push: vi.fn(),
    replace: vi.fn(),
    refresh: vi.fn(),
    back: vi.fn(),
    forward: vi.fn(),
    prefetch: vi.fn(),
  }),
  useSearchParams: () => new URLSearchParams(),
  useParams: () => ({}),
  redirect: vi.fn(),
  notFound: vi.fn(),
}));

vi.mock("next-intl", () => ({
  useTranslations: () => {
    const t = (key: string) => key;
    t.rich = (key: string) => key;
    t.markup = (key: string) => key;
    t.raw = (key: string) => key;
    return t;
  },
  useLocale: () => "de",
  useFormatter: () => ({
    dateTime: (v: Date) => v.toISOString(),
    number: (v: number) => String(v),
    relativeTime: (v: unknown) => String(v),
  }),
  useMessages: () => ({}),
  NextIntlClientProvider: ({ children }: { children?: React.ReactNode }) =>
    React.createElement(React.Fragment, null, children),
}));
