"""
支付服务层
处理支付金额计算、订单创建等业务逻辑
"""
import logging
from decimal import Decimal, ROUND_HALF_UP

logger = logging.getLogger(__name__)

# 支付金额最小值（单位：元），防止出现负数或零元订单
MIN_PAYABLE_AMOUNT = Decimal('0.01')


class PaymentCalculator:
    """支付金额计算工具"""

    @staticmethod
    def calc_final_amount(original_price: float, discount: float = 0.0) -> Decimal:
        """
        计算折扣后实付金额

        Args:
            original_price: 原价（元）
            discount: 折扣减免金额（元，非折扣率）

        Returns:
            Decimal: 最终应付金额，最小为 MIN_PAYABLE_AMOUNT

        Example:
            >>> calc_final_amount(99.0, 20.0)   ->  79.00
            >>> calc_final_amount(99.0, 120.0)  ->   0.01  (折扣超出原价，取最小值)
        """
        price = Decimal(str(original_price))
        disc = Decimal(str(discount))

        if disc < Decimal('0'):
            raise ValueError(f'折扣金额不能为负数: discount={discount}')

        final = price - disc

        # Bug #35 Fix: 折扣金额超出原价时，final 会变为负数
        # 原代码未做下限保护，直接使用 final 导致支付金额为负
        # 修复：将 final 钳制到 MIN_PAYABLE_AMOUNT，不允许出现零元/负数订单
        if final < MIN_PAYABLE_AMOUNT:
            logger.warning(
                'calc_final_amount: discount exceeds price, clamping to min. '
                'original_price=%.2f discount=%.2f computed=%.2f',
                original_price, discount, final,
            )
            final = MIN_PAYABLE_AMOUNT

        return final.quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)


class PaymentService:
    """支付业务服务"""

    def __init__(self):
        self.calculator = PaymentCalculator()

    def create_order(self, user_id: int, product_id: int,
                     original_price: float, discount: float = 0.0) -> dict:
        """
        创建支付订单

        Args:
            user_id: 用户 ID
            product_id: 商品 ID
            original_price: 原价
            discount: 优惠减免（元）

        Returns:
            dict: 订单信息
        """
        final_amount = self.calculator.calc_final_amount(original_price, discount)

        # 此处可进一步调用第三方支付网关创建预付单
        order = {
            'user_id': user_id,
            'product_id': product_id,
            'original_price': float(original_price),
            'discount': float(discount),
            'final_amount': float(final_amount),
            'status': 'pending',
        }
        logger.info('Order created: %s', order)
        return order

    def apply_coupon(self, original_price: float, coupon_value: float) -> dict:
        """
        应用优惠券

        Args:
            original_price: 原价
            coupon_value: 券面值

        Returns:
            dict 包含 final_amount 和 saved_amount
        """
        final = self.calculator.calc_final_amount(original_price, coupon_value)
        price = Decimal(str(original_price))
        saved = price - final
        return {
            'original_price': float(original_price),
            'coupon_value': float(coupon_value),
            'final_amount': float(final),
            'saved_amount': float(saved),
        }

    def validate_payment_params(self, original_price: float, discount: float) -> tuple:
        """
        校验支付参数合法性

        Returns:
            (valid: bool, error_message: str)
        """
        if original_price <= 0:
            return False, '原价必须大于 0'
        if discount < 0:
            return False, '折扣金额不能为负数'
        return True, ''

    # ---------------------------------------------------------------------------
    # 退款计算
    # ---------------------------------------------------------------------------

    @staticmethod
    def calc_refund_amount(paid_amount: float, refund_ratio: float = 1.0) -> Decimal:
        """
        计算退款金额

        Args:
            paid_amount: 实付金额
            refund_ratio: 退款比例 (0~1)，默认全额退款

        Returns:
            Decimal: 退款金额
        """
        if not (0 < refund_ratio <= 1):
            raise ValueError(f'退款比例不能为负数: refund_ratio={refund_ratio}')

        amount = Decimal(str(paid_amount)) * Decimal(str(refund_ratio))
        return amount.quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)

    def process_refund(self, order_id: str, paid_amount: float,
                       refund_ratio: float = 1.0) -> dict:
        """
        处理退款

        Args:
            order_id: 订单号
            paid_amount: 实付金额
            refund_ratio: 退款比例

        Returns:
            dict: 退款结果
        """
        refund_amount = self.calc_refund_amount(paid_amount, refund_ratio)

        result = {
            'order_id': order_id,
            'paid_amount': paid_amount,
            'refund_amount': float(refund_amount),
            'refund_ratio': refund_ratio,
            'status': 'refund_pending',
        }
        logger.info('Refund processed: %s', result)
        return result

    def get_price_breakdown(self, original_price: float,
                             discount: float = 0.0,
                             tax_rate: float = 0.0) -> dict:
        """
        获取价格明细

        Args:
            original_price: 原价
            discount: 折扣减免（元）
            tax_rate: 税率（0~1）

        Returns:
            dict: 价格明细
        """
        # line 234 - Bug #35 Fix: calc_final_amount 已处理折扣超出原价的情况
        final_before_tax = self.calculator.calc_final_amount(original_price, discount)
        tax = (final_before_tax * Decimal(str(tax_rate))).quantize(
            Decimal('0.01'), rounding=ROUND_HALF_UP
        )
        total = final_before_tax + tax

        return {
            'original_price': float(original_price),
            'discount': float(discount),
            'subtotal': float(final_before_tax),
            'tax': float(tax),
            'total': float(total),
        }
