import { renderHook } from '@testing-library/react';
import { describe, expect, it } from 'vitest';

import type { ProcurementMaterial } from '@/types';

import { useFilteredMaterials } from './useFilteredMaterials';

function makeMaterial(overrides: Partial<ProcurementMaterial> = {}): ProcurementMaterial {
  return {
    id: 'm-001',
    batch_id: 'B-001',
    material_name: '螺钉',
    specification: 'M6x20',
    quantity: 10,
    unit: '个',
    invoice_type: '增值税',
    technical_standard: '',
    material_requirement: '',
    technical_requirement: '',
    applicable_conditions: '',
    test_requirement: '',
    acceptance_note: '',
    warranty_period: '',
    deadline: '',
    brand: 'A',
    remarks: '',
    delivery_address: '',
    source_file: 'spec.xlsx',
    created_by: 'alice',
    created_at: '2026-04-01T08:00:00Z',
    ...overrides,
  };
}

const fixture: ProcurementMaterial[] = [
  makeMaterial({ id: 'm-1', batch_id: 'B-001', material_name: '螺钉', source_file: 'a.xlsx', created_by: 'alice', created_at: '2026-04-01T08:00:00Z', quantity: 10 }),
  makeMaterial({ id: 'm-2', batch_id: 'B-001', material_name: '螺母', source_file: 'a.xlsx', created_by: 'bob', created_at: '2026-04-05T08:00:00Z', quantity: 5 }),
  makeMaterial({ id: 'm-3', batch_id: 'B-002', material_name: '垫片', source_file: 'b.xlsx', created_by: 'alice', created_at: '2026-04-10T08:00:00Z', quantity: 20 }),
  makeMaterial({ id: 'm-4', batch_id: 'B-002', material_name: '钢板', source_file: 'b.xlsx', created_by: 'carol', created_at: '2026-04-15T08:00:00Z', quantity: 1 }),
];

describe('useFilteredMaterials', () => {
  it('returns all materials when no filters are provided', () => {
    const { result } = renderHook(() => useFilteredMaterials(fixture, {}));
    expect(result.current.map(m => m.id)).toEqual(['m-1', 'm-2', 'm-3', 'm-4']);
  });

  it('filters by exact batch_id', () => {
    const { result } = renderHook(() => useFilteredMaterials(fixture, { batchId: 'B-001' }));
    expect(result.current.map(m => m.id)).toEqual(['m-1', 'm-2']);
  });

  it('filters by case-insensitive source_file substring', () => {
    const { result } = renderHook(() => useFilteredMaterials(fixture, { sourceFile: 'B' }));
    expect(result.current.map(m => m.id)).toEqual(['m-3', 'm-4']);
  });

  it('filters by case-insensitive material name', () => {
    const { result } = renderHook(() => useFilteredMaterials(fixture, { name: '螺' }));
    expect(result.current.map(m => m.id)).toEqual(['m-1', 'm-2']);
  });

  it('filters by created_by substring', () => {
    const { result } = renderHook(() => useFilteredMaterials(fixture, { createdBy: 'alice' }));
    expect(result.current.map(m => m.id)).toEqual(['m-1', 'm-3']);
  });

  it('filters by created_at range (inclusive)', () => {
    const { result } = renderHook(() =>
      useFilteredMaterials(fixture, { createdAtFrom: '2026-04-05', createdAtTo: '2026-04-10' }),
    );
    expect(result.current.map(m => m.id)).toEqual(['m-2', 'm-3']);
  });

  it('combines multiple filters as AND', () => {
    const { result } = renderHook(() =>
      useFilteredMaterials(fixture, { batchId: 'B-001', createdBy: 'alice' }),
    );
    expect(result.current.map(m => m.id)).toEqual(['m-1']);
  });

  it('sorts by string field ascending and descending', () => {
    // 用 ASCII 字符避免依赖运行时 locale 的中文 collation 差异
    const ascii = [
      makeMaterial({ id: 'a', source_file: 'cdoc.xlsx' }),
      makeMaterial({ id: 'b', source_file: 'adoc.xlsx' }),
      makeMaterial({ id: 'c', source_file: 'bdoc.xlsx' }),
    ];
    const asc = renderHook(() =>
      useFilteredMaterials(ascii, { sortKey: 'source_file', sortDir: 'asc' }),
    );
    expect(asc.result.current.map(m => m.id)).toEqual(['b', 'c', 'a']);

    const desc = renderHook(() =>
      useFilteredMaterials(ascii, { sortKey: 'source_file', sortDir: 'desc' }),
    );
    expect(desc.result.current.map(m => m.id)).toEqual(['a', 'c', 'b']);
  });

  it('sorts by numeric field with arithmetic comparison', () => {
    const { result } = renderHook(() =>
      useFilteredMaterials(fixture, { sortKey: 'quantity', sortDir: 'asc' }),
    );
    expect(result.current.map(m => m.quantity)).toEqual([1, 5, 10, 20]);
  });

  it('does not mutate the input array when sorting', () => {
    const before = fixture.map(m => m.id);
    renderHook(() => useFilteredMaterials(fixture, { sortKey: 'material_name', sortDir: 'desc' }));
    expect(fixture.map(m => m.id)).toEqual(before);
  });

  it('returns referentially stable result when filters are unchanged', () => {
    const filters = { batchId: 'B-001' };
    const { result, rerender } = renderHook(
      ({ data, f }) => useFilteredMaterials(data, f),
      { initialProps: { data: fixture, f: filters } },
    );
    const first = result.current;
    rerender({ data: fixture, f: filters });
    expect(result.current).toBe(first);
  });
});
