try:
    from .svector import vec2, vec3
    from .smath import sqrt, sign, map as clamp_value, pi  # map 可以用来做 clamp

except:
    from svector import vec2, vec3
    from smath import sqrt, sign, map as clamp_value, pi  # map 可以用来做 clamp
    

# ========== 2D几何类型 ==========

class Rect:
    """矩形 - 2D轴对齐矩形"""
    def __init__(self, x=0, y=0, w=0, h=0):
        self.x = x
        self.y = y
        self.w = w
        self.h = h
    
    # ----- 属性 -----
    @property
    def left(self): return self.x
    
    @property
    def right(self): return self.x + self.w
    
    @property
    def top(self): return self.y
    
    @property
    def bottom(self): return self.y + self.h
    
    @property
    def center(self):
        return vec2(self.x + self.w/2, self.y + self.h/2)
    
    @property
    def topleft(self):
        return vec2(self.x, self.y)
    
    @property
    def topright(self):
        return vec2(self.x + self.w, self.y)
    
    @property
    def bottomleft(self):
        return vec2(self.x, self.y + self.h)
    
    @property
    def bottomright(self):
        return vec2(self.x + self.w, self.y + self.h)

    @property
    def width(self):
        return self.w

    @property
    def height(self):
        return self.h
    
    # ----- 碰撞检测 -----
    def collide_rect(self, other):
        """矩形与矩形碰撞"""
        return (self.x < other.x + other.w and
                self.x + self.w > other.x and
                self.y < other.y + other.h and
                self.y + self.h > other.y)
    
    def collide_point(self, x, y=None):
        """点与矩形碰撞"""
        if y is None:  # 如果传入的是 vec2
            x, y = x.x, x.y
        return (self.x <= x <= self.x + self.w and
                self.y <= y <= self.y + self.h)
    
    def collide_circle(self, circle):
        """矩形与圆碰撞"""
        # 找矩形上离圆心最近的点
        closest_x = max(self.x, min(circle.center.x, self.x + self.w))
        closest_y = max(self.y, min(circle.center.y, self.y + self.h))
        dx = circle.center.x - closest_x
        dy = circle.center.y - closest_y
        return (dx*dx + dy*dy) <= circle.radius * circle.radius
    
    # ----- 变换 -----
    def inflate(self, dw, dh):
        """扩展矩形"""
        return Rect(
            self.x - dw/2,
            self.y - dh/2,
            self.w + dw,
            self.h + dh
        )

    def expand(self, *args):
        """扩展矩形以包含点或另一个矩形
        
        用法:
            rect.expand(x, y)          # 包含点
            rect.expand(vec2(10,20))   # 包含点
            rect.expand(other_rect)    # 包含矩形
        """
        if len(args) == 1:
            arg = args[0]
            if isinstance(arg, Rect):
                # 包含矩形
                new_x = min(self.x, arg.x)
                new_y = min(self.y, arg.y)
                new_w = max(self.right, arg.right) - new_x
                new_h = max(self.bottom, arg.bottom) - new_y
                return Rect(new_x, new_y, new_w, new_h)
            else:
                # 包含点（vec2 或 元组）
                if hasattr(arg, 'x') and hasattr(arg, 'y'):
                    x, y = arg.x, arg.y
                else:
                    x, y = arg[0], arg[1]
        else:
            # 包含点 (x, y)
            x, y = args[0], args[1]
        
        # 包含点的逻辑
        new_x = min(self.x, x)
        new_y = min(self.y, y)
        new_w = max(self.right, x) - new_x
        new_h = max(self.bottom, y) - new_y
        return Rect(new_x, new_y, new_w, new_h)

    
    @property
    def area(self):
        return self.w * self.h
    
    
    def move(self, dx, dy):
        """移动矩形"""
        return Rect(self.x + dx, self.y + dy, self.w, self.h)
    
    def union(self, other):
        """合并两个矩形"""
        x = min(self.x, other.x)
        y = min(self.y, other.y)
        w = max(self.right, other.right) - x
        h = max(self.bottom, other.bottom) - y
        return Rect(x, y, w, h)
    
    # ----- 辅助 -----
    def __repr__(self):
        return f"Rect({self.x}, {self.y}, {self.w}, {self.h})"


class Circle:
    """圆形"""
    def __init__(self, center, radius):
        self.center = center if isinstance(center, vec2) else vec2(center[0], center[1])
        self.radius = radius
    
    def collide_point(self, x, y=None):
        """点与圆碰撞"""
        if y is None:
            x, y = x.x, x.y
        dx = x - self.center.x
        dy = y - self.center.y
        return (dx*dx + dy*dy) <= self.radius * self.radius

    @property
    def area(self):
        return self.radius ** 2 * pi
    
    def collide_circle(self, other):
        """圆与圆碰撞"""
        dx = self.center.x - other.center.x
        dy = self.center.y - other.center.y
        return (dx*dx + dy*dy) <= (self.radius + other.radius) ** 2
    
    def collide_rect(self, rect):
        """圆与矩形碰撞（复用Rect的碰撞）"""
        return rect.collide_circle(self)
    
    def __repr__(self):
        return f"Circle({self.center}, {self.radius})"


class Line2:
    """2D线段"""
    def __init__(self, p1, p2):
        self.p1 = p1 if isinstance(p1, vec2) else vec2(p1[0], p1[1])
        self.p2 = p2 if isinstance(p2, vec2) else vec2(p2[0], p2[1])
    
    def length(self):
        """线段长度"""
        dx = self.p2.x - self.p1.x
        dy = self.p2.y - self.p1.y
        return sqrt(dx*dx + dy*dy)
    
    def closest_point(self, p):
        """线段上离点p最近的点"""
        p = p if isinstance(p, vec2) else vec2(p[0], p[1])
        
        # 向量
        ab = vec2(self.p2.x - self.p1.x, self.p2.y - self.p1.y)
        ap = vec2(p.x - self.p1.x, p.y - self.p1.y)
        
        # 投影系数 t
        ab_len2 = ab.x*ab.x + ab.y*ab.y
        if ab_len2 == 0:  # 线段退化成点
            return self.p1
        
        t = (ap.x*ab.x + ap.y*ab.y) / ab_len2
        t = max(0, min(1, t))  # 限制在线段范围内
        
        return vec2(
            self.p1.x + t * ab.x,
            self.p1.y + t * ab.y
        )
    
    def collide_point(self, x, y=None, tolerance=0.1):
        """点是否在线段上（在容差范围内）"""
        if y is None:
            x, y = x.x, x.y
        p = vec2(x, y)
        closest = self.closest_point(p)
        dx = p.x - closest.x
        dy = p.y - closest.y
        return (dx*dx + dy*dy) <= tolerance * tolerance
    
    def intersect_line(self, other):
        """线段与线段相交检测"""
        # 参数方程
        x1, y1 = self.p1.x, self.p1.y
        x2, y2 = self.p2.x, self.p2.y
        x3, y3 = other.p1.x, other.p1.y
        x4, y4 = other.p2.x, other.p2.y
        
        denom = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4)
        if denom == 0:  # 平行
            return None
        
        t = ((x1 - x3) * (y3 - y4) - (y1 - y3) * (x3 - x4)) / denom
        u = -((x1 - x2) * (y1 - y3) - (y1 - y2) * (x1 - x3)) / denom
        
        if 0 <= t <= 1 and 0 <= u <= 1:
            x = x1 + t * (x2 - x1)
            y = y1 + t * (y2 - y1)
            return vec2(x, y)
        return None
    
    def __repr__(self):
        return f"Line2({self.p1}, {self.p2})"


# ========== 3D几何类型 ==========

class AABB:
    """轴对齐包围盒（3D）"""
    def __init__(self, min_point, max_point):
        self.min = min_point if isinstance(min_point, vec3) else vec3(*min_point)
        self.max = max_point if isinstance(max_point, vec3) else vec3(*max_point)
    
    @property
    def center(self):
        return vec3(
            (self.min.x + self.max.x) / 2,
            (self.min.y + self.max.y) / 2,
            (self.min.z + self.max.z) / 2
        )
    
    def collide_point(self, x, y=None, z=None):
        """点与AABB碰撞"""
        if y is None and z is None and isinstance(x, vec3):
            x, y, z = x.x, x.y, x.z
        return (self.min.x <= x <= self.max.x and
                self.min.y <= y <= self.max.y and
                self.min.z <= z <= self.max.z)
    
    def collide_aabb(self, other):
        """AABB与AABB碰撞"""
        return (self.min.x <= other.max.x and
                self.max.x >= other.min.x and
                self.min.y <= other.max.y and
                self.max.y >= other.min.y and
                self.min.z <= other.max.z and
                self.max.z >= other.min.z)
    
    def __repr__(self):
        return f"AABB({self.min}, {self.max})"


class Sphere:
    """球体"""
    def __init__(self, center, radius):
        self.center = center if isinstance(center, vec3) else vec3(*center)
        self.radius = radius
    
    def collide_point(self, x, y=None, z=None):
        """点与球体碰撞"""
        if y is None and z is None and isinstance(x, vec3):
            x, y, z = x.x, x.y, x.z
        dx = x - self.center.x
        dy = y - self.center.y
        dz = z - self.center.z
        return (dx*dx + dy*dy + dz*dz) <= self.radius * self.radius
    
    def collide_sphere(self, other):
        """球与球碰撞"""
        dx = self.center.x - other.center.x
        dy = self.center.y - other.center.y
        dz = self.center.z - other.center.z
        return (dx*dx + dy*dy + dz*dz) <= (self.radius + other.radius) ** 2
    
    def __repr__(self):
        return f"Sphere({self.center}, {self.radius})"
    
    @property
    def area(self):
        """表面积 4πr²"""
        return 4 * pi * self.radius ** 2
    
    @property
    def volume(self):
        """体积 (4/3)πr³"""
        return (4/3) * pi * self.radius ** 3


# ========== 高级碰撞函数 ==========

def raycast_rect(ray_origin, ray_dir, rect):
    """射线与矩形碰撞检测（返回碰撞点和距离）"""
    # 实现射线与AABB的碰撞
    t_min = -float('inf')
    t_max = float('inf')
    
    for i in range(2):  # x 和 y 轴
        if ray_dir[i] != 0:
            t1 = (rect.x - ray_origin[i]) / ray_dir[i]
            t2 = (rect.x + rect.w - ray_origin[i]) / ray_dir[i]
            t_min = max(t_min, min(t1, t2))
            t_max = min(t_max, max(t1, t2))
    
    if t_max >= t_min and t_max > 0:
        t = t_min if t_min > 0 else t_max
        return vec2(
            ray_origin.x + t * ray_dir.x,
            ray_origin.y + t * ray_dir.y
        ), t
    return None, None


def reflect(vector, normal):
    """反射向量"""
    # R = V - 2*(V·N)*N
    dot = vector.x * normal.x + vector.y * normal.y
    return vec2(
        vector.x - 2 * dot * normal.x,
        vector.y - 2 * dot * normal.y
    )


# ========== 快捷函数 ==========

def rect(x=0, y=0, w=0, h=0):
    """创建矩形"""
    return Rect(x, y, w, h)

def circle(center, radius):
    """创建圆形"""
    return Circle(center, radius)

def line(p1, p2):
    """创建线段"""
    return Line2(p1, p2)

def aabb(min_point, max_point):
    """创建AABB"""
    return AABB(min_point, max_point)

def sphere(center, radius):
    """创建球体"""
    return Sphere(center, radius)
