import { fireEvent, render, screen, waitFor, within } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom';
import { beforeEach, describe, expect, it, vi } from 'vitest';

import { openFailureSupplementPrintView } from '@/components/shared/FailureSupplementPrintView';
import Standardized from '@/pages/Standardized';
import type { StandardizationFailureItem } from '@/services/standardizedService';
import {
  createManualStandardizedResultsFromFailures,
  fetchStandardizationFailures,
  fetchStandardizationTasks,
  fetchStandardized,
} from '@/services/standardizedService';
import type { StandardizedMaterial } from '@/types';

const { toastSuccessMock, toastErrorMock, openFailureSupplementPrintViewMock } = vi.hoisted(() => ({
  toastSuccessMock: vi.fn(),
  toastErrorMock: vi.fn(),
  openFailureSupplementPrintViewMock: vi.fn(),
}));

vi.mock('sonner', () => ({
  toast: {
    success: toastSuccessMock,
    error: toastErrorMock,
  },
}));

vi.mock('@/components/shared/FailureSupplementPrintView', async (importOriginal) => {
  const actual = await importOriginal<typeof import('@/components/shared/FailureSupplementPrintView')>();

  return {
    ...actual,
    openFailureSupplementPrintView: openFailureSupplementPrintViewMock,
  };
});

vi.mock('@/hooks/useProcurementBatchOptions', () => ({
  useProcurementBatchOptions: () => ({
    batchOptions: [
      { value: 'BATCH-001', label: 'BATCH-001' },
      { value: 'BATCH-002', label: 'BATCH-002' },
    ],
  }),
}));

vi.mock('@/hooks/useAuth', () => ({
  useAuth: () => ({
    user: { username: 'operator' },
  }),
}));

vi.mock('@/services/automationService', () => ({
  retryStandardizationFailures: vi.fn(),
  stopStandardizeTask: vi.fn(),
}));

vi.mock('@/services/standardizedService', async (importOriginal) => {
  const actual = await importOriginal<typeof import('@/services/standardizedService')>();

  return {
    ...actual,
    createManualStandardizedResultsFromFailures: vi.fn(),
    deleteStandardizationFailuresByIds: vi.fn(),
    deleteStandardizationTaskById: vi.fn(),
    deleteStandardizedByIds: vi.fn(),
    fetchStandardizationFailures: vi.fn(),
    fetchStandardizationTasks: vi.fn(),
    fetchStandardized: vi.fn(),
    updateStandardized: vi.fn(),
  };
});

function createStandardizedMaterial(overrides: Partial<StandardizedMaterial> = {}): StandardizedMaterial {
  return {
    id: 'std-001',
    batch_id: 'BATCH-001',
    material_id: 'mat-001',
    source_type: 'ai',
    invoice_type: '专票',
    original_name: '球墨铸铁井盖',
    original_spec: 'DN700',
    standardized_name: '球墨铸铁井盖',
    category: '市政材料',
    brand: '晋钢',
    notes: '',
    delivery_address: '济南仓',
    primary_search_term: '球墨铸铁井盖 DN700 晋钢',
    alt_search_terms: ['井盖 DN700'],
    standardized_spec: 'DN700',
    standardized_unit: '套',
    quantity: 12,
    product_type: '市政道路',
    llm_model: 'glm-5.1',
    ai_reasoning: '',
    created_by: 'user-001',
    updated_at: '2026-04-20T10:00:00.000Z',
    created_at: '2026-04-20T10:00:00.000Z',
    ...overrides,
  };
}

function createFailureItem(overrides: Partial<StandardizationFailureItem> = {}): StandardizationFailureItem {
  return {
    id: 'failure-001',
    task_id: 'task-001',
    batch_id: 'BATCH-001',
    source_material_id: 'mat-001',
    original_name: '球墨铸铁井盖',
    original_spec: 'DN700',
    quantity: 12,
    unit: '套',
    invoice_type: '专票',
    standardized_name: '球墨铸铁井盖',
    can_search_1688: false,
    missing_required_fields: ['规格型号'],
    failure_reason: '缺少规格型号',
    human_fix_hint: '请补充规格型号',
    llm_model: 'glm-5.1',
    created_at: '2026-04-20T10:00:00.000Z',
    updated_at: '2026-04-20T10:00:00.000Z',
    source_snapshot: {
      id: 'mat-001',
      batch_id: 'BATCH-001',
      material_name: '球墨铸铁井盖',
      specification: 'DN700',
      quantity: 12,
      unit: '套',
      invoice_type: '专票',
      brand: '源品牌',
      remarks: '道路工程使用',
      delivery_address: '济南仓',
      technical_standard: 'GB/T 23858',
      material_requirement: '球墨铸铁',
      technical_requirement: '',
      applicable_conditions: '市政道路',
      test_requirement: '',
      acceptance_note: '',
      warranty_period: '',
      deadline: '',
      source_file: 'source.xlsx',
      created_at: '2026-04-20T09:00:00.000Z',
      created_by: 'user-001',
    },
    ...overrides,
  };
}

function renderStandardized(initialPath = '/standardized') {
  return render(
    <MemoryRouter initialEntries={[initialPath]}>
      <Standardized />
    </MemoryRouter>,
  );
}

describe('Standardized page', () => {
  beforeEach(() => {
    vi.clearAllMocks();
    vi.mocked(fetchStandardized).mockResolvedValue([createStandardizedMaterial()]);
    vi.mocked(fetchStandardizationFailures).mockResolvedValue([]);
    vi.mocked(fetchStandardizationTasks).mockResolvedValue([]);
    vi.mocked(openFailureSupplementPrintView).mockResolvedValue({ mode: 'print', count: 1 });
    vi.mocked(createManualStandardizedResultsFromFailures).mockResolvedValue({
      successCount: 0,
      failedCount: 0,
      successes: [],
      failures: [],
    });
  });

  it('does not render the supplement upload action on the successful standardized rows tab', async () => {
    renderStandardized('/standardized');

    expect((await screen.findAllByText('球墨铸铁井盖')).length).toBeGreaterThan(0);
    expect(screen.getByRole('button', { name: /导出/ })).toBeInTheDocument();
    expect(screen.queryByRole('button', { name: /上传补充卡/ })).not.toBeInTheDocument();
  });

  it('submits manual failure supplements and reports mixed batch feedback', async () => {
    vi.mocked(fetchStandardizationFailures).mockResolvedValue([
      createFailureItem({
        id: 'failure-001',
        original_name: '写入成功物料',
        missing_required_fields: ['规格型号'],
        failure_reason: '缺少规格型号',
        human_fix_hint: '请补充规格型号',
      }),
      createFailureItem({
        id: 'failure-002',
        source_material_id: 'mat-002',
        original_name: '写入失败物料',
        missing_required_fields: ['品牌'],
        failure_reason: '缺少品牌',
        human_fix_hint: '请补充品牌',
      }),
    ]);
    vi.mocked(createManualStandardizedResultsFromFailures).mockResolvedValue({
      successCount: 1,
      failedCount: 1,
      successes: [{
        failureId: 'failure-001',
        materialId: 'mat-001',
        batchId: 'BATCH-001',
        updated_at: '2026-04-20T11:00:00.000Z',
      }],
      failures: [{ failureId: 'failure-002', error: 'duplicate key violation' }],
    });

    renderStandardized('/standardized?tab=failed');

    await screen.findByRole('button', { name: /人工补充/ });
    expect(screen.getByRole('button', { name: /下载补充卡/ })).toBeInTheDocument();
    expect(screen.queryByRole('button', { name: /上传补充卡/ })).not.toBeInTheDocument();

    fireEvent.click(screen.getByRole('button', { name: /人工补充/ }));
    const dialog = await screen.findByRole('dialog');

    fireEvent.change(within(dialog).getByLabelText('规格型号 *'), { target: { value: 'DN700' } });
    fireEvent.click(within(dialog).getByRole('button', { name: /写入失败物料/ }));
    fireEvent.change(within(dialog).getByLabelText('品牌 *'), { target: { value: 'Leica' } });
    fireEvent.click(within(dialog).getByRole('button', { name: '确认入成功池' }));

    await waitFor(() => {
      expect(createManualStandardizedResultsFromFailures).toHaveBeenCalledWith([
        {
          failureId: 'failure-001',
          supplement: expect.objectContaining({ spec_model: 'DN700' }),
        },
        {
          failureId: 'failure-002',
          supplement: expect.objectContaining({ brand: 'Leica' }),
        },
      ]);
    });
    expect(toastSuccessMock).toHaveBeenCalledWith('已确认 1 条记录入成功池');
    expect(toastErrorMock).toHaveBeenCalledWith('有 1 条写入失败：failure-002: duplicate key violation');

    await waitFor(() => {
      expect(screen.queryByRole('button', { name: /写入成功物料/ })).not.toBeInTheDocument();
    });
    expect(screen.queryByText('写入成功物料')).not.toBeInTheDocument();
    expect(screen.getByRole('button', { name: /写入失败物料/ })).toBeInTheDocument();
    expect(screen.getAllByText('缺少：提交失败').length).toBeGreaterThan(0);
  });

  it('does not expose failure resolution status controls', async () => {
    vi.mocked(fetchStandardizationFailures).mockResolvedValue([createFailureItem()]);

    renderStandardized('/standardized?tab=failed');

    await screen.findByText('球墨铸铁井盖');
    expect(screen.queryByText('处理状态')).not.toBeInTheDocument();
    expect(screen.queryByRole('button', { name: /修改状态/ })).not.toBeInTheDocument();
    expect(screen.queryByText('待处理')).not.toBeInTheDocument();
    expect(screen.queryByText('已完成')).not.toBeInTheDocument();
  });

  it('shows an accurate toast when the supplement card print window opens', async () => {
    vi.mocked(fetchStandardizationFailures).mockResolvedValue([createFailureItem()]);
    vi.mocked(openFailureSupplementPrintView).mockResolvedValue({ mode: 'print', count: 1 });

    renderStandardized('/standardized?tab=failed');

    fireEvent.click(await screen.findByRole('button', { name: /下载补充卡/ }));

    await waitFor(() => {
      expect(openFailureSupplementPrintView).toHaveBeenCalledWith([expect.objectContaining({ id: 'failure-001' })]);
    });
    expect(toastSuccessMock).toHaveBeenCalledWith('已打开 1 条失败记录补充卡打印窗口');
  });

  it('shows the generated file toast when supplement card printing falls back to download', async () => {
    vi.mocked(fetchStandardizationFailures).mockResolvedValue([createFailureItem()]);
    vi.mocked(openFailureSupplementPrintView).mockResolvedValue({
      mode: 'download',
      count: 1,
      filename: '球墨铸铁井盖-BATCH-001-20260426T120000.html',
      reason: 'popup-blocked',
    });

    renderStandardized('/standardized?tab=failed');

    fireEvent.click(await screen.findByRole('button', { name: /下载补充卡/ }));

    await waitFor(() => {
      expect(toastSuccessMock).toHaveBeenCalledWith('打印窗口被浏览器拦截，已生成补充卡文件 球墨铸铁井盖-BATCH-001-20260426T120000.html');
    });
  });

  it('reports no downloadable records without opening the supplement print flow', async () => {
    renderStandardized('/standardized?tab=failed');

    fireEvent.click(await screen.findByRole('button', { name: /下载补充卡/ }));

    expect(openFailureSupplementPrintView).not.toHaveBeenCalled();
    expect(toastErrorMock).toHaveBeenCalledWith('没有可下载的失败记录');
  });

  it('shows the supplement card export error when print and file generation fail', async () => {
    vi.mocked(fetchStandardizationFailures).mockResolvedValue([createFailureItem()]);
    vi.mocked(openFailureSupplementPrintView).mockRejectedValue(new Error('补充卡文件生成失败'));

    renderStandardized('/standardized?tab=failed');

    fireEvent.click(await screen.findByRole('button', { name: /下载补充卡/ }));

    await waitFor(() => {
      expect(toastErrorMock).toHaveBeenCalledWith('补充卡文件生成失败');
    });
  });
});
