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

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

import DocumentImportBatchStatus from './DocumentImportBatchStatus.vue';

const apiMocks = vi.hoisted(() => ({
  get: vi.fn(),
  post: vi.fn(),
}));

vi.mock('#/api/request', () => ({ api: apiMocks }));

vi.mock('@easyflow/locales', () => ({
  $t: (key: string) => key,
}));

function createBatch(status: 'COMPLETED' | 'RUNNING', completedCount: number) {
  return {
    batchId: 'batch-1',
    completedCount,
    failedCount: 0,
    importMode: 'AUTO',
    pendingCount: status === 'RUNNING' ? 1 : 0,
    processingCount: 0,
    progressPercent: status === 'COMPLETED' ? 100 : 50,
    skippedCount: 0,
    status,
    totalCount: 2,
  };
}

describe('documentImportBatchStatus', () => {
  afterEach(() => {
    vi.clearAllMocks();
    vi.useRealTimers();
  });

  it('页面首次进入时不恢复已完成批次', async () => {
    apiMocks.get.mockResolvedValue({
      data: createBatch('COMPLETED', 2),
      errorCode: 0,
    });

    const wrapper = mount(DocumentImportBatchStatus, {
      props: { knowledgeId: 'knowledge-1' },
    });
    await flushPromises();

    expect(wrapper.find('.batch-status').exists()).toBe(false);
    wrapper.unmount();
  });

  it('当前页面跟踪的批次完成后继续展示结果', async () => {
    vi.useFakeTimers();
    apiMocks.get
      .mockResolvedValueOnce({
        data: createBatch('RUNNING', 1),
        errorCode: 0,
      })
      .mockResolvedValueOnce({
        data: createBatch('COMPLETED', 2),
        errorCode: 0,
      });

    const wrapper = mount(DocumentImportBatchStatus, {
      props: { knowledgeId: 'knowledge-1' },
    });
    await flushPromises();

    expect(wrapper.find('.batch-status').exists()).toBe(true);

    await vi.advanceTimersByTimeAsync(3000);
    await flushPromises();

    expect(wrapper.find('.batch-status').exists()).toBe(true);
    expect(wrapper.text()).toContain(
      'documentCollection.importDoc.batchCompleted',
    );
    wrapper.unmount();
  });

  it('部分失败批次按 failedCount 继续并发送统一批次参数', async () => {
    const failedBatch = {
      batchId: 'batch-1',
      completedCount: 1,
      failedCount: 1,
      importMode: 'AUTO',
      pendingCount: 0,
      processingCount: 0,
      progressPercent: 100,
      retryableFailedCount: 0,
      skippedCount: 0,
      status: 'PARTIAL_SUCCEEDED',
      totalCount: 2,
    };
    apiMocks.get.mockResolvedValue({
      data: failedBatch,
      errorCode: 0,
    });
    apiMocks.post.mockResolvedValue({
      data: {
        ...failedBatch,
        failedCount: 0,
        pendingCount: 1,
        progressPercent: 50,
        status: 'RUNNING',
      },
      errorCode: 0,
    });

    const wrapper = mount(DocumentImportBatchStatus, {
      props: {
        knowledgeId: 'knowledge-1',
        manageable: true,
      },
    });
    await flushPromises();

    const continueButton = wrapper.find('.batch-status__continue');
    expect(continueButton.exists()).toBe(true);
    await continueButton.trigger('click');
    await flushPromises();

    expect(apiMocks.post).toHaveBeenCalledWith(
      '/api/v1/document/import/batch/continue',
      {
        batchId: 'batch-1',
        knowledgeId: 'knowledge-1',
      },
    );
    wrapper.unmount();
  });

  it('没有失败项时不使用旧兼容计数显示继续按钮', async () => {
    apiMocks.get.mockResolvedValue({
      data: {
        ...createBatch('COMPLETED', 2),
        retryableFailedCount: 1,
        status: 'PARTIAL_SUCCEEDED',
      },
      errorCode: 0,
    });

    const wrapper = mount(DocumentImportBatchStatus, {
      props: {
        knowledgeId: 'knowledge-1',
        manageable: true,
      },
    });
    await flushPromises();

    expect(wrapper.find('.batch-status__continue').exists()).toBe(false);
    wrapper.unmount();
  });

  it('中断批次展示异常原因、错误标识和继续入口', async () => {
    apiMocks.get.mockResolvedValue({
      data: {
        ...createBatch('RUNNING', 0),
        failedCount: 2,
        interruptCode: 'redis_unavailable',
        interruptedAt: '2026-08-07T09:25:28+08:00',
        interruptMessage: '缓存与消息服务异常，自动导入已中断',
        pendingCount: 0,
        status: 'INTERRUPTED',
      },
      errorCode: 0,
    });

    const wrapper = mount(DocumentImportBatchStatus, {
      props: {
        knowledgeId: 'knowledge-1',
        manageable: true,
      },
    });
    await flushPromises();

    const alert = wrapper.find('.batch-status__alert');
    expect(alert.exists()).toBe(true);
    expect(alert.text()).toContain('缓存与消息服务异常，自动导入已中断');
    expect(alert.text()).toContain('redis_unavailable');
    expect(wrapper.find('.batch-status__count').text()).toContain('2 / 2');
    expect(wrapper.find('.batch-status__continue').exists()).toBe(true);
    wrapper.unmount();
  });

  it('状态接口暂时失败时展示错误并自动退避恢复轮询', async () => {
    vi.useFakeTimers();
    apiMocks.get
      .mockRejectedValueOnce(new Error('network unavailable'))
      .mockResolvedValueOnce({
        data: createBatch('RUNNING', 1),
        errorCode: 0,
      });

    const wrapper = mount(DocumentImportBatchStatus, {
      props: { knowledgeId: 'knowledge-1' },
    });
    await flushPromises();

    expect(wrapper.find('.batch-status--error').exists()).toBe(true);

    await vi.advanceTimersByTimeAsync(3000);
    await flushPromises();

    expect(apiMocks.get).toHaveBeenCalledTimes(2);
    expect(wrapper.find('.batch-status--error').exists()).toBe(false);
    expect(wrapper.find('.batch-status').exists()).toBe(true);
    wrapper.unmount();
  });

  it('运行批次轮询失败时保留旧状态、展示错误并自动恢复', async () => {
    vi.useFakeTimers();
    apiMocks.get
      .mockResolvedValueOnce({
        data: createBatch('RUNNING', 1),
        errorCode: 0,
      })
      .mockRejectedValueOnce(new Error('network unavailable'))
      .mockResolvedValueOnce({
        data: createBatch('COMPLETED', 2),
        errorCode: 0,
      });

    const wrapper = mount(DocumentImportBatchStatus, {
      props: { knowledgeId: 'knowledge-1' },
    });
    await flushPromises();

    await vi.advanceTimersByTimeAsync(3000);
    await flushPromises();

    expect(wrapper.find('.batch-status__summary').exists()).toBe(true);
    expect(wrapper.find('.batch-status__load-error').exists()).toBe(true);

    await vi.advanceTimersByTimeAsync(3000);
    await flushPromises();

    expect(apiMocks.get).toHaveBeenCalledTimes(3);
    expect(wrapper.find('.batch-status__load-error').exists()).toBe(false);
    expect(wrapper.text()).toContain(
      'documentCollection.importDoc.batchCompleted',
    );
    wrapper.unmount();
  });
});
