
import pytest
from pypokemon.pypokemon import luckypokemon
from pypokemon.pypokemon import calculate_damage
from pypokemon.pypokemon import battle
from pypokemon.pypokemon import show_pokemon, pokemon_ascii

def test_show_pokemon_ascii(capsys):
    """Ensure ASCII art for each Pokémon appears in output."""
    show_pokemon()
    captured = capsys.readouterr()
    
    for name, art in pokemon_ascii.items():
        assert art.strip() in captured.out

def test_show_pokemon_display(capsys):
    """Check if all Pokémon names appear in output."""
    show_pokemon()
    captured = capsys.readouterr()
    
    assert "Venusaur appears!" in captured.out
    assert "Charizard appears!" in captured.out
    assert "Blastoise appears!" in captured.out

def test_show_pokemon_stats(capsys):
    """Verify if HP, Attack, Defense, and Type are printed correctly."""
    show_pokemon()
    captured = capsys.readouterr()
    
    for name, stats in pokemon_data.items():
        assert f"HP: {stats['HP']}" in captured.out
        assert f"Attack Range: {stats['Attack']}" in captured.out
        assert f"Defense Range: {stats['Defense']}" in captured.out
        assert f"Type: {stats['Type']}" in captured.out

def test_battle_prints_output(capfd):
    """Test if battle() produces printed output."""
    battle("Charizard", "Blastoise")
    captured = capfd.readouterr()
    assert "Battle Start!" in captured.out
    assert "attacks" in captured.out
    assert "wins!" in captured.out or "fainted!" in captured.out

def test_battle_declares_winner(capfd):
    """Test if battle() always declares a winner."""
    battle("Venusaur", "Charizard")
    captured = capfd.readouterr()
    assert "wins!" in captured.out, "Battle result should declare a winner."

def test_battle_varied_results(capfd):
    """Test if battle() can have different winners over multiple simulations."""
    results = set()

    for _ in range(20):  # Run more battles to increase randomness
        battle("Charizard", "Blastoise")

    captured = capfd.readouterr()  # Capture the output after all battles

    if "Charizard wins!" in captured.out:
        results.add("Charizard")
    if "Blastoise wins!" in captured.out:
        results.add("Blastoise")


def test_calculate_damage_returns_integer():
    """Test if calculate_damage() returns an integer."""
    damage = calculate_damage("Charizard", "Blastoise")
    assert isinstance(damage, int), "Damage should be an integer."

def test_calculate_damage_positive_value():
    """Test if calculate_damage() always returns a positive value (at least 1)."""
    damage = calculate_damage("Venusaur", "Charizard")
    assert damage >= 1, "Damage should be at least 1."

def test_calculate_damage_effectiveness():
    """Test if type effectiveness affects damage output."""
    damage_fire_vs_grass = calculate_damage("Charizard", "Venusaur")  # Fire vs Grass (should be strong)
    damage_fire_vs_water = calculate_damage("Charizard", "Blastoise")  # Fire vs Water (should be weak)
    
    assert damage_fire_vs_grass > damage_fire_vs_water, "Fire vs Grass should deal more damage than Fire vs Water."


def test_luckypokemon_returns_string():
    """Test if luckypokemon() returns a string."""
    result = luckypokemon()
    assert isinstance(result, str), "The function should return a string."

def test_luckypokemon_contains_pokemon_name():
    """Test if the returned string contains a valid Pokémon name from the list."""
    pokemon_list = [
        "Pikachu", "Charmander", "Bulbasaur", "Squirtle", "Jigglypuff", 
        "Meowth", "Psyduck", "Snorlax", "Eevee", "Gyarados", 
        "Lapras", "Ditto", "Vaporeon", "Jolteon", "Flareon",
        "Machamp", "Gengar", "Dragonite", "Mewtwo", "Mew",
        "Togepi", "Espeon", "Umbreon", "Scizor", "Heracross",
        "Blaziken", "Swampert", "Sceptile", "Gardevoir", "Salamence",
        "Metagross", "Lucario", "Garchomp", "Infernape", "Torterra",
        "Empoleon", "Roserade", "Glaceon", "Leafeon", "Togekiss",
        "Zoroark", "Hydreigon", "Greninja", "Aegislash", "Talonflame",
        "Sylveon", "Decidueye", "Incineroar", "Primarina", "Zacian"
    ]
    result = luckypokemon()
    # Extract Pokémon name from the returned string
    extracted_pokemon = result.split("... ")[-1].split("!")[0]
    assert extracted_pokemon in pokemon_list, f"{extracted_pokemon} is not a valid Pokémon!"

def test_luckypokemon_randomness():
    """Test if luckypokemon() produces different results over multiple calls."""
    results = {luckypokemon() for _ in range(10)}
    assert len(results) > 1, "The function should return different Pokémon names over multiple calls."
