import { describe, it, expect, vi, beforeEach } from "vitest";
import { render, screen } from "@testing-library/react";
import { TEST_RESTAURANT, TEST_RESTAURANT_2 } from "@/__tests__/helpers/fixtures";
import type { ReactNode } from "react";
import React from "react";
import { ToastContext, type ToastContextValue } from "@/hooks/useToast";

vi.mock("next/navigation", () => ({
  useRouter: () => ({ push: vi.fn() }),
}));

vi.mock("@/lib/celebrate", () => ({
  fireCelebration: vi.fn(),
  playChime: vi.fn(),
}));

vi.mock("@/lib/userId", () => ({
  isRegistered: vi.fn().mockReturnValue(true),
}));

vi.mock("./ShareCardModal", () => ({
  default: () => null,
}));

vi.mock("./RestaurantImage", () => ({
  default: ({ alt }: { alt: string }) => <img alt={alt} />,
}));

vi.mock("./AuthModal", () => ({
  default: () => null,
}));

vi.mock("./NoMatchResult", () => ({
  default: ({ onReset }: { onReset: () => void }) => (
    <div data-testid="no-match">
      <button onClick={onReset}>重来</button>
    </div>
  ),
}));

vi.mock("./RunnerUpCard", () => ({
  default: ({ restaurant }: { restaurant: { name: string } }) => (
    <div data-testid="runner-up">{restaurant.name}</div>
  ),
}));

const mockFetch = vi.fn().mockResolvedValue({ ok: true, json: () => Promise.resolve({}) });
vi.stubGlobal("fetch", mockFetch);

import MatchResult from "./MatchResult";

const toastCtx: ToastContextValue = { show: vi.fn() };

function Wrapper({ children }: { children: ReactNode }) {
  return React.createElement(
    ToastContext.Provider,
    { value: toastCtx },
    children,
  );
}

const baseProps = {
  restaurant: TEST_RESTAURANT,
  matchLikes: 2,
  runnerUps: [],
  allRestaurants: [TEST_RESTAURANT, TEST_RESTAURANT_2],
  userCount: 2,
  roomId: "ROOM01",
  userId: "user-1",
  onReset: vi.fn().mockResolvedValue(undefined),
  onNarrow: vi.fn().mockResolvedValue(undefined),
  resetting: false,
};

beforeEach(() => {
  vi.clearAllMocks();
});

describe("MatchResult", () => {
  it("renders unanimous match display", () => {
    render(
      <Wrapper>
        <MatchResult {...baseProps} matchType="unanimous" />
      </Wrapper>,
    );
    expect(screen.getByText("就去这了")).toBeInTheDocument();
    expect(screen.getByText("大家一拍即合！")).toBeInTheDocument();
    expect(screen.getByText("测试餐厅")).toBeInTheDocument();
  });

  it("renders best match display", () => {
    render(
      <Wrapper>
        <MatchResult {...baseProps} matchType="best" />
      </Wrapper>,
    );
    expect(screen.getByText("就去这了")).toBeInTheDocument();
    expect(screen.getByText("2/2 人想去这家")).toBeInTheDocument();
  });

  it("renders no_match by delegating to NoMatchResult", () => {
    render(
      <Wrapper>
        <MatchResult {...baseProps} matchType="no_match" />
      </Wrapper>,
    );
    expect(screen.getByTestId("no-match")).toBeInTheDocument();
  });

  it("shows navigation button", () => {
    render(
      <Wrapper>
        <MatchResult {...baseProps} matchType="unanimous" />
      </Wrapper>,
    );
    expect(screen.getByText("导航过去")).toBeInTheDocument();
  });

  it("shows phone button when tel available", () => {
    render(
      <Wrapper>
        <MatchResult {...baseProps} matchType="unanimous" />
      </Wrapper>,
    );
    expect(screen.getByText("打电话订位")).toBeInTheDocument();
  });

  it("shows share button", () => {
    render(
      <Wrapper>
        <MatchResult {...baseProps} matchType="best" />
      </Wrapper>,
    );
    expect(screen.getByText("生成分享卡片")).toBeInTheDocument();
  });

  it("shows solo message when userCount is 1", () => {
    render(
      <Wrapper>
        <MatchResult {...baseProps} matchType="unanimous" userCount={1} />
      </Wrapper>,
    );
    expect(screen.getByText("帮你选好了")).toBeInTheDocument();
    expect(screen.getByText("你的首选，别犹豫了")).toBeInTheDocument();
  });

  it("shows reset button", () => {
    render(
      <Wrapper>
        <MatchResult {...baseProps} matchType="unanimous" />
      </Wrapper>,
    );
    expect(screen.getByText("再来一轮")).toBeInTheDocument();
  });
});
