"""app.core.excel.validators 单元测试"""

import pytest
from app.core.excel.validators import ProductValidator


@pytest.fixture
def validator():
    return ProductValidator()


class TestValidateBarcode:
    """条码验证测试"""

    def test_valid_barcode_13_digits(self, validator):
        ok, val, err = validator.validate_barcode("6920584471055")
        assert ok is True
        assert val == "6920584471055"
        assert err is None

    def test_valid_barcode_8_digits(self, validator):
        ok, val, err = validator.validate_barcode("12345678")
        assert ok is True
        assert val == "12345678"

    def test_valid_barcode_12_digits(self, validator):
        ok, val, err = validator.validate_barcode("692058447105")
        assert ok is True

    def test_none_returns_invalid(self, validator):
        ok, val, err = validator.validate_barcode(None)
        assert ok is False
        assert err == "条码为空"

    def test_warehouse_identifier(self, validator):
        ok, val, err = validator.validate_barcode("仓库")
        assert ok is False
        assert val == "仓库"
        assert err == "条码为仓库标识"

    def test_warehouse_full_name(self, validator):
        ok, val, err = validator.validate_barcode("仓库全名")
        assert ok is False

    def test_prefix_5_to_6_correction(self, validator):
        """5开头(非53)的长条码应修正为6开头"""
        ok, val, err = validator.validate_barcode("5920584471055")
        assert ok is True
        assert val.startswith("6")
        assert val == "6920584471055"

    def test_prefix_53_not_corrected(self, validator):
        """53开头的条码不修正"""
        ok, val, err = validator.validate_barcode("5321545613000")
        assert ok is True
        assert val.startswith("53")

    def test_14_digit_trailing_zero_truncated(self, validator):
        """14位条码末尾是0时截断到13位"""
        ok, val, err = validator.validate_barcode("69205844710550")
        assert ok is True
        assert len(val) == 13

    def test_14_digit_no_trailing_zero_invalid(self, validator):
        """14位条码末尾不是0时报错"""
        ok, val, err = validator.validate_barcode("69205844710551")
        assert ok is False
        assert "长度异常" in err

    def test_too_short_invalid(self, validator):
        ok, val, err = validator.validate_barcode("1234567")
        assert ok is False
        assert "长度异常" in err

    def test_too_long_invalid(self, validator):
        ok, val, err = validator.validate_barcode("1" * 14)
        # 14 digits with trailing 0s gets truncated, but "111...1" has no trailing 0
        ok2, val2, err2 = validator.validate_barcode("1" * 15)
        assert ok2 is False

    def test_no_digits_invalid(self, validator):
        ok, val, err = validator.validate_barcode("abc")
        assert ok is False
        assert err == "条码不包含数字"

    def test_float_input_cleaned(self, validator):
        """浮点数输入应清理为整数字符串"""
        ok, val, err = validator.validate_barcode(6920584471055.0)
        assert ok is True
        assert val == "6920584471055"

    def test_special_barcode_5321545613(self, validator):
        """特殊条码 5321545613 应通过验证"""
        ok, val, err = validator.validate_barcode("5321545613")
        assert ok is True
        assert val == "5321545613"


class TestValidatePrice:
    """单价验证测试"""

    def test_valid_price(self, validator):
        ok, val, is_gift, err = validator.validate_price(10.5)
        assert ok is True
        assert val == 10.5
        assert is_gift is False

    def test_zero_price_is_gift(self, validator):
        ok, val, is_gift, err = validator.validate_price(0)
        assert ok is True
        assert val == 0.0
        assert is_gift is True

    def test_none_is_gift(self, validator):
        ok, val, is_gift, err = validator.validate_price(None)
        assert ok is False
        assert is_gift is True

    def test_gift_string(self, validator):
        ok, val, is_gift, err = validator.validate_price("赠品")
        assert ok is True
        assert is_gift is True

    def test_gift_english(self, validator):
        ok, val, is_gift, err = validator.validate_price("gift")
        assert ok is True
        assert is_gift is True

    def test_price_string_with_yen(self, validator):
        ok, val, is_gift, err = validator.validate_price("¥123.45")
        assert ok is True
        assert val == 123.45
        assert is_gift is False

    def test_price_string_with_comma(self, validator):
        ok, val, is_gift, err = validator.validate_price("1,234.56")
        assert ok is True
        assert val == 1234.56

    def test_negative_price_invalid(self, validator):
        ok, val, is_gift, err = validator.validate_price(-5)
        assert ok is False
        assert is_gift is True

    def test_empty_string_is_gift(self, validator):
        ok, val, is_gift, err = validator.validate_price("")
        assert ok is True
        assert is_gift is True


class TestValidateQuantity:
    """数量验证测试"""

    def test_valid_quantity(self, validator):
        ok, val, err = validator.validate_quantity(10)
        assert ok is True
        assert val == 10.0

    def test_float_quantity(self, validator):
        ok, val, err = validator.validate_quantity(2.5)
        assert ok is True
        assert val == 2.5

    def test_string_quantity(self, validator):
        ok, val, err = validator.validate_quantity("15")
        assert ok is True
        assert val == 15.0

    def test_string_with_unit(self, validator):
        ok, val, err = validator.validate_quantity("10瓶")
        assert ok is True
        assert val == 10.0

    def test_none_invalid(self, validator):
        ok, val, err = validator.validate_quantity(None)
        assert ok is False
        assert err == "数量为空"

    def test_zero_invalid(self, validator):
        ok, val, err = validator.validate_quantity(0)
        assert ok is False
        assert "必须大于0" in err

    def test_negative_invalid(self, validator):
        ok, val, err = validator.validate_quantity(-3)
        assert ok is False
        assert "必须大于0" in err

    def test_non_numeric_string_invalid(self, validator):
        ok, val, err = validator.validate_quantity("abc")
        assert ok is False
        assert err == "数量不包含数字"


class TestValidateProduct:
    """商品数据整体验证测试"""

    def test_valid_product(self, validator):
        product = {
            'barcode': '6920584471055',
            'price': 10.5,
            'quantity': 5,
            'amount': 52.5,
        }
        result = validator.validate_product(product)
        assert result['barcode'] == '6920584471055'
        assert result['price'] == 10.5
        assert result['quantity'] == 5.0
        assert result.get('is_gift') is None or result.get('is_gift') is False

    def test_gift_product(self, validator):
        product = {
            'barcode': '6920584471055',
            'price': '赠品',
            'quantity': 5,
        }
        result = validator.validate_product(product)
        assert result['is_gift'] is True
        assert result['price'] == 0.0

    def test_quantity_from_amount_and_price(self, validator):
        """数量为空时，通过金额/单价计算"""
        product = {
            'barcode': '6920584471055',
            'price': 10.0,
            'amount': 50.0,
            'quantity': None,
        }
        result = validator.validate_product(product)
        assert result['quantity'] == 5.0  # 50 / 10

    def test_invalid_barcode_still_uses_fixed(self, validator):
        """条码验证失败但有修复值时仍使用修复值"""
        product = {
            'barcode': '5920584471055',  # 5开头, 会被修正为6开头
            'price': 10.0,
            'quantity': 5,
        }
        result = validator.validate_product(product)
        assert result['barcode'] == '6920584471055'

    def test_amount_zero_marks_gift(self, validator):
        """金额为0时标记为赠品"""
        product = {
            'barcode': '6920584471055',
            'price': 10.0,
            'quantity': 5,
            'amount': 0,
        }
        result = validator.validate_product(product)
        assert result.get('is_gift') is True
