import { computed, ref } from "vue";
import { fireEvent, render, screen } from "@testing-library/vue";
import { describe, expect, it, vi } from "vitest";

import UpdateCenterModal from "@/components/UpdateCenterModal.vue";
import type {
  UpdateCenterItem,
  UpdateCenterSnapshot,
  UpdateCenterTaskState,
} from "@/global/typedefinition";
import type { UpdateCenterStore } from "@/modules/updateCenter";

const createItem = (
  overrides: Partial<UpdateCenterItem> = {},
): UpdateCenterItem => ({
  taskKey: "aptss:spark-weather",
  packageName: "spark-weather",
  displayName: "Spark Weather",
  currentVersion: "1.0.0",
  newVersion: "2.0.0",
  source: "aptss",
  ...overrides,
});

const createTask = (
  overrides: Partial<UpdateCenterTaskState> = {},
): UpdateCenterTaskState => ({
  taskKey: "aptss:spark-weather",
  packageName: "spark-weather",
  source: "aptss",
  status: "downloading",
  progress: 42,
  logs: [],
  errorMessage: "",
  ...overrides,
});

const createStore = (
  overrides: Partial<UpdateCenterSnapshot> = {},
): UpdateCenterStore => {
  const snapshot = ref<UpdateCenterSnapshot>({
    items: [
      createItem({
        taskKey: "aptss:spark-weather",
        source: "aptss",
      }),
      createItem({
        taskKey: "apm:spark-clock",
        packageName: "spark-clock",
        displayName: "Spark Clock",
        source: "apm",
        isMigration: true,
        migrationTarget: "apm",
      }),
    ],
    tasks: [createTask()],
    warnings: ["更新过程中请勿关闭商店"],
    hasRunningTasks: true,
    ...overrides,
  });

  const selectedTaskKeys = ref(new Set<string>(["aptss:spark-weather"]));

  return {
    isOpen: ref(true),
    loading: ref(false),
    showCloseConfirm: ref(true),
    showMigrationConfirm: ref(false),
    searchQuery: ref(""),
    selectedTaskKeys,
    snapshot,
    filteredItems: computed(() => snapshot.value.items),
    allSelected: computed(() => false),
    someSelected: computed(() => selectedTaskKeys.value.size > 0),
    bind: vi.fn(),
    unbind: vi.fn(),
    open: vi.fn(),
    refresh: vi.fn(),
    ignoreItem: vi.fn(),
    unignoreItem: vi.fn(),
    toggleSelection: vi.fn(),
    getSelectedItems: vi.fn(() =>
      snapshot.value.items.filter(
        (item) =>
          selectedTaskKeys.value.has(item.taskKey) && item.ignored !== true,
      ),
    ),
    closeNow: vi.fn(),
    startSelected: vi.fn(),
    requestClose: vi.fn(),
  };
};

describe("UpdateCenterModal", () => {
  it("constrains the update list so it can scroll with a visible scrollbar", () => {
    const store = createStore({
      items: Array.from({ length: 20 }, (_, index) =>
        createItem({
          taskKey: `aptss:spark-item-${index}`,
          packageName: `spark-item-${index}`,
          displayName: `Spark Item ${index}`,
        }),
      ),
      tasks: [],
      warnings: [],
      hasRunningTasks: false,
    });

    const { container } = render(UpdateCenterModal, {
      props: {
        show: true,
        store,
      },
    });

    const scrollContainer = container.querySelector(".scrollbar-muted");

    expect(scrollContainer?.className).toContain("overflow-y-auto");
    expect(scrollContainer?.className).toContain("flex-1");
    expect(scrollContainer?.className).toContain("overscroll-contain");
  });

  it("renders source tags, running state, warnings, and migration marker", () => {
    const store = createStore();

    render(UpdateCenterModal, {
      props: {
        show: true,
        store,
      },
    });

    expect(screen.getByText("软件更新")).toBeTruthy();
    expect(screen.getByText("传统deb")).toBeTruthy();
    expect(screen.getByText("APM")).toBeTruthy();
    expect(screen.getByText("将迁移到 APM")).toBeTruthy();
    expect(screen.getByText("更新过程中请勿关闭商店")).toBeTruthy();
    expect(screen.getByText("下载中")).toBeTruthy();
    expect(screen.getByText("42%")).toBeTruthy();
  });

  it("renders ignored items as disabled instead of normal selectable actions", () => {
    const store = createStore({
      items: [
        createItem({
          taskKey: "aptss:spark-weather",
          packageName: "spark-weather",
          displayName: "Spark Weather",
          source: "aptss",
          ignored: true,
        }),
      ],
      tasks: [],
      warnings: [],
      hasRunningTasks: false,
    });

    render(UpdateCenterModal, {
      props: {
        show: true,
        store,
      },
    });

    expect(screen.getByText("已忽略")).toBeTruthy();
    expect(screen.getAllByRole("checkbox").at(-1)).toBeDisabled();
    expect(screen.getByRole("button", { name: "取消忽略" })).toBeTruthy();
  });

  it("renders ignore action for normal items", () => {
    const store = createStore({
      items: [
        createItem({
          taskKey: "aptss:spark-weather",
          packageName: "spark-weather",
          displayName: "Spark Weather",
          source: "aptss",
          ignored: false,
        }),
      ],
      tasks: [],
      warnings: [],
      hasRunningTasks: false,
    });

    render(UpdateCenterModal, {
      props: {
        show: true,
        store,
      },
    });

    expect(screen.getByRole("button", { name: "忽略更新" })).toBeTruthy();
  });

  it("renders migration confirmation when requested", () => {
    const store = createStore({ hasRunningTasks: false });
    store.showMigrationConfirm.value = true;

    render(UpdateCenterModal, {
      props: {
        show: true,
        store,
      },
    });

    expect(screen.getByText("迁移确认")).toBeTruthy();
  });

  it("close button triggers request-close flow", async () => {
    const store = createStore({ hasRunningTasks: false });

    render(UpdateCenterModal, {
      props: {
        show: true,
        store,
      },
    });

    await fireEvent.click(screen.getByRole("button", { name: "关闭" }));

    expect(store.requestClose).toHaveBeenCalledTimes(1);
  });

  it("shows loading panel when loading with no items", () => {
    const store = createStore({
      items: [],
      tasks: [],
      warnings: [],
      hasRunningTasks: false,
    });
    store.loading.value = true;

    render(UpdateCenterModal, {
      props: {
        show: true,
        store,
      },
    });

    expect(screen.getByText("正在检查更新…")).toBeTruthy();
  });

  it("shows refresh hint while loading with existing items", () => {
    const store = createStore({ hasRunningTasks: false });
    store.loading.value = true;

    render(UpdateCenterModal, {
      props: {
        show: true,
        store,
      },
    });

    expect(screen.getByText("Spark Weather")).toBeTruthy();
    expect(screen.getByText("正在刷新更新列表…")).toBeTruthy();
  });

  it("disables refresh button while loading", () => {
    const store = createStore({ hasRunningTasks: false });
    store.loading.value = true;

    render(UpdateCenterModal, {
      props: {
        show: true,
        store,
      },
    });

    expect(screen.getByRole("button", { name: /刷新/ })).toBeDisabled();
  });
});
