"""模块：分佣策略引擎
策略模式实现——每种分账方式独立封装，新增分账逻辑只需添加新策略类。

支持四种策略：
  PercentageStrategy: 比例分账  → TotalAmount × rate
  FixedStrategy:      固定金额   → 固定值（受保底/封顶约束）
  TieredStrategy:     阶梯分账   → 按次数/档位查表
  RemainderStrategy:  剩余归平台 → TotalAmount - SUM(其他参与者)
"""

from abc import ABC, abstractmethod
from decimal import Decimal
from typing import Dict, List, Optional
from gvsdsdk.commission.models import RateTable


class BaseSplitStrategy(ABC):
    """分账策略抽象基类"""

    def __init__(self, participant_rule: dict, rate_table: Optional[RateTable] = None):
        self._rule = participant_rule
        self._rate_table = rate_table

    @abstractmethod
    def Calculate(self, total_amount: Decimal, tier_index: int = 0, **context) -> Decimal:
        ...

    @property
    def Role(self):
        return self._rule.get('Role', 'unknown')

    @property
    def SplitType(self):
        return self._rule.get('Type', 'unknown')

    def _get_rate_from_table(self, key):
        if self._rate_table:
            rate = self._rate_table.GetRate(key)
            if rate is not None:
                return rate
        return self._rule.get('Rate', Decimal('0'))


class PercentageStrategy(BaseSplitStrategy):
    """比例分账策略

    配置示例:
        { role: 'worker', type: 'percentage', value: 0.80 }
        { role: 'worker', type: 'percentage', rate_table_key: '1' }
    """

    def Calculate(self, total_amount: Decimal, tier_index: int = 0, **context) -> Decimal:
        rate_key = self._rule.get('RateTableKey', '')
        if rate_key:
            rate = self._get_rate_from_table(rate_key)
        else:
            rate = Decimal(str(self._rule.get('Value', 0)))
        amount = total_amount * rate
        return self._apply_bounds(amount, total_amount)

    def _apply_bounds(self, amount, total_amount):
        minimum = self._rule.get('MinAmount')
        maximum = self._rule.get('MaxAmount')
        if minimum is not None:
            amount = max(amount, Decimal(str(minimum)))
        if maximum is not None:
            amount = min(amount, Decimal(str(maximum)))
        return amount


class FixedStrategy(BaseSplitStrategy):
    """固定金额策略

    配置示例:
        { role: 'agent', type: 'fixed', value: 10 }
        { role: 'leader', type: 'fixed', rate_table_key: 'guanshi_fc' }
    """

    def Calculate(self, total_amount: Decimal, tier_index: int = 0, **context) -> Decimal:
        rate_key = self._rule.get('RateTableKey', '')
        if rate_key:
            amount = self._get_rate_from_table(rate_key)
        else:
            amount = Decimal(str(self._rule.get('Value', 0)))
        return amount


class TieredStrategy(BaseSplitStrategy):
    """阶梯分账策略——按次数/档位查表

    配置示例:
        { role: 'agent', type: 'tiered',
          tiers: { 1: 5, 2: 8, 3: 10 } }
    或从费率表中按 key_N 形式查找。
    """

    def Calculate(self, total_amount: Decimal, tier_index: int = 0, **context) -> Decimal:
        tiers = self._rule.get('Tiers', {})
        if tiers:
            tier_key = str(tier_index)
            raw_value = tiers.get(tier_key, tiers.get('default', 0))
            if isinstance(raw_value, str) and raw_value.endswith('%'):
                return total_amount * Decimal(raw_value.rstrip('%')) / Decimal('100')
            return Decimal(str(raw_value))

        tier_key = self._rule.get('TierKeyPrefix', '')
        if tier_key and self._rate_table:
            rate = self._rate_table.GetRate(f'{tier_key}_{tier_index}')
            if rate is not None:
                return rate

        return Decimal('0')


class RemainderStrategy(BaseSplitStrategy):
    """剩余归平台策略——扣除所有其他参与者后的余额

    配置示例:
        { role: 'platform', type: 'remainder' }
    """

    def Calculate(self, total_amount: Decimal, tier_index: int = 0, **context) -> Decimal:
        allocated = context.get('AllocatedAmount', Decimal('0'))
        remainder = total_amount - allocated
        return remainder if remainder > 0 else Decimal('0')


class WithdrawalFeeStrategy(BaseSplitStrategy):
    """提现手续费策略

    配置示例:
        { role: 'platform', type: 'withdrawal_fee', value: 0.01 }
    """

    def Calculate(self, total_amount: Decimal, tier_index: int = 0, **context) -> Decimal:
        rate_key = self._rule.get('RateTableKey', '')
        if rate_key:
            rate = self._get_rate_from_table(rate_key)
        else:
            rate = Decimal(str(self._rule.get('Value', 0)))
        return total_amount * rate


STRATEGY_MAP: Dict[str, type] = {
    'percentage': PercentageStrategy,
    'fixed': FixedStrategy,
    'tiered': TieredStrategy,
    'remainder': RemainderStrategy,
    'withdrawal_fee': WithdrawalFeeStrategy,
}


def CreateStrategy(participant_rule: dict, rate_table: Optional[RateTable] = None) -> BaseSplitStrategy:
    split_type = participant_rule.get('Type', 'percentage')
    strategy_class = STRATEGY_MAP.get(split_type, PercentageStrategy)
    return strategy_class(participant_rule, rate_table)
