from dataclasses import dataclass
import pygame
import math
from . import data
import json

class NotFoundPositionError(Exception): __module__ = "builtins"

class AnimationSprite:
    def __init__(self, x, y, w, h):
        super().__init__()
        self.rect = pygame.Rect(x, y, w, h)
        self.world_x = x
        self.world_y = y
        self.origin_w = self.rect.width
        self.origin_h = self.rect.height
        self.animating = False
        self.start_x = 0
        self.start_y = 0
        self.target_x = 0
        self.target_y = 0
        self.current_time = 0
        self.total_time = 0
        
        # 默认值
        self.original_image = None
        self.image = None
    
    def move_to_position_in(self, target_world_x, target_world_y, time):
        self.animating = True
        self.start_x = self.world_x  # 保存世界坐标
        self.start_y = self.world_y
        self.target_x = target_world_x
        self.target_y = target_world_y
        self.current_time = 0
        self.total_time = time

    
    def update_animation(self):
        if not self.animating:
            return
        
        self.current_time += 1
        t = self.current_time / self.total_time
        
        if t >= 1:
            self.world_x = self.target_x
            self.world_y = self.target_y
            self.animating = False
        else:
            self.world_x = self.start_x + (self.target_x - self.start_x) * t
            self.world_y = self.start_y + (self.target_y - self.start_y) * t
        # 注意：这里不直接修改 rect，让 update_position 去处理

        # 缩放图像（如果子类有 image 属性）
        if hasattr(self, 'image') and hasattr(self, 'original_image') and self.original_image is not None:  # 添加 None 检查
            new_size = (max(1, int(self.rect.width)), max(1, int(self.rect.height)))
            self.image = pygame.transform.scale(self.original_image, new_size)


    def _rotate_point(self, x, y, cx, cy, angle_deg):
        """绕某点旋转坐标"""
        if angle_deg == 0:
            return x, y
        
        angle_rad = math.radians(angle_deg)
        cos = math.cos(angle_rad)
        sin = math.sin(angle_rad)
        
        # 平移至原点
        dx = x - cx
        dy = y - cy
        
        # 旋转
        new_x = dx * cos - dy * sin
        new_y = dx * sin + dy * cos
        
        # 平移回来
        return new_x + cx, new_y + cy
            

    def update_position(self):
        if data.camera_size <= 0:
            data.camera_size = 0.001
        
        scale = 1 / data.camera_size
        
        # 计算相对于相机中心的世界坐标偏移
        dx = self.world_x - data.camera_position["x"]
        dy = self.world_y - data.camera_position["y"]
        
        # 应用相机旋转（绕相机中心旋转）
        rx, ry = self._rotate_point(dx, dy, 0, 0, data.camera_d)
        
        # 缩放并转换到屏幕坐标
        self.rect.x = rx * scale + data.screen_center["x"]
        self.rect.y = ry * scale + data.screen_center["y"]
        
        # 更新大小
        self.rect.width = max(1, int(self.origin_w * scale))
        self.rect.height = max(1, int(self.origin_h * scale))
        
        # 如果有图像，进行缩放
        if self.original_image is not None:
            # 先缩放（基于原始尺寸）
            scaled = pygame.transform.scale(self.original_image, 
                                            (self.origin_w, self.origin_h))
            # 再旋转
            rotated = pygame.transform.rotate(scaled, -data.camera_d)
            # 再缩放到目标大小（这样可以保持大小稳定）
            self.image = pygame.transform.scale(rotated, 
                                                (self.rect.width, self.rect.height))
            self.rect = self.image.get_rect(center=self.rect.center)

    def update_pf(self):
        """
        Complete update method: Update animation and position. Call this function in the main loop.


        完整的更新方法：更新动画和位置
        在主循环中调用这个函数即可
        """
        self.update_animation()
        self.update_position()


    def get_position(self):
        return json.dumps({"x": self.world_x, "y": self.world_y})

class AnimationBackground:
    @dataclass
    class Data:
        can_rotate : bool = False
        can_go_with_camera : bool = False
        can_change_size : bool = False
        is_center_window : bool = False

    def __init__(self, x, y, w, h):
        super().__init__()
        self.rect = pygame.Rect(x, y, w, h)
        self.world_x = x
        self.world_y = y
        self.origin_w = self.rect.width  # 保存原始尺寸
        self.origin_h = self.rect.height

        self.move_speed = 6 # 越大越慢

        # 为子类准备的图像缩放支持
        self.original_image = None


    def _rotate_point(self, x, y, cx, cy, angle_deg):
        """绕某点旋转坐标"""
        if angle_deg == 0:
            return x, y
        
        angle_rad = math.radians(angle_deg)
        cos = math.cos(angle_rad)
        sin = math.sin(angle_rad)
        
        # 平移至原点
        dx = x - cx
        dy = y - cy
        
        # 旋转
        new_x = dx * cos - dy * sin
        new_y = dx * sin + dy * cos
        
        # 平移回来
        return new_x + cx, new_y + cy
            

    def update(self):
        if data.camera_size <= 0:
            data.camera_size = 0.001
        
        scale = 1 / data.camera_size
        
        # 计算相对于相机中心的世界坐标偏移
        dx = self.world_x - data.camera_position["x"]
        dy = self.world_y - data.camera_position["y"]
        
        # 应用相机旋转（绕相机中心旋转）
        rx, ry = self._rotate_point(dx, dy, 0, 0, data.camera_d)
        
        # 缩放并转换到屏幕坐标
        if self.Data.can_go_with_camera:
            self.rect.x = rx * scale + data.screen_center["x"] // self.move_speed
            self.rect.y = ry * scale + data.screen_center["y"] // self.move_speed
        elif self.Data.is_center_window:
            self.rect.x = data.screen_center["x"] - self.rect.width // 2
            self.rect.y = data.screen_center["y"] - self.rect.height // 2
        else:
            raise NotFoundPositionError(f"'{self.__class__.__name__}' not found window center position for background")
        
        # 更新大小
        self.rect.width = max(1, int(self.origin_w * scale))
        self.rect.height = max(1, int(self.origin_h * scale))
        
        # 如果有图像，进行缩放
        if self.Data.can_change_size and self.original_image is not None:
            # 缩放（基于原始尺寸）
            scaled = pygame.transform.scale(self.original_image, 
                                            (self.origin_w, self.origin_h))
                
            # 再旋转
            rotated = pygame.transform.rotate(scaled, -data.camera_d)

            # 再缩放到目标大小（这样可以保持大小稳定）
            self.image = pygame.transform.scale(rotated, 
                                                (self.rect.width, self.rect.height))
            self.rect = self.image.get_rect(center=self.rect.center)

    def set_background_move_speed(self, speed):
        self.move_speed = speed

__all__ = [
    'AnimationSprite', 
    'AnimationBackground', 
]