"""
Tests for weather engines.
"""

import pytest
from soracli.engines.base import BaseWeatherEngine, EngineConfig, Particle
from soracli.engines.rain import RainEngine
from soracli.engines.snow import SnowEngine
from soracli.engines.thunder import ThunderEngine
from soracli.engines.fog import FogEngine
from soracli.engines.clear import ClearEngine
from soracli.engines import get_engine_for_condition


class TestEngineConfig:
    """Tests for EngineConfig dataclass."""
    
    def test_default_config(self):
        """Test default configuration values."""
        config = EngineConfig()
        assert config.width == 80
        assert config.height == 24
        assert config.intensity == 1.0
        assert config.refresh_rate == 0.05
        assert config.sound_enabled is False
        assert config.is_night is False
    
    def test_custom_config(self):
        """Test custom configuration values."""
        config = EngineConfig(
            width=120,
            height=40,
            intensity=1.5,
            is_night=True
        )
        assert config.width == 120
        assert config.height == 40
        assert config.intensity == 1.5
        assert config.is_night is True


class TestParticle:
    """Tests for Particle dataclass."""
    
    def test_create_particle(self):
        """Test particle creation."""
        particle = Particle(x=10.5, y=20.3, char='|')
        assert particle.x == 10.5
        assert particle.y == 20.3
        assert particle.char == '|'
        assert particle.speed == 1.0
        assert particle.drift == 0.0
    
    def test_particle_with_all_params(self):
        """Test particle with all parameters."""
        particle = Particle(
            x=5.0, y=10.0, char='*',
            speed=0.5, color='cyan', drift=-0.1
        )
        assert particle.speed == 0.5
        assert particle.color == 'cyan'
        assert particle.drift == -0.1


class TestRainEngine:
    """Tests for RainEngine."""
    
    def test_initialization(self):
        """Test rain engine initialization."""
        engine = RainEngine()
        assert engine.config is not None
        assert engine.particles == []
    
    def test_get_particle_chars(self):
        """Test rain particle characters."""
        engine = RainEngine()
        chars = engine.get_particle_chars()
        assert len(chars) > 0
        assert '|' in chars or '│' in chars
    
    def test_initialize_particles(self):
        """Test particle initialization."""
        config = EngineConfig(width=40, height=20, intensity=1.0)
        engine = RainEngine(config)
        engine.initialize_particles()
        assert len(engine.particles) > 0
    
    def test_update_particles(self):
        """Test particle update."""
        config = EngineConfig(width=40, height=20, intensity=1.0)
        engine = RainEngine(config)
        engine.initialize_particles()
        initial_count = len(engine.particles)
        engine.update_particles()
        # Particle count should remain roughly the same
        assert len(engine.particles) > 0
    
    def test_set_wind(self):
        """Test wind direction setting."""
        engine = RainEngine()
        engine.set_wind(0.5)
        assert engine.wind_direction == 0.5
        engine.set_wind(2.0)  # Should be clamped
        assert engine.wind_direction == 1.0


class TestSnowEngine:
    """Tests for SnowEngine."""
    
    def test_initialization(self):
        """Test snow engine initialization."""
        engine = SnowEngine()
        assert engine.config is not None
    
    def test_get_particle_chars(self):
        """Test snow particle characters."""
        engine = SnowEngine()
        chars = engine.get_particle_chars()
        assert len(chars) > 0
    
    def test_initialize_particles(self):
        """Test particle initialization."""
        config = EngineConfig(width=40, height=20, intensity=1.0)
        engine = SnowEngine(config)
        engine.initialize_particles()
        assert len(engine.particles) > 0
        assert len(engine.accumulation) == config.width


class TestThunderEngine:
    """Tests for ThunderEngine."""
    
    def test_initialization(self):
        """Test thunder engine initialization."""
        engine = ThunderEngine()
        assert engine.config is not None
        assert engine.rain_engine is not None
    
    def test_lightning_generation(self):
        """Test lightning bolt generation."""
        config = EngineConfig(width=40, height=20)
        engine = ThunderEngine(config)
        engine.initialize_particles()
        bolt = engine._generate_lightning_bolt()
        assert len(bolt) > 0
    
    def test_force_lightning(self):
        """Test force lightning trigger."""
        config = EngineConfig(width=40, height=20)
        engine = ThunderEngine(config)
        engine.initialize_particles()
        engine.force_lightning()
        assert engine.lightning_active is True


class TestFogEngine:
    """Tests for FogEngine."""
    
    def test_initialization(self):
        """Test fog engine initialization."""
        engine = FogEngine()
        assert engine.config is not None
    
    def test_density_map_generation(self):
        """Test density map generation."""
        config = EngineConfig(width=40, height=20)
        engine = FogEngine(config)
        engine.initialize_particles()
        assert len(engine.density_map) == config.height
        assert len(engine.density_map[0]) == config.width
    
    def test_density_values(self):
        """Test density values are in valid range."""
        config = EngineConfig(width=40, height=20, intensity=1.0)
        engine = FogEngine(config)
        engine.initialize_particles()
        for row in engine.density_map:
            for density in row:
                assert 0.0 <= density <= 1.0


class TestClearEngine:
    """Tests for ClearEngine."""
    
    def test_night_mode_stars(self):
        """Test stars initialization in night mode."""
        config = EngineConfig(width=40, height=20, is_night=True)
        engine = ClearEngine(config)
        engine.initialize_particles()
        assert len(engine.particles) > 0
    
    def test_day_mode_clouds(self):
        """Test cloud initialization in day mode."""
        config = EngineConfig(width=40, height=20, is_night=False)
        engine = ClearEngine(config)
        engine.initialize_particles()
        assert len(engine.clouds) > 0
    
    def test_toggle_day_night(self):
        """Test day/night toggle."""
        config = EngineConfig(is_night=True)
        engine = ClearEngine(config)
        engine.initialize_particles()
        engine.toggle_day_night()
        assert engine.config.is_night is False


class TestEngineMapping:
    """Tests for weather condition to engine mapping."""
    
    def test_rain_conditions(self):
        """Test rain condition mapping."""
        assert get_engine_for_condition('Rain') == RainEngine
        assert get_engine_for_condition('Light Rain') == RainEngine
        assert get_engine_for_condition('Drizzle') == RainEngine
    
    def test_snow_conditions(self):
        """Test snow condition mapping."""
        assert get_engine_for_condition('Snow') == SnowEngine
        assert get_engine_for_condition('Heavy Snow') == SnowEngine
    
    def test_thunder_conditions(self):
        """Test thunderstorm condition mapping."""
        assert get_engine_for_condition('Thunderstorm') == ThunderEngine
    
    def test_fog_conditions(self):
        """Test fog condition mapping."""
        assert get_engine_for_condition('Fog') == FogEngine
        assert get_engine_for_condition('Mist') == FogEngine
        assert get_engine_for_condition('Haze') == FogEngine
    
    def test_clear_conditions(self):
        """Test clear condition mapping."""
        assert get_engine_for_condition('Clear') == ClearEngine
        assert get_engine_for_condition('Clouds') == ClearEngine
    
    def test_unknown_condition(self):
        """Test unknown condition defaults to clear."""
        assert get_engine_for_condition('Unknown') == ClearEngine
