import pygame
import math
import random
from submodules.robot_controller_base.robot_controller import RobotController

class Fire:
    def __init__(self, x, y, radius):
        self.x = x
        self.y = y
        self.radius = radius
        
class DummySimRobot(RobotController):
    def __init__(self, config, stats_path='./stats'):
        super().__init__(
            fire_ext_max_capacity=config.INITIAL_FIRE_CHARGE,
            collision_damage=config.COLLISION_DAMAGE,
            k_sof=config.SCORE_PER_FIRE,
            k_cas=1,
            k_asset=1,
            k_hp=1,
            k_charge=1,
            fall_damage=10
        )

        pygame.init()
        self.width = config.MAP_WIDTH
        self.height = config.MAP_HEIGHT
        self.screen = pygame.display.set_mode((self.width, self.height))
        pygame.display.set_caption("Robot Simulator – Extinguish Fires")
        self.clock = pygame.time.Clock()
        self.font = pygame.font.SysFont(None, 28)
        
        border_thickness = config.BORDER_THICKNESS
        if border_thickness > 0:
            border_obstacles = [
                (0, 0, self.width, border_thickness),
                (0, self.height - border_thickness, self.width, border_thickness),
                (0, 0, border_thickness, self.height),
                (self.width - border_thickness, 0, border_thickness, self.height)
            ]
            self.obstacles = list(config.MAP_OBSTACLES) + border_obstacles
        else:
            self.obstacles = list(config.MAP_OBSTACLES)
            
        self.start = config.START_POS
        self.finish = config.FINISH_POS
        self.robot_radius = config.ROBOT_RADIUS
        self.robot_image = None
        
        if config.ROBOT_IMAGE_PATH:
            try:
                self.robot_image = pygame.image.load(config.ROBOT_IMAGE_PATH)
                self.robot_image = pygame.transform.scale(self.robot_image, (self.robot_radius*2, self.robot_radius*2))
            except:
                pass
            
        self.extinguish_radius = config.EXTINGUISH_RADIUS
        self.extinguish_angle = math.radians(config.EXTINGUISH_ANGLE)
        self.score_per_fire = config.SCORE_PER_FIRE
        self.num_fires = config.NUM_FIRES
        self.fire_radius = config.FIRE_RADIUS
        
        self.extinguish_active = False
        self.extinguish_timer = 0
        self.extinguish_cooldown = 0
        self.invincibility_timer = 0

        self.x, self.y = self.start
        self.angle = 0.0
        self.linear_speed = 0.0
        self.angular_speed = 0.0

        self.game_over = False
        self.won = False

        self.fires = []
        self._generate_fires()

        # Параметры для сохранения статистики
        self.stats_path = stats_path
        self._stats_saved = False
        self._last_stats_path = None
        
    def _generate_fires(self):
        self.fires.clear()
        attempts = 0
        margin = 30 # минимальное расстояние между центрами костров

        while len(self.fires) < self.num_fires and attempts < 2000:
            fx = random.randint(self.robot_radius + 10, self.width - self.robot_radius - 10)
            fy = random.randint(self.robot_radius + 10, self.height - self.robot_radius - 10)

            # Проверка: не на препятствии
            if self._point_collides_with_obstacle(fx, fy, self.robot_radius):
                attempts += 1
                continue

            # Проверка: не слишком близко к старту
            if math.hypot(fx - self.start[0], fy - self.start[1]) < self.robot_radius * 3:
                attempts += 1
                continue

            # Проверка: не слишком близко к финишу
            if math.hypot(fx - self.finish[0], fy - self.finish[1]) < self.robot_radius * 3:
                attempts += 1
                continue

            # Проверка: не пересекается с уже существующими кострами
            overlap = False
            for fire in self.fires:
                if math.hypot(fx - fire.x, fy - fire.y) < 2 * self.fire_radius + margin:
                    overlap = True
                    break
            if overlap:
                attempts += 1
                continue

            self.fires.append(Fire(fx, fy, self.fire_radius))
            attempts += 1

        print(f"Сгенерировано {len(self.fires)} очагов возгорания")
            
    def _point_collides_with_obstacle(self, x, y, radius):
        for ox, oy, ow, oh in self.obstacles:
            closest_x = max(ox, min(x, ox + ow))
            closest_y = max(oy, min(y, oy + oh))
            if math.hypot(x - closest_x, y - closest_y) < radius:
                return True
        return False

    def _is_fire_in_front(self, fire):
        """Проверяет, находится ли огонь в зоне тушения"""
        dx = fire.x - self.x
        dy = fire.y - self.y
        dist = math.hypot(dx, dy)
        if dist > self.extinguish_radius:
            return False

        angle_to_fire = math.atan2(dy, dx)
        angle_diff = angle_to_fire - self.angle
        angle_diff = (angle_diff + math.pi) % (2*math.pi) - math.pi

        return abs(angle_diff) <= self.extinguish_angle / 2
    
    def send_speed_cmd(self, v, w):
        """Отправка команды скорости с проверкой заряда"""
        self._check_time_init()
        if self._charge_points == 0:
            return 0, 0

        v = min(max(-1, v), 1)
        w = min(max(-1, w), 1)

        self.linear_speed = v
        self.angular_speed = w

        return v, w
        
    def send_fire_ext_burst_cmd(self):
        """Команда тушения огня"""
        self._check_time_init()

        if self.extinguish_cooldown > 0 or self.extinguish_active:
            return False
        if self._fire_ext_capacity <= 0:
            return False
        
        self.extinguish_active = True
        self.extinguish_timer = 30
        self.extinguish_cooldown = 10
        
        self._fire_ext_capacity -= 1
        
        extinguished = False
        
        for fire in self.fires[:]:
            if self._is_fire_in_front(fire):
                self.fires.remove(fire)
                self._register_exted_sof({
                    'x': fire.x,
                    'y': fire.y,
                    'radius': fire.radius
                })
                extinguished = True
                break

        return extinguished

    def send_fire_ext_pose_cmd(self, horizontal_pose, vertical_pose):
        """Команда позиции огнетушителя"""
        self._check_time_init()
        raise NotImplementedError("Fire extinguish not implemented in DummySimRobot")

    def send_pick_asset_cmd(self):
        """Команда подбора объекта"""
        self._check_time_init()
        raise NotImplementedError("Pick asset not implemented in DummySimRobot")

    def send_lights_cmd(self):
        """Команда включения света"""
        self._check_time_init()
        raise NotImplementedError("Turn  on the light not implemented in DummySimRobot")

    def send_fall_reset_cmd(self):
        """Команда сброса после падения"""
        self._check_time_init()
        raise NotImplementedError("Fall can't be implemented DummySimRobot")
    
    def update(self, dt=1/30.0):
        if self.game_over or self.won:
            return

        # Уменьшение заряда
        if self.linear_speed != 0:
            self._decrease_charge(abs(self.linear_speed), dt)
        
        # Обновление таймеров
        if self.invincibility_timer > 0:
            self.invincibility_timer -= 1
        if self.extinguish_timer > 0:
            self.extinguish_timer -= 1
            if self.extinguish_timer == 0:
                self.extinguish_active = False
        if self.extinguish_cooldown > 0:
            self.extinguish_cooldown -= 1
        
        # Движение
        self.angle += self.angular_speed * dt * 2
        dx = self.linear_speed * math.cos(self.angle) * dt * 100
        dy = self.linear_speed * math.sin(self.angle) * dt * 100
        new_x = self.x + dx
        new_y = self.y + dy
        
        # Проверка: столкновение
        if self._point_collides_with_obstacle(new_x, new_y, self.robot_radius):
            if self.invincibility_timer == 0:
                self._register_collision()
                self.invincibility_timer = 30
        else:
            self.x, self.y = new_x, new_y
        
        # Проверка победы/поражения
        if math.hypot(self.x - self.finish[0], self.y - self.finish[1]) < self.robot_radius:
            self.won = True
            self._save_statistics()
        if self._hit_points <= 0:
            self.game_over = True
            self._save_statistics()
        if self._charge_points <= 0:
            self.game_over = True
            self._save_statistics()
            
    def draw(self):
        """Отрисовка симуляции"""
        self.screen.fill((255,255,255))
        
        # Препятствия
        for ox, oy, ow, oh in self.obstacles:
            pygame.draw.rect(self.screen, (100,100,100), (ox, oy, ow, oh))
        
        # Финиш
        pygame.draw.circle(self.screen, (0,200,0), (int(self.finish[0]), int(self.finish[1])), self.robot_radius, 3)
        
        # Костры
        for fire in self.fires:
            pygame.draw.circle(self.screen, (255,0,0), (int(fire.x), int(fire.y)), fire.radius)
            pygame.draw.circle(self.screen, (255,100,0), (int(fire.x), int(fire.y)), fire.radius-3)
        
        # Конус тушения
        if self.extinguish_active:
            cone_surface = pygame.Surface((self.width, self.height), pygame.SRCALPHA)
            num_points = 20
            points = [(self.x, self.y)]
            half_angle = self.extinguish_angle / 2
            cone_len = self.extinguish_radius
            for i in range(num_points + 1):
                angle = self.angle - half_angle + (self.extinguish_angle) * (i / num_points)
                x = self.x + cone_len * math.cos(angle)
                y = self.y + cone_len * math.sin(angle)
                points.append((x, y))
            if len(points) > 2:
                pygame.draw.polygon(cone_surface, (0, 200, 255, 80), points)
            self.screen.blit(cone_surface, (0, 0))
        
        # Робот
        if self.invincibility_timer > 0 and (self.invincibility_timer % 6 < 3):
            pass # Мигание
        else:
            if self.robot_image:
                rotated = pygame.transform.rotate(self.robot_image, -math.degrees(self.angle))
                rect = rotated.get_rect(center=(int(self.x), int(self.y)))
                self.screen.blit(rotated, rect)
            else:
                nose = (self.x + self.robot_radius * math.cos(self.angle),
                        self.y + self.robot_radius * math.sin(self.angle))
                left = (self.x + self.robot_radius * math.cos(self.angle + 2.5),
                        self.y + self.robot_radius * math.sin(self.angle + 2.5))
                right = (self.x + self.robot_radius * math.cos(self.angle - 2.5),
                        self.y + self.robot_radius * math.sin(self.angle - 2.5))
                pygame.draw.polygon(self.screen, (0,0,255), [nose, left, right])
            
        # Статистика
        hp_text = self.font.render(f"HP: {self._hit_points}", True, (0,0,0))
        charge_text = self.font.render(f"Charge: {self._charge_points:.1f}", True, (0,0,0))
        fire_charge_text = self.font.render(f"Fire charges: {self._fire_ext_capacity}", True, (0,0,0))
        score_text = self.font.render(f"Score: {self.get_score():.2f}", True, (0,0,0))
        #fires_text = self.font.render(f"Fires left: {len(self.fires)}", True, (0,0,0))
        self.screen.blit(hp_text, (10, 10))
        self.screen.blit(charge_text, (10, 40))
        self.screen.blit(fire_charge_text, (10, 70))
        self.screen.blit(score_text, (10, 100))
        
        # Конец игры
        if self.game_over:
            msg = self.font.render("GAME OVER – Press R to restart", True, (255,0,0))
            self.screen.blit(msg, (self.width//2 - 150, self.height//2))
        elif self.won:
            msg = self.font.render("YOU WIN! – Press R to restart", True, (0,100,0))
            self.screen.blit(msg, (self.width//2 - 120, self.height//2))

        pygame.display.flip()

    def _save_statistics(self):
        """Сохраняет статистику при окончании игры"""
        if not self._stats_saved:
            self._last_stats_path = self.dump_stats(save_path=self.stats_path)
            self._stats_saved = True
            print(f"\n{'='*50}")
            print(f"GAME {'WON' if self.won else 'OVER'}")
            print(f"Stats saved: {self._last_stats_path}")
            print(self.get_str_status())
            print(f"{'='*50}\n")
        
    def handle_events(self):
        """Обработка событий pygame"""
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                return False
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_r:
                    self.restart()
                elif event.key == pygame.K_BACKSPACE:
                    self.reset_position()
        return True
    
    def step(self):
        """Один шаг симуляции"""
        if not self.handle_events():
            return False
        self.update()
        self.draw()
        self.clock.tick(30)
        return True
    
    def restart(self):
        """Перезапуск игры"""
        self.x, self.y = self.start
        self.angle = 0.0
        self.linear_speed = 0.0
        self.angular_speed = 0.0

        # Сброс основных состояний
        self._hit_points = self._start_hp
        self._fire_ext_capacity = self._fire_ext_max_capacity
        self._charge_points = self._start_charge
        self._collisions.clear()
        self._exted_sofs.clear()
        self._found_casualty.clear()
        self._found_assets.clear()
        self._falls.clear()
        self._start_time = None

        # Сброс состояния симуляции
        self.game_over = False
        self.won = False
        self.invincibility_timer = 0
        self.extinguish_active = False
        self.extinguish_timer = 0
        self.extinguish_cooldown = 0

        self._stats_saved = False
        self._last_stats_path = None

        # Новая генерация костров
        self._generate_fires()
        
    def reset_position(self):
        """Сброс позиции робота"""
        if self.game_over or self.won:
            return
        self.x, self.y = self.start
        self.angle = 0.0
        self.linear_speed = 0.0
        self.angular_speed = 0.0

    def quit(self):
        """Завершение pygame"""
        pygame.quit()
    
