import math
import random
from typing import List, Tuple

class DamageCalculator:
    """
    一个模拟C++/PHP中范围圈伤害逻辑，并进行增强的Python风格实现。
    参考了范围伤害的区域检测和伤害计算概念[1,2](@ref)。
    """

    def __init__(self, base_damage: int, critical_rate: float = 0.1, critical_multiplier: float = 1.5):
        """
        初始化伤害计算器。

        :param base_damage: 基础伤害值
        :param critical_rate: 暴击率 (0.0 到 1.0)
        :param critical_multiplier: 暴击伤害 multiplier
        """
        self.base_damage = base_damage
        self.critical_rate = critical_rate
        self.critical_multiplier = critical_multiplier

    def calculate_radial_damage(self,
                               origin: Tuple[float, float],
                               target_position: Tuple[float, float],
                               inner_radius: float,
                               outer_radius: float) -> dict:
        """
        计算范围圈伤害，考虑距离衰减，并增强伤害（例如暴击）。

        :param origin: 伤害范围的中心点坐标 (x, y)
        :param target_position: 目标点的坐标 (x, y)
        :param inner_radius: 内半径，此范围内伤害不衰减[1](@ref)
        :param outer_radius: 外半径，超出此范围无伤害[1](@ref)
        :return: 包含最终伤害、是否暴击等信息的字典
        """
        distance = self._calculate_distance(origin, target_position)

        if distance > outer_radius:
            return {"damage": 0, "is_critical": False, "message": "目标超出伤害范围"}

        # 计算距离衰减因子[1](@ref)
        damage_multiplier = self._calculate_damage_falloff(distance, inner_radius, outer_radius)

        # 基础伤害计算
        raw_damage = int(self.base_damage * damage_multiplier)

        # 增强伤害：判断是否暴击
        is_critical = self._check_critical_hit()
        if is_critical:
            final_damage = int(raw_damage * self.critical_multiplier)
        else:
            final_damage = raw_damage

        return {
            "damage": final_damage,
            "is_critical": is_critical,
            "raw_damage": raw_damage,
            "distance": distance,
            "damage_multiplier": damage_multiplier
        }

    def _calculate_distance(self, point1: Tuple[float, float], point2: Tuple[float, float]) -> float:
        """计算两点之间的欧几里得距离。"""
        return math.sqrt((point2[0] - point1[0])**2 + (point2[1] - point1[1])**2)

    def _calculate_damage_falloff(self, distance: float, inner_radius: float, outer_radius: float) -> float:
        """
        根据距离计算伤害衰减因子。
        在内半径内为全额伤害，内半径到外半径之间线性衰减[1](@ref)。
        """
        if distance <= inner_radius:
            return 1.0
        elif distance <= outer_radius:
            # 线性衰减
            return 1.0 - (distance - inner_radius) / (outer_radius - inner_radius)
        else:
            return 0.0

    def _check_critical_hit(self) -> bool:
        """判断此次攻击是否暴击。"""
        return random.random() < self.critical_rate

    def get_targets_in_radius(self, origin: Tuple[float, float], potential_targets: List[Tuple], outer_radius: float) -> List[Tuple]:
        """
        获取在指定外半径内的所有目标。
        类似于范围检测[2](@ref)。
        """
        targets_in_range = []
        for target in potential_targets:
            # 假设target是一个包含位置信息的对象或元组
            target_pos = target # 这里需要根据你的实际数据结构调整，例如可能是target['position']或target.x, target.y
            if self._calculate_distance(origin, target_pos) <= outer_radius:
                targets_in_range.append(target)
        return targets_in_range


# 示例用法和测试
if __name__ == "__main__":
    # 初始化伤害计算器：基础伤害100，暴击率15%，暴击伤害倍率2.0
    dmg_calculator = DamageCalculator(base_damage=100, critical_rate=0.15, critical_multiplier=2.0)

    # 定义伤害范围：中心点(0,0)，内半径2.0，外半径5.0
    damage_origin = (0.0, 0.0)
    inner_rad = 2.0
    outer_rad = 5.0

    # 定义一些测试目标点
    test_targets = [
        ("目标1(内圈)", (1.0, 1.0)),
        ("目标2(中圈)", (3.0, 0.0)),
        ("目标3(外圈边缘)", (4.9, 0.0)),
        ("目标4(圈外)", (6.0, 0.0))
    ]

    print("=== 范围圈伤害计算示例（增强后） ===")
    print(f"基础伤害: {dmg_calculator.base_damage}")
    print(f"伤害范围: 内半径={inner_rad}, 外半径={outer_rad}")
    print(f"暴击率: {dmg_calculator.critical_rate*100}%, 暴击倍率: {dmg_calculator.critical_multiplier}x")
    print("-" * 50)

    for target_name, target_pos in test_targets:
        result = dmg_calculator.calculate_radial_damage(damage_origin, target_pos, inner_rad, outer_rad)
        if result["damage"] > 0:
            crit_text = " [暴击!]" if result["is_critical"] else ""
            print(f"{target_name} -> 最终伤害: {result['damage']}{crit_text} (距离: {result['distance']:.2f}, 衰减系数: {result['damage_multiplier']:.2f}, 未暴击基础伤害: {result['raw_damage']})")
        else:
            print(f"{target_name} -> 无伤害 (距离: {result['distance']:.2f}，超出范围)")

    # 演示获取范围内的目标
    print("\n=== 范围内目标检测示例 ===")
    all_potential_targets = [pos for _, pos in test_targets] # 提取位置信息
    targets_in_radius = dmg_calculator.get_targets_in_radius(damage_origin, all_potential_targets, outer_rad)
    print(f"在伤害外半径内的目标坐标有: {targets_in_radius}")