import { render, screen, fireEvent, waitFor } from "@testing-library/react";
import { describe, it, expect, vi, beforeEach } from "vitest";
import { NextIntlClientProvider } from "next-intl";
import messages from "../messages/de.json";

// Mocks MUST be defined before component import to ensure they are picked up
vi.mock("../components/Reveal", () => ({
  Reveal: ({ children }: any) => <>{children}</>,
  Stagger: ({ children }: any) => <>{children}</>,
}));

// Better FormData mock for happy-dom
global.FormData = class MockFormData {
  private data = new Map();
  constructor(form?: HTMLFormElement) {
    if (form) {
      const elements = form.elements as any;
      for (let i = 0; i < elements.length; i++) {
        const item = elements.item(i);
        if (item.name && item.value) {
          this.data.set(item.name, item.value);
        }
      }
    }
  }
  append(key: string, value: any) {
    this.data.set(key, value);
  }
  get(key: string) {
    return this.data.get(key);
  }
  entries() {
    return Array.from(this.data.entries())[Symbol.iterator]();
  }
} as any;

// Mock alert
const alertMock = vi.fn();
global.alert = alertMock;

// Import component AFTER mocks
import Contact from "../components/ContactContent";

// Mock fetch
const fetchMock = vi.fn();
global.fetch = fetchMock;

const renderContact = () => {
  return render(
    <NextIntlClientProvider locale="de" messages={messages}>
      <Contact />
    </NextIntlClientProvider>,
  );
};

describe("Contact Page", () => {
  beforeEach(() => {
    vi.clearAllMocks();
    fetchMock.mockReset();
    fetchMock.mockResolvedValue({
      ok: true,
      json: async () => ({ success: true }),
    });
  });

  it("renders the contact form correctly", () => {
    renderContact();

    expect(screen.getByLabelText(/Name \*/i)).toBeInTheDocument();
    expect(screen.getByLabelText(/Firma/i)).toBeInTheDocument();
    expect(screen.getByLabelText(/E-Mail \*/i)).toBeInTheDocument();
    expect(screen.getByLabelText(/Nachricht \*/i)).toBeInTheDocument();
  });

  it("submits the form successfully", async () => {
    renderContact();

    fireEvent.change(screen.getByLabelText(/Name \*/i), {
      target: { value: "John Doe" },
    });
    fireEvent.change(screen.getByLabelText(/E-Mail \*/i), {
      target: { value: "john@example.com" },
    });
    fireEvent.change(screen.getByLabelText(/Nachricht \*/i), {
      target: { value: "This is a test message that is long enough." },
    });

    const form = screen.getByRole("form");
    fireEvent.submit(form);

    await waitFor(
      () => {
        expect(fetchMock).toHaveBeenCalled();
      },
      { timeout: 2000 },
    );

    expect(
      (await screen.findAllByText(/Anfrage erfolgreich übermittelt/i)).length,
    ).toBeGreaterThanOrEqual(1);
    expect(
      (await screen.findAllByText(/Ihr Anliegen wurde erfasst/i)).length,
    ).toBeGreaterThanOrEqual(1);
  });

  it("handles submission errors", async () => {
    fetchMock.mockResolvedValueOnce({
      ok: false,
      json: async () => ({ error: "Server error" }),
    });

    renderContact();

    fireEvent.change(screen.getByLabelText(/Name \*/i), {
      target: { value: "John Doe" },
    });
    fireEvent.change(screen.getByLabelText(/E-Mail \*/i), {
      target: { value: "john@example.com" },
    });
    fireEvent.change(screen.getByLabelText(/Nachricht \*/i), {
      target: { value: "This is a test message." },
    });

    const form = screen.getByRole("form");
    fireEvent.submit(form);

    expect(await screen.findByText(/Server error/i)).toBeInTheDocument();
  });
});
