import { act } from "react";
import { createRoot, type Root } from "react-dom/client";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";

import { Result } from "@/utils/result";

import { FeedbackScreen } from "../feedback-screen";

const mocks = vi.hoisted(() => ({
  replace: vi.fn(),
  submitFeedback: vi.fn(),
}));

vi.mock("@/router/use-global-app-navigator", () => ({
  useGlobalAppNavigator: () => ({ replace: mocks.replace }),
}));

vi.mock("@/lib/feedback", () => ({
  submitFeedback: mocks.submitFeedback,
}));

vi.mock("../feedback-context", () => ({
  createFeedbackContext: () => ({
    appVersion: "test",
    platform: "android",
    browser: "chrome",
    viewport: "390x844@3",
  }),
}));

describe("FeedbackScreen", () => {
  let container: HTMLDivElement;
  let root: Root;

  beforeEach(() => {
    (globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean })
      .IS_REACT_ACT_ENVIRONMENT = true;
    mocks.replace.mockReset();
    mocks.submitFeedback.mockReset();
    container = document.createElement("div");
    document.body.appendChild(container);
    root = createRoot(container);
  });

  afterEach(() => {
    act(() => root.unmount());
    container.remove();
  });

  it("renders all categories and defaults to Problem", () => {
    renderFeedbackScreen(root);

    expect(container.textContent).toContain("Help us improve CozSweet");
    expect(container.textContent).toContain("Problem");
    expect(container.textContent).toContain("Suggestion");
    expect(container.textContent).toContain("Payment");
    expect(container.textContent).toContain("Other");
    expect(
      container.querySelector<HTMLInputElement>('input[value="problem"]')
        ?.checked,
    ).toBe(true);
    expect(container.textContent).toContain(
      "Minimum 10 characters required.",
    );
    expect(
      container
        .querySelector("textarea")
        ?.getAttribute("aria-describedby"),
    ).toBe("feedback-content-hint");
    expect(
      container.querySelector<HTMLAnchorElement>(
        '[data-analytics-key="feedback.back_to_profile"]',
      )?.getAttribute("href"),
    ).toBe("/profile?returnTo=%2Fcharacters%2Fmaya%2Fchat");
  });

  it("submits valid text and renders the feedback id", async () => {
    mocks.submitFeedback.mockResolvedValue(
      Result.ok({ feedbackId: "feedback-123" }),
    );
    renderFeedbackScreen(root);
    const textarea = container.querySelector("textarea");
    if (!textarea) throw new Error("Expected feedback textarea");

    act(() => setTextareaValue(textarea, "The message button stopped working."));
    const submit = container.querySelector<HTMLButtonElement>(
      'button[type="submit"]',
    );
    expect(submit?.disabled).toBe(false);

    await act(async () => {
      submit?.click();
      await Promise.resolve();
    });

    expect(mocks.submitFeedback).toHaveBeenCalledWith({
      category: "problem",
      content: "The message button stopped working.",
      context: {
        appVersion: "test",
        platform: "android",
        browser: "chrome",
        viewport: "390x844@3",
      },
      images: [],
    });
    expect(container.textContent).toContain("feedback-123");
    expect(container.textContent).toContain("Thank you for helping us.");
    expect(container.textContent).toContain("Back to Profile");
  });
});

function renderFeedbackScreen(root: Root): void {
  act(() =>
    root.render(<FeedbackScreen returnTo="/characters/maya/chat" />),
  );
}

function setTextareaValue(element: HTMLTextAreaElement, value: string): void {
  const setter = Object.getOwnPropertyDescriptor(
    HTMLTextAreaElement.prototype,
    "value",
  )?.set;
  setter?.call(element, value);
  element.dispatchEvent(new Event("input", { bubbles: true }));
}
