import { flushPromises, mount } from '@vue/test-utils';

import { beforeEach, describe, expect, it, vi } from 'vitest';

import SkillCreateDialog from './SkillCreateDialog.vue';

const apiMocks = vi.hoisted(() => ({
  cancelSkillImport: vi.fn(),
  importSkillConfirmBatch: vi.fn(),
  importSkillPreviews: vi.fn(),
  prepareSkillGitCandidates: vi.fn(),
  saveSkill: vi.fn(),
  scanSkillGitRepository: vi.fn(),
}));

vi.mock('./api', () => apiMocks);

describe('skill Git repository import dialog', () => {
  beforeEach(() => {
    vi.clearAllMocks();
    apiMocks.scanSkillGitRepository.mockResolvedValue({
      data: {
        candidates: [
          {
            candidateId: 'a'.repeat(64),
            description: '聚合热门 AI 内容',
            issues: [],
            name: 'aihot',
            path: 'aihot',
            resourceCount: 2,
            status: 'IMPORTABLE',
            totalBytes: 2048,
          },
        ],
        expiresAt: '2026-08-15T14:00:00Z',
        repository: {
          commitSha: 'b'.repeat(40),
          defaultBranch: 'main',
          name: 'khazix-skills',
          url: 'https://github.com/KKKKhazix/khazix-skills',
        },
        scanToken: 'c'.repeat(32),
        summary: { discovered: 1, importable: 1, needsAttention: 0 },
      },
      errorCode: 0,
    });
    apiMocks.prepareSkillGitCandidates.mockResolvedValue({
      data: [
        {
          importToken: 'd'.repeat(32),
          issues: [],
          skills: [
            {
              conflict: false,
              name: 'aihot',
              packageId: 'aihot',
              packageRoot: 'aihot',
            },
          ],
        },
      ],
      errorCode: 0,
    });
    apiMocks.importSkillConfirmBatch.mockResolvedValue({
      data: [
        {
          importToken: 'd'.repeat(32),
          skills: [{ id: 101, name: 'aihot' }],
          success: true,
        },
      ],
      errorCode: 0,
    });
  });

  it('scans, selects and imports one repository candidate through the standard pipeline', async () => {
    const wrapper = mount(SkillCreateDialog, {
      global: {
        stubs: {
          ElDialog: {
            props: ['modelValue', 'title'],
            template:
              '<section><h2>{{ title }}</h2><slot/><footer><slot name="footer"/></footer></section>',
          },
        },
      },
      props: {
        categories: [],
        defaultMode: 'import',
        modelValue: true,
      },
    });
    await flushPromises();

    const sourceButtons = wrapper.findAllComponents({ name: 'ElRadioButton' });
    sourceButtons
      .find((item) => item.props('value') === 'git')
      ?.vm.$emit('click');
    sourceButtons
      .find((item) => item.props('value') === 'git')
      ?.vm.$emit('update:modelValue', 'git');
    const sourceGroup = wrapper.findAllComponents({ name: 'ElRadioGroup' })[1];
    sourceGroup?.vm.$emit('update:modelValue', 'git');
    await flushPromises();

    const repositoryInput = wrapper.find(
      'input[placeholder="输入 HTTPS Git 仓库地址"]',
    );
    await repositoryInput.setValue(
      'https://github.com/KKKKhazix/khazix-skills',
    );
    const scanButton = wrapper
      .findAll('button')
      .find((button) => button.text().trim() === '扫描仓库');
    await scanButton?.trigger('click');
    await flushPromises();

    expect(apiMocks.scanSkillGitRepository).toHaveBeenCalledWith(
      'https://github.com/KKKKhazix/khazix-skills',
    );
    expect(wrapper.text()).toContain('khazix-skills');
    expect(wrapper.text()).toContain('aihot');

    await wrapper
      .get('.skill-create-dialog__candidate-toggle')
      .trigger('click');
    const importButton = wrapper
      .findAll('button')
      .find((button) => button.text().includes('导入所选'));
    await importButton?.trigger('click');
    await flushPromises();

    expect(apiMocks.prepareSkillGitCandidates).toHaveBeenCalledWith(
      'c'.repeat(32),
      ['a'.repeat(64)],
    );
    expect(apiMocks.importSkillConfirmBatch).toHaveBeenCalledWith([
      expect.objectContaining({
        conflictStrategy: 'REJECT',
        importToken: 'd'.repeat(32),
        visibilityScope: 'PRIVATE',
      }),
    ]);
    expect(wrapper.emitted('imported')).toEqual([[1]]);
  });

  it('renders and confirms every Skill returned from one multi-Skill ZIP', async () => {
    const archive = new File(['fixture'], 'skill-bundle.zip', {
      type: 'application/zip',
    });
    apiMocks.importSkillPreviews.mockResolvedValue({
      data: ['skill-1', 'skill-2'].map((name, index) => ({
        importToken: `${index + 1}`.repeat(32),
        issues: [],
        skills: [
          {
            conflict: false,
            name,
            packageId: name,
            packageRoot: name,
          },
        ],
        sourceName: archive.name,
      })),
      errorCode: 0,
    });
    apiMocks.importSkillConfirmBatch.mockResolvedValue({
      data: ['skill-1', 'skill-2'].map((name, index) => ({
        importToken: `${index + 1}`.repeat(32),
        skills: [{ id: index + 1, name }],
        success: true,
      })),
      errorCode: 0,
    });
    const wrapper = mount(SkillCreateDialog, {
      global: {
        stubs: {
          ElDialog: {
            props: ['modelValue', 'title'],
            template:
              '<section><h2>{{ title }}</h2><slot/><footer><slot name="footer"/></footer></section>',
          },
        },
      },
      props: {
        categories: [],
        defaultMode: 'import',
        modelValue: true,
      },
    });
    await flushPromises();

    const fileInput = wrapper.get('input[type="file"]');
    Object.defineProperty(fileInput.element, 'files', {
      configurable: true,
      value: [archive],
    });
    await fileInput.trigger('change');
    await flushPromises();

    expect(apiMocks.importSkillPreviews).toHaveBeenCalledWith([archive]);
    expect(wrapper.text()).toContain('skill-1');
    expect(wrapper.text()).toContain('skill-2');
    expect(wrapper.text()).toContain('skill-bundle.zip');

    const importButton = wrapper
      .findAll('button')
      .find((button) => button.text().trim() === '导入');
    await importButton?.trigger('click');
    await flushPromises();

    expect(apiMocks.importSkillConfirmBatch).toHaveBeenCalledWith([
      expect.objectContaining({ importToken: '1'.repeat(32) }),
      expect.objectContaining({ importToken: '2'.repeat(32) }),
    ]);
    expect(wrapper.emitted('imported')).toEqual([[2]]);
  });
});
