"""app.core.handlers.column_mapper 单元测试"""

import pytest
import pandas as pd
from app.core.handlers.column_mapper import ColumnMapper


class TestStandardColumns:
    """STANDARD_COLUMNS 完整性测试"""

    def test_has_all_standard_fields(self):
        expected = {'barcode', 'name', 'specification', 'quantity', 'unit',
                    'unit_price', 'total_price', 'gift_quantity',
                    'category', 'brand', 'supplier'}
        assert set(ColumnMapper.STANDARD_COLUMNS.keys()) == expected

    def test_no_empty_alias_lists(self):
        for field, aliases in ColumnMapper.STANDARD_COLUMNS.items():
            assert len(aliases) > 0, f"{field} has no aliases"

    def test_barcode_includes_key_names(self):
        bc = ColumnMapper.STANDARD_COLUMNS['barcode']
        assert '条码' in bc
        assert '商品条码' in bc
        assert 'barcode' in bc

    def test_gift_quantity_includes_common_names(self):
        gq = ColumnMapper.STANDARD_COLUMNS['gift_quantity']
        assert '赠送量' in gq
        assert '赠品数量' in gq


class TestFindColumn:
    """ColumnMapper.find_column 列查找测试"""

    def test_exact_match(self):
        cols = ['商品条码', '商品名称', '数量', '单价']
        assert ColumnMapper.find_column(cols, 'barcode') == '商品条码'

    def test_exact_match_standard_english(self):
        cols = ['barcode', 'name', 'quantity']
        assert ColumnMapper.find_column(cols, 'barcode') == 'barcode'

    def test_whitespace_match(self):
        """列名含空格时应匹配"""
        cols = ['名 称', '数 量']
        assert ColumnMapper.find_column(cols, 'name') == '名 称'
        assert ColumnMapper.find_column(cols, 'quantity') == '数 量'

    def test_partial_match_substring(self):
        """列名包含候选名时应匹配"""
        cols = ['商品条码（小条码）', '商品名称']
        assert ColumnMapper.find_column(cols, 'barcode') == '商品条码（小条码）'

    def test_not_found_returns_none(self):
        cols = ['日期', '备注', '编号']
        assert ColumnMapper.find_column(cols, 'barcode') is None

    def test_unknown_standard_name_returns_none(self):
        cols = ['商品条码']
        assert ColumnMapper.find_column(cols, 'nonexistent_field') is None

    def test_first_match_wins(self):
        """多个列都能匹配时返回第一个"""
        cols = ['条码', '商品条码', 'barcode']
        assert ColumnMapper.find_column(cols, 'barcode') == '条码'

    def test_case_insensitive(self):
        cols = ['Barcode', 'Name']
        assert ColumnMapper.find_column(cols, 'barcode') == 'Barcode'

    def test_all_fields_matchable(self):
        """每个标准字段都能找到至少一个匹配"""
        cols = [
            '商品条码', '商品名称', '规格', '数量', '单位',
            '单价', '金额', '赠送量', '类别', '品牌', '供应商',
        ]
        for std_name in ColumnMapper.STANDARD_COLUMNS:
            result = ColumnMapper.find_column(cols, std_name)
            assert result is not None, f"Could not find {std_name} in {cols}"


class TestDetectHeaderRow:
    """ColumnMapper.detect_header_row 表头检测测试"""

    def test_header_on_first_row(self):
        df = pd.DataFrame({
            'A': ['条码', '123456', '789012'],
            'B': ['数量', '10', '20'],
            'C': ['单价', '5.5', '3.0'],
        })
        assert ColumnMapper.detect_header_row(df, min_matches=2) == 0

    def test_header_on_second_row(self):
        df = pd.DataFrame({
            'A': ['备注', '条码', '123456'],
            'B': ['日期', '数量', '10'],
            'C': ['时间', '单价', '5.5'],
        })
        assert ColumnMapper.detect_header_row(df, min_matches=2) == 1

    def test_no_header_returns_minus_one(self):
        df = pd.DataFrame({
            'A': ['aaa', 'bbb', 'ccc'],
            'B': ['ddd', 'eee', 'fff'],
        })
        assert ColumnMapper.detect_header_row(df, min_matches=3) == -1

    def test_empty_dataframe(self):
        df = pd.DataFrame()
        assert ColumnMapper.detect_header_row(df) == -1

    def test_max_rows_limits_scan(self):
        """表头在第 10 行但 max_rows=5 时应返回 -1"""
        data = {f'col{i}': ['x'] * 15 for i in range(3)}
        data['col0'][10] = '条码'
        data['col1'][10] = '数量'
        data['col2'][10] = '单价'
        df = pd.DataFrame(data)
        assert ColumnMapper.detect_header_row(df, max_rows=5, min_matches=2) == -1


class TestColumnMapperInstance:
    """ColumnMapper 实例方法测试"""

    def test_init_with_no_config(self):
        mapper = ColumnMapper()
        assert mapper.mapping_config == {}

    def test_init_with_custom_config(self):
        mapper = ColumnMapper(mapping_config={'barcode': ['我的条码']})
        assert '我的条码' in mapper.custom_mappings

    def test_map_columns_renames(self):
        mapper = ColumnMapper()
        df = pd.DataFrame({'商品条码': ['123'], '商品名称': ['测试'], '数量': [10]})
        result = mapper.map_columns(df, target_columns=['barcode', 'name', 'quantity'])
        assert 'barcode' in result.columns
        assert 'name' in result.columns
        assert 'quantity' in result.columns

    def test_map_columns_fills_missing(self):
        mapper = ColumnMapper()
        df = pd.DataFrame({'商品条码': ['123']})
        result = mapper.map_columns(df, target_columns=['barcode', 'quantity'])
        assert 'barcode' in result.columns
        assert 'quantity' in result.columns
        assert result['quantity'].iloc[0] == 0  # default value

    def test_add_custom_mapping(self):
        mapper = ColumnMapper()
        mapper.add_custom_mapping('barcode', '自定义条码列')
        assert '自定义条码列' in mapper.reverse_mapping
        assert mapper.reverse_mapping['自定义条码列'] == 'barcode'
