/**
 * ModelCard 互動測試（Phase 0.9 模型下載）
 *
 * 覆蓋：
 *   - 下載按鈕顯示條件：converted + ready 顯示；uploaded / 非 ready 不顯示
 *   - 點下載按鈕：preventDefault + stopPropagation（不觸發外層 <Link> 導航）
 *   - 下載中：按鈕 disabled + 顯示「下載中」
 *   - 成功 → toast.success；失敗 → toast.error（用 backend code 對應 i18n）
 *   - 其他卡片下載中時，本卡按鈕 disabled
 *
 * Mock：
 *   - sonner toast → 攔截 success / error
 *   - model-store downloadModel action → vi.spyOn 控制回傳
 *   - next/navigation（jsdom 無 app router context）
 */

import { fireEvent, render, screen, waitFor } from "@testing-library/react";
import { afterEach, beforeEach, describe, expect, it, vi, type Mock } from "vitest";

import { LocaleProvider } from "@/lib/i18n/context";
import { useModelStore, type ModelSummary } from "@/stores/model-store";

import { ModelCard } from "./model-card";

vi.mock("sonner", () => {
  const success = vi.fn();
  const error = vi.fn();
  return { toast: Object.assign(vi.fn(), { success, error }) };
});

vi.mock("next/navigation", () => ({
  useRouter: () => ({
    push: vi.fn(),
    replace: vi.fn(),
    back: vi.fn(),
    forward: vi.fn(),
    refresh: vi.fn(),
    prefetch: vi.fn(),
  }),
}));

import { toast } from "sonner";

const convertedReady: ModelSummary = {
  id: "m1",
  name: "YOLOv5s",
  targetChip: "kl520",
  fileSize: 1024,
  source: "converted",
  status: "ready",
  createdAt: "2026-01-01T00:00:00Z",
};

function renderCard(model: ModelSummary) {
  return render(
    <LocaleProvider>
      <ModelCard model={model} />
    </LocaleProvider>,
  );
}

beforeEach(() => {
  useModelStore.setState({ downloadingId: null });
  (toast.success as Mock).mockReset();
  (toast.error as Mock).mockReset();
});

afterEach(() => {
  vi.restoreAllMocks();
  useModelStore.setState({ downloadingId: null });
});

describe("ModelCard 下載按鈕顯示條件", () => {
  it("converted + ready → 顯示下載按鈕", () => {
    renderCard(convertedReady);
    expect(screen.getByTestId("model-card-download")).toBeInTheDocument();
  });

  it("uploaded（即使 ready）→ 不顯示下載按鈕", () => {
    renderCard({ ...convertedReady, source: "uploaded" });
    expect(screen.queryByTestId("model-card-download")).not.toBeInTheDocument();
  });

  it("converted 但 scanning → 不顯示下載按鈕", () => {
    renderCard({ ...convertedReady, status: "scanning" });
    expect(screen.queryByTestId("model-card-download")).not.toBeInTheDocument();
  });

  it("preset → 顯示下載按鈕（backend B8 內建模型可下載）", () => {
    renderCard({ ...convertedReady, source: "preset" });
    expect(screen.getByTestId("model-card-download")).toBeInTheDocument();
  });
});

describe("ModelCard 下載互動", () => {
  it("點下載按鈕：preventDefault + stopPropagation（不觸發 Link 導航）", async () => {
    const spy = vi
      .spyOn(useModelStore.getState(), "downloadModel")
      .mockResolvedValue({ ok: true });

    renderCard(convertedReady);
    const btn = screen.getByTestId("model-card-download");

    // 自建 event 驗 preventDefault / stopPropagation 都被呼叫
    const event = new MouseEvent("click", { bubbles: true, cancelable: true });
    const preventDefault = vi.spyOn(event, "preventDefault");
    const stopPropagation = vi.spyOn(event, "stopPropagation");
    fireEvent(btn, event);

    expect(preventDefault).toHaveBeenCalled();
    expect(stopPropagation).toHaveBeenCalled();
    await waitFor(() => expect(spy).toHaveBeenCalledWith(convertedReady));
  });

  it("下載成功 → toast.success", async () => {
    vi.spyOn(useModelStore.getState(), "downloadModel").mockResolvedValue({ ok: true });
    renderCard(convertedReady);
    fireEvent.click(screen.getByTestId("model-card-download"));
    await waitFor(() => expect(toast.success).toHaveBeenCalledOnce());
    expect(toast.error).not.toHaveBeenCalled();
  });

  it("下載失敗（forbidden）→ toast.error，描述用對應 i18n", async () => {
    vi.spyOn(useModelStore.getState(), "downloadModel").mockResolvedValue({
      ok: false,
      code: "forbidden",
      message: "no",
    });
    renderCard(convertedReady);
    fireEvent.click(screen.getByTestId("model-card-download"));
    await waitFor(() => expect(toast.error).toHaveBeenCalledOnce());
    // 第二參數 description 對應 models.download.error.forbidden（繁中）
    const call = (toast.error as Mock).mock.calls[0];
    expect(call[1].description).toBe("你沒有權限下載此模型");
  });

  it("未知 code → toast.error 描述退化成 unknown 文案", async () => {
    vi.spyOn(useModelStore.getState(), "downloadModel").mockResolvedValue({
      ok: false,
      code: "some_unmapped_code",
      message: "x",
    });
    renderCard(convertedReady);
    fireEvent.click(screen.getByTestId("model-card-download"));
    await waitFor(() => expect(toast.error).toHaveBeenCalledOnce());
    const call = (toast.error as Mock).mock.calls[0];
    expect(call[1].description).toBe("下載失敗，請稍後再試");
  });

  it("其他卡片下載中（downloadingId != null）→ 本卡按鈕 disabled", () => {
    useModelStore.setState({ downloadingId: "other-model" });
    renderCard(convertedReady);
    expect(screen.getByTestId("model-card-download")).toBeDisabled();
  });

  it("本卡下載中 → 顯示「下載中…」且 disabled", () => {
    useModelStore.setState({ downloadingId: "m1" });
    renderCard(convertedReady);
    const btn = screen.getByTestId("model-card-download");
    expect(btn).toBeDisabled();
    expect(btn).toHaveTextContent("下載中");
  });
});
