# tests combat : hitbox, cooldown, projectile

import math
from unittest.mock import AsyncMock

import pytest

from combat import circle_overlap, normalize
from constants import ATTACK_COOLDOWN, TICK_DURATION
from game_loop import GameLoop
from lobby import Lobby, LobbyPlayer


def make_game_loop(class_name="seris"):
    player = LobbyPlayer(conn_id="c1", username="Test", player_class=class_name, is_ready=True, is_host=True)
    lobby = Lobby(code="TEST01", players=[player], started=True)
    return GameLoop(lobby, AsyncMock())


def test_circle_overlap_overlapping():
    assert circle_overlap(0, 0, 1, 0.5, 0, 1) is True

def test_circle_overlap_far_apart():
    assert circle_overlap(0, 0, 0.5, 10, 10, 0.5) is False


def test_normalize_diagonal():
    dx, dy = normalize(1, 1)
    assert dx == pytest.approx(1 / math.sqrt(2))
    assert dy == pytest.approx(1 / math.sqrt(2))

def test_normalize_zero():
    assert normalize(0, 0) == (0.0, 0.0)


def test_cooldown_decroit():
    loop = make_game_loop()
    loop.state.players[0].cooldowns["attack"] = 0.5
    loop._update_cooldowns()
    assert loop.state.players[0].cooldowns["attack"] == pytest.approx(0.5 - TICK_DURATION)


def test_handle_attack_cree_projectile():
    loop = make_game_loop()
    p = loop.state.players[0]
    loop.handle_attack(p.id, p.x + 5, p.y)
    assert len(loop.state.projectiles) == 1
    assert p.cooldowns["attack"] == pytest.approx(ATTACK_COOLDOWN)


def test_handle_attack_bloque_par_cd():
    loop = make_game_loop()
    p = loop.state.players[0]
    p.cooldowns["attack"] = 0.5
    loop.handle_attack(p.id, p.x + 5, p.y)
    assert len(loop.state.projectiles) == 0


def test_projectile_se_deplace():
    loop = make_game_loop()
    p = loop.state.players[0]
    loop.handle_attack(p.id, p.x + 5, p.y)
    old_x = loop.state.projectiles[0].x
    loop._update_projectiles()
    assert loop.state.projectiles[0].x != old_x


def test_projectile_disparait_quand_ttl_zero():
    loop = make_game_loop()
    p = loop.state.players[0]
    loop.handle_attack(p.id, p.x + 5, p.y)
    loop.state.projectiles[0].ttl = 0.01
    loop._update_projectiles()
    assert len(loop.state.projectiles) == 0
