import { describe, it, expect, vi, beforeEach } from 'vitest';
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { BankCardManagement, BankCardItem, BankCardType } from '../../src/components/BankCardManagement';
import { toast } from 'sonner';

// Mock toast
vi.mock('sonner', () => ({
  toast: {
    success: vi.fn(),
    error: vi.fn(),
    warning: vi.fn(),
  },
}));

// Mock 文件选择器组件
vi.mock('@d8d/file-management-ui/components', () => ({
  FileSelector: vi.fn(({ onChange, placeholder }) => (
    <div data-testid="file-selector">
      <button
        data-testid="file-selector-button"
        onClick={() => onChange && onChange(1)}
      >
        {placeholder || '选择文件'}
      </button>
    </div>
  )),
}));

// Mock 银行名称管理UI API
vi.mock('@d8d/bank-name-management-ui/api', () => ({
  bankNameClientManager: {
    get: vi.fn(() => ({
      index: {
        $get: vi.fn(() => Promise.resolve({
          status: 200,
          json: async () => ({
            data: [
              { id: 1, name: '中国工商银行', code: 'ICBC', remark: '工商银行', status: 1 },
              { id: 2, name: '中国建设银行', code: 'CCB', remark: '建设银行', status: 1 },
              { id: 3, name: '中国农业银行', code: 'ABC', remark: '农业银行', status: 1 },
              { id: 4, name: '中国银行', code: 'BOC', remark: '中国银行', status: 1 },
              { id: 5, name: '招商银行', code: 'CMB', remark: '招商银行', status: 1 },
            ],
            total: 5
          })
        }))
      }
    }))
  }
}));

describe('银行卡管理组件集成测试', () => {
  const mockOnChange = vi.fn();
  let queryClient: QueryClient;

  beforeEach(() => {
    queryClient = new QueryClient({
      defaultOptions: {
        queries: {
          retry: false,
        },
      },
    });
    vi.clearAllMocks();
  });

  const renderComponent = (props = {}) => {
    return render(
      <QueryClientProvider client={queryClient}>
        <BankCardManagement
          value={[]}
          onChange={mockOnChange}
          {...props}
        />
      </QueryClientProvider>
    );
  };

  it('应该正确渲染银行卡管理组件', () => {
    renderComponent();

    // 验证标题
    expect(screen.getByText('银行卡管理')).toBeInTheDocument();

    // 验证添加按钮
    expect(screen.getByText('添加银行卡')).toBeInTheDocument();
    expect(screen.getByRole('button', { name: '添加银行卡' })).toBeInTheDocument();
  });

  it('应该添加新的银行卡', () => {
    renderComponent();

    // 点击添加银行卡按钮
    const addButton = screen.getByTestId('add-bank-card-button');
    fireEvent.click(addButton);

    // 验证新的银行卡表单出现
    expect(screen.getByText('发卡支行 *')).toBeInTheDocument();
    expect(screen.getByText('银行名称 *')).toBeInTheDocument();
    expect(screen.getByText('银行卡号 *')).toBeInTheDocument();
    expect(screen.getByText('持卡人姓名 *')).toBeInTheDocument();
    expect(screen.getByText('银行卡类型')).toBeInTheDocument();
    expect(screen.getByText('银行卡照片')).toBeInTheDocument();
    expect(screen.getByText('设为默认银行卡')).toBeInTheDocument();

    // 验证onChange被调用
    expect(mockOnChange).toHaveBeenCalled();
    const callArgs = mockOnChange.mock.calls[0][0];
    expect(callArgs).toHaveLength(1);
    expect(callArgs[0]).toMatchObject({
      subBankName: '',
      bankNameId: null,
      cardNumber: '',
      cardholderName: '',
      cardType: null,
      fileId: null,
      isDefault: 0,
    });
  });

  it('应该填写银行卡信息', async () => {
    renderComponent();

    // 添加银行卡
    const addButton = screen.getByTestId('add-bank-card-button');
    fireEvent.click(addButton);

    // 等待银行数据加载
    await waitFor(() => {
      expect(screen.getByTestId('bank-select-0')).toBeInTheDocument();
    });

    // 填写支行名称
    const subBankNameInput = screen.getByTestId('sub-bank-name-input-0');
    fireEvent.change(subBankNameInput, { target: { value: '北京分行朝阳支行' } });

    // 选择银行 - 点击银行选择器
    const bankSelectTrigger = screen.getByTestId('bank-select-0');
    fireEvent.click(bankSelectTrigger);

    // 等待银行选项出现
    await waitFor(() => {
      expect(screen.getByText('中国工商银行')).toBeInTheDocument();
    });

    // 选择中国工商银行
    const bankOption = screen.getByText('中国工商银行');
    fireEvent.click(bankOption);

    // 填写银行卡号
    const cardNumberInput = screen.getByTestId('card-number-input-0');
    fireEvent.change(cardNumberInput, { target: { value: '6222021234567890123' } });

    // 填写持卡人姓名
    const cardholderNameInput = screen.getByTestId('cardholder-name-input-0');
    fireEvent.change(cardholderNameInput, { target: { value: '张三' } });

    // 选择银行卡类型 - 点击类型选择器
    const cardTypeSelectTrigger = screen.getByTestId('card-type-select-0');
    fireEvent.click(cardTypeSelectTrigger);

    // 等待银行卡类型选项出现
    await waitFor(() => {
      expect(screen.getByText(BankCardType.FIRST_CLASS)).toBeInTheDocument();
    });

    // 选择一类卡
    const cardTypeOption = screen.getByText(BankCardType.FIRST_CLASS);
    fireEvent.click(cardTypeOption);

    // 选择文件
    const fileSelectorButton = screen.getByTestId('file-selector-button');
    fireEvent.click(fileSelectorButton);

    // 设置为默认银行卡
    const defaultSwitch = screen.getByTestId('default-card-switch-0');
    fireEvent.click(defaultSwitch);

    // 验证所有字段都被正确更新
    const lastCall = mockOnChange.mock.calls[mockOnChange.mock.calls.length - 1][0];
    expect(lastCall[0]).toMatchObject({
      subBankName: '北京分行朝阳支行',
      bankNameId: 1, // 中国工商银行的ID
      cardNumber: '6222021234567890123',
      cardholderName: '张三',
      cardType: BankCardType.FIRST_CLASS,
      fileId: 1,
      isDefault: 1,
    });
  });

  it('应该删除银行卡', () => {
    const initialCards: BankCardItem[] = [
      {
        subBankName: '北京分行',
        bankNameId: 1,
        cardNumber: '6222021234567890123',
        cardholderName: '张三',
        cardType: BankCardType.FIRST_CLASS,
        fileId: 1,
        isDefault: 1,
        tempId: 'temp-1',
      },
      {
        subBankName: '上海分行',
        bankNameId: 2,
        cardNumber: '6222029876543210987',
        cardholderName: '李四',
        cardType: BankCardType.SECOND_CLASS,
        fileId: 2,
        isDefault: 0,
        tempId: 'temp-2',
      },
    ];

    renderComponent({ value: initialCards });

    // 验证有两张银行卡
    expect(screen.getAllByText('发卡支行 *')).toHaveLength(2);
    expect(screen.getByTestId('remove-bank-card-0')).toBeInTheDocument();
    expect(screen.getByTestId('remove-bank-card-1')).toBeInTheDocument();

    // 删除第一张银行卡
    const deleteButton = screen.getByTestId('remove-bank-card-0');
    fireEvent.click(deleteButton);

    // 验证onChange被调用，且只剩一张银行卡
    expect(mockOnChange).toHaveBeenCalled();
    const callArgs = mockOnChange.mock.calls[0][0];
    expect(callArgs).toHaveLength(1);
    expect(callArgs[0].subBankName).toBe('上海分行');
  });

  it('应该限制最大银行卡数量', () => {
    const maxCards = 3;
    renderComponent({ maxCards });

    // 添加最大数量的银行卡
    const addButton = screen.getByTestId('add-bank-card-button');
    for (let i = 0; i < maxCards; i++) {
      fireEvent.click(addButton);
    }

    // 验证可以添加maxCards张银行卡
    expect(screen.getAllByText('发卡支行 *')).toHaveLength(maxCards);

    // 验证按钮被禁用
    expect(addButton).toBeDisabled();

    // 尝试添加超过限制的银行卡
    fireEvent.click(addButton);

    // 验证toast警告被调用（按钮被禁用时可能不会触发）
    // expect(toast.warning).toHaveBeenCalledWith(`最多只能添加 ${maxCards} 张银行卡`);

    // 验证银行卡数量没有增加
    expect(screen.getAllByText('发卡支行 *')).toHaveLength(maxCards);
  });

  it('应该只能设置一张默认银行卡', () => {
    const initialCards: BankCardItem[] = [
      {
        subBankName: '北京分行',
        bankNameId: 1,
        cardNumber: '6222021234567890123',
        cardholderName: '张三',
        cardType: BankCardType.FIRST_CLASS,
        fileId: 1,
        isDefault: 1, // 第一张是默认卡
        tempId: 'temp-1',
      },
      {
        subBankName: '上海分行',
        bankNameId: 2,
        cardNumber: '6222029876543210987',
        cardholderName: '李四',
        cardType: BankCardType.SECOND_CLASS,
        fileId: 2,
        isDefault: 0, // 第二张不是默认卡
        tempId: 'temp-2',
      },
    ];

    renderComponent({ value: initialCards });

    // 获取所有默认开关
    const defaultSwitches = screen.getAllByTestId(/default-card-switch-/);
    expect(defaultSwitches).toHaveLength(2);

    // 第一张卡应该是默认卡（开关应该被选中）
    const firstSwitch = defaultSwitches[0];
    expect(firstSwitch).toBeChecked();

    // 第二张卡不是默认卡（开关不应该被选中）
    const secondSwitch = defaultSwitches[1];
    expect(secondSwitch).not.toBeChecked();

    // 将第二张卡设置为默认卡
    fireEvent.click(secondSwitch);

    // 验证onChange被调用，且只有第二张卡是默认卡
    const callArgs = mockOnChange.mock.calls[0][0];
    expect(callArgs[0].isDefault).toBe(0); // 第一张卡不再是默认卡
    expect(callArgs[1].isDefault).toBe(1); // 第二张卡现在是默认卡
  });

  it('应该测试银行选择组件集成', async () => {
    renderComponent();

    // 添加银行卡
    const addButton = screen.getByTestId('add-bank-card-button');
    fireEvent.click(addButton);

    // 等待银行数据加载
    await waitFor(() => {
      expect(screen.getByTestId('bank-select-0')).toBeInTheDocument();
    });

    // 验证银行选择器存在
    const bankSelectTrigger = screen.getByTestId('bank-select-0');
    expect(bankSelectTrigger).toBeInTheDocument();

    // 等待Select组件的禁用状态被解开（数据加载完成）
    await waitFor(() => {
      expect(bankSelectTrigger).not.toHaveAttribute('disabled');
    });

    // 检查Select组件的aria-expanded属性
    expect(bankSelectTrigger).toHaveAttribute('aria-expanded', 'false');

    // 使用fireEvent点击银行选择器
    fireEvent.click(bankSelectTrigger);

    // 等待Select组件打开（aria-expanded变为true）
    await waitFor(() => {
      expect(bankSelectTrigger).toHaveAttribute('aria-expanded', 'true');
    });

    // 等待银行选项出现
    await waitFor(() => {
      expect(screen.getByText('中国农业银行')).toBeInTheDocument();
    });

    // 查找隐藏的select元素并直接设置值（参考area-select-form测试）
    const hiddenSelect = bankSelectTrigger.parentElement?.querySelector('select[aria-hidden="true"]');
    if (hiddenSelect) {
      await userEvent.selectOptions(hiddenSelect, '3'); // 选择中国农业银行（ID为3）
    } else {
      // 如果没有隐藏的select，尝试直接点击选项
      const bankOption = screen.getByText('中国农业银行');
      fireEvent.click(bankOption);
    }

    // 验证银行ID被正确设置
    const lastCall = mockOnChange.mock.calls[mockOnChange.mock.calls.length - 1][0];
    expect(lastCall[0].bankNameId).toBe(3);
  });

  it('应该测试银行卡类型选择', async () => {
    renderComponent();

    // 添加银行卡
    const addButton = screen.getByTestId('add-bank-card-button');
    fireEvent.click(addButton);

    // 验证银行卡类型选择器存在
    const cardTypeSelect = screen.getByTestId('card-type-select-0');
    expect(cardTypeSelect).toBeInTheDocument();

    // 点击银行卡类型选择器
    fireEvent.click(cardTypeSelect);

    // 等待银行卡类型选项出现
    await waitFor(() => {
      expect(screen.getByText(BankCardType.FIRST_CLASS)).toBeInTheDocument();
      expect(screen.getByText(BankCardType.SECOND_CLASS)).toBeInTheDocument();
    });

    // 选择一类卡
    const firstClassOption = screen.getByText(BankCardType.FIRST_CLASS);
    fireEvent.click(firstClassOption);

    // 验证一类卡被选中
    const lastCall1 = mockOnChange.mock.calls[mockOnChange.mock.calls.length - 1][0];
    expect(lastCall1[0].cardType).toBe(BankCardType.FIRST_CLASS);

    // 再次点击选择器选择二类卡
    fireEvent.click(cardTypeSelect);
    await waitFor(() => {
      expect(screen.getByText(BankCardType.SECOND_CLASS)).toBeInTheDocument();
    });

    // 选择二类卡
    const secondClassOption = screen.getByText(BankCardType.SECOND_CLASS);
    fireEvent.click(secondClassOption);

    // 验证二类卡被选中
    const lastCall2 = mockOnChange.mock.calls[mockOnChange.mock.calls.length - 1][0];
    expect(lastCall2[0].cardType).toBe(BankCardType.SECOND_CLASS);
  });

  it('应该测试文件选择器集成', () => {
    renderComponent();

    // 添加银行卡
    const addButton = screen.getByText('添加银行卡');
    fireEvent.click(addButton);

    // 验证文件选择器存在
    expect(screen.getByTestId('file-selector')).toBeInTheDocument();
    expect(screen.getByTestId('file-selector-button')).toBeInTheDocument();

    // 点击文件选择器按钮
    const fileSelectorButton = screen.getByTestId('file-selector-button');
    fireEvent.click(fileSelectorButton);

    // 验证文件ID被正确设置
    const lastCall = mockOnChange.mock.calls[mockOnChange.mock.calls.length - 1][0];
    expect(lastCall[0].fileId).toBe(1);
  });

  it('应该测试初始值渲染', () => {
    const initialCards: BankCardItem[] = [
      {
        subBankName: '测试支行',
        bankNameId: 1,
        cardNumber: '6222021234567890123',
        cardholderName: '测试用户',
        cardType: BankCardType.FIRST_CLASS,
        fileId: 123,
        isDefault: 1,
        tempId: 'test-1',
      },
    ];

    renderComponent({ value: initialCards });

    // 验证初始值被正确渲染
    const subBankNameInput = screen.getByPlaceholderText('例如：北京分行朝阳支行') as HTMLInputElement;
    const cardNumberInput = screen.getByPlaceholderText('例如：6222 0212 3456 7890') as HTMLInputElement;
    const cardholderNameInput = screen.getByPlaceholderText('请输入持卡人姓名') as HTMLInputElement;

    expect(subBankNameInput.value).toBe('测试支行');
    expect(cardNumberInput.value).toBe('6222 0212 3456 7890 123');
    expect(cardholderNameInput.value).toBe('测试用户');

    // 验证银行选择器存在
    expect(screen.getByTestId('bank-select-0')).toBeInTheDocument();

    // 验证银行卡类型选择器存在
    expect(screen.getByTestId('card-type-select-0')).toBeInTheDocument();
    // 注意：Select组件的值在测试环境中可能无法直接获取
    // 我们只验证组件存在

    // 验证默认开关被选中
    const defaultSwitch = screen.getByTestId('default-card-switch-0');
    expect(defaultSwitch).toBeChecked();
  });

  it('应该测试外部value变化同步', async () => {
    const { rerender } = renderComponent();

    // 初始状态没有银行卡
    expect(screen.queryByText('发卡支行 *')).not.toBeInTheDocument();

    // 更新props添加银行卡
    const newCards: BankCardItem[] = [
      {
        subBankName: '新支行',
        bankNameId: 2,
        cardNumber: '6222029999999999999',
        cardholderName: '新用户',
        cardType: BankCardType.SECOND_CLASS,
        fileId: 456,
        isDefault: 1,
        tempId: 'new-1',
      },
    ];

    rerender(
      <QueryClientProvider client={queryClient}>
        <BankCardManagement
          value={newCards}
          onChange={mockOnChange}
        />
      </QueryClientProvider>
    );

    // 验证新银行卡被渲染
    await waitFor(() => {
      expect(screen.getByText('发卡支行 *')).toBeInTheDocument();
    });

    const subBankNameInput = screen.getByPlaceholderText('例如：北京分行朝阳支行') as HTMLInputElement;
    expect(subBankNameInput.value).toBe('新支行');
  });
});