package com.example.boidelov3.games.boideloclassic.manager;

import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;

import java.util.ArrayList;

/**
 * Tests unitaires pour la classe BoideloPlayerManager.
 * Couvre la gestion des joueurs (ajout, suppression, liste).
 */
public class BoideloPlayerManagerTest {

    private BoideloPlayerManager playerManager;

    @Before
    public void setUp() {
        playerManager = new BoideloPlayerManager();
    }

    @Test
    public void testConstructor_initializesWithEmptyList() {
        assertEquals("Initial player count should be 0", 0, playerManager.getPlayerCount());
        assertTrue("Initial players list should be empty", playerManager.getPlayers().isEmpty());
    }

    @Test
    public void testAddPlayer_withValidName() {
        playerManager.addPlayer("Alice");

        assertEquals("Player count should be 1", 1, playerManager.getPlayerCount());
        assertEquals("Player name should be Alice", "Alice", playerManager.getPlayers().get(0));
    }

    @Test
    public void testAddPlayer_multiplePlayers() {
        playerManager.addPlayer("Alice");
        playerManager.addPlayer("Bob");
        playerManager.addPlayer("Charlie");

        assertEquals("Player count should be 3", 3, playerManager.getPlayerCount());
        assertEquals("First player should be Alice", "Alice", playerManager.getPlayers().get(0));
        assertEquals("Second player should be Bob", "Bob", playerManager.getPlayers().get(1));
        assertEquals("Third player should be Charlie", "Charlie", playerManager.getPlayers().get(2));
    }

    @Test
    public void testAddPlayer_withNullName() {
        playerManager.addPlayer(null);

        assertEquals("Should not add null name", 0, playerManager.getPlayerCount());
    }

    @Test
    public void testAddPlayer_withEmptyString() {
        playerManager.addPlayer("");

        assertEquals("Should not add empty string", 0, playerManager.getPlayerCount());
    }

    @Test
    public void testAddPlayer_withWhitespaceOnly() {
        playerManager.addPlayer("   ");

        assertEquals("Should not add whitespace-only name", 0, playerManager.getPlayerCount());
    }

    @Test
    public void testAddPlayer_trimsWhitespace() {
        playerManager.addPlayer("  Alice  ");

        assertEquals("Player name should be trimmed", "Alice", playerManager.getPlayers().get(0));
    }

    @Test
    public void testAddPlayer_withLeadingTrailingSpaces() {
        playerManager.addPlayer("  Bob  ");
        playerManager.addPlayer(" Charlie ");

        assertEquals("Both names should be trimmed", "Bob", playerManager.getPlayers().get(0));
        assertEquals("Second name should be trimmed", "Charlie", playerManager.getPlayers().get(1));
    }

    @Test
    public void testAddPlayer_duplicateNames() {
        playerManager.addPlayer("Alice");
        playerManager.addPlayer("Alice");

        assertEquals("Should allow duplicate names", 2, playerManager.getPlayerCount());
    }

    @Test
    public void testAddPlayer_caseSensitiveNames() {
        playerManager.addPlayer("alice");
        playerManager.addPlayer("Alice");
        playerManager.addPlayer("ALICE");

        assertEquals("Should treat different cases as different names", 3, playerManager.getPlayerCount());
    }

    @Test
    public void testAddPlayer_withSpecialCharacters() {
        playerManager.addPlayer("José éàï");
        playerManager.addPlayer("张三");
        playerManager.addPlayer("Владимир");

        assertEquals("Should handle special characters", 3, playerManager.getPlayerCount());
        assertEquals("First special character name should be preserved", "José éàï", playerManager.getPlayers().get(0));
    }

    @Test
    public void testAddPlayer_withNumbers() {
        playerManager.addPlayer("Player123");
        playerManager.addPlayer("007");

        assertEquals("Should handle numbers in names", 2, playerManager.getPlayerCount());
    }

    @Test
    public void testRemovePlayer_validIndex() {
        playerManager.addPlayer("Alice");
        playerManager.addPlayer("Bob");
        playerManager.addPlayer("Charlie");

        playerManager.removePlayer(1);

        assertEquals("Player count should be 2", 2, playerManager.getPlayerCount());
        assertEquals("First player should still be Alice", "Alice", playerManager.getPlayers().get(0));
        assertEquals("Second player should now be Charlie", "Charlie", playerManager.getPlayers().get(1));
    }

    @Test
    public void testRemovePlayer_firstIndex() {
        playerManager.addPlayer("Alice");
        playerManager.addPlayer("Bob");
        playerManager.addPlayer("Charlie");

        playerManager.removePlayer(0);

        assertEquals("Player count should be 2", 2, playerManager.getPlayerCount());
        assertEquals("First player should now be Bob", "Bob", playerManager.getPlayers().get(0));
    }

    @Test
    public void testRemovePlayer_lastIndex() {
        playerManager.addPlayer("Alice");
        playerManager.addPlayer("Bob");
        playerManager.addPlayer("Charlie");

        playerManager.removePlayer(2);

        assertEquals("Player count should be 2", 2, playerManager.getPlayerCount());
        assertEquals("Last player should be Bob", "Bob", playerManager.getPlayers().get(1));
    }

    @Test
    public void testRemovePlayer_invalidNegativeIndex() {
        playerManager.addPlayer("Alice");
        playerManager.addPlayer("Bob");

        playerManager.removePlayer(-1);

        assertEquals("Should not remove with negative index", 2, playerManager.getPlayerCount());
    }

    @Test
    public void testRemovePlayer_invalidTooLargeIndex() {
        playerManager.addPlayer("Alice");
        playerManager.addPlayer("Bob");

        playerManager.removePlayer(10);

        assertEquals("Should not remove with too large index", 2, playerManager.getPlayerCount());
    }

    @Test
    public void testRemovePlayer_fromEmptyList() {
        playerManager.removePlayer(0);

        assertEquals("Should handle removal from empty list", 0, playerManager.getPlayerCount());
    }

    @Test
    public void testRemovePlayer_allPlayers() {
        playerManager.addPlayer("Alice");
        playerManager.addPlayer("Bob");
        playerManager.addPlayer("Charlie");

        playerManager.removePlayer(0);
        playerManager.removePlayer(0);
        playerManager.removePlayer(0);

        assertEquals("All players should be removed", 0, playerManager.getPlayerCount());
    }

    @Test
    public void testGetPlayers_returnsNewList() {
        playerManager.addPlayer("Alice");
        playerManager.addPlayer("Bob");

        ArrayList<String> list1 = playerManager.getPlayers();
        ArrayList<String> list2 = playerManager.getPlayers();

        assertNotSame("Should return new list each time", list1, list2);
        assertEquals("Lists should have same content", list1, list2);
    }

    @Test
    public void testGetPlayers_returnsCopy_modificationDoesNotAffectOriginal() {
        playerManager.addPlayer("Alice");
        playerManager.addPlayer("Bob");

        ArrayList<String> players = playerManager.getPlayers();
        players.add("Charlie"); // Modify returned list
        players.clear(); // Clear returned list

        assertEquals("Modifying returned list should not affect manager", 2, playerManager.getPlayerCount());
        assertEquals("Manager should still have original players", "Alice", playerManager.getPlayers().get(0));
    }

    @Test
    public void testGetPlayerCount_incrementsWithAdds() {
        assertEquals("Initial count should be 0", 0, playerManager.getPlayerCount());

        playerManager.addPlayer("A");
        assertEquals("Count should be 1", 1, playerManager.getPlayerCount());

        playerManager.addPlayer("B");
        playerManager.addPlayer("C");
        assertEquals("Count should be 3", 3, playerManager.getPlayerCount());
    }

    @Test
    public void testGetPlayerCount_decrementsWithRemoves() {
        playerManager.addPlayer("A");
        playerManager.addPlayer("B");
        playerManager.addPlayer("C");

        playerManager.removePlayer(1);
        assertEquals("Count should be 2", 2, playerManager.getPlayerCount());

        playerManager.removePlayer(0);
        assertEquals("Count should be 1", 1, playerManager.getPlayerCount());
    }

    @Test
    public void testClearPlayers_removesAllPlayers() {
        playerManager.addPlayer("Alice");
        playerManager.addPlayer("Bob");
        playerManager.addPlayer("Charlie");

        playerManager.clearPlayers();

        assertEquals("Player count should be 0", 0, playerManager.getPlayerCount());
        assertTrue("Players list should be empty", playerManager.getPlayers().isEmpty());
    }

    @Test
    public void testClearPlayers_whenAlreadyEmpty() {
        playerManager.clearPlayers();

        assertEquals("Clearing empty list should be fine", 0, playerManager.getPlayerCount());
    }

    @Test
    public void testClearPlayers_thenAddNewPlayers() {
        playerManager.addPlayer("Alice");
        playerManager.addPlayer("Bob");

        playerManager.clearPlayers();

        playerManager.addPlayer("Charlie");
        playerManager.addPlayer("David");

        assertEquals("Should be able to add after clear", 2, playerManager.getPlayerCount());
        assertEquals("New player should be Charlie", "Charlie", playerManager.getPlayers().get(0));
    }

    @Test
    public void testMultipleManagers_areIndependent() {
        BoideloPlayerManager manager1 = new BoideloPlayerManager();
        BoideloPlayerManager manager2 = new BoideloPlayerManager();

        manager1.addPlayer("Alice");
        manager2.addPlayer("Bob");

        assertEquals("Manager1 should have 1 player", 1, manager1.getPlayerCount());
        assertEquals("Manager2 should have 1 player", 1, manager2.getPlayerCount());
        assertEquals("Manager1 player should be Alice", "Alice", manager1.getPlayers().get(0));
        assertEquals("Manager2 player should be Bob", "Bob", manager2.getPlayers().get(0));
    }

    @Test
    public void testAddPlayer_singleCharacterName() {
        playerManager.addPlayer("A");

        assertEquals("Should accept single character", 1, playerManager.getPlayerCount());
        assertEquals("Single character should be preserved", "A", playerManager.getPlayers().get(0));
    }

    @Test
    public void testAddPlayer_veryLongName() {
        String longName = "ThisIsAVeryLongPlayerNameThatMightBeUsedInAGameWithFriends";
        playerManager.addPlayer(longName);

        assertEquals("Should accept long names", 1, playerManager.getPlayerCount());
        assertEquals("Long name should be preserved", longName, playerManager.getPlayers().get(0));
    }

    @Test
    public void testAddRemoveAdd_sequence() {
        playerManager.addPlayer("A");
        playerManager.addPlayer("B");
        playerManager.addPlayer("C");

        playerManager.removePlayer(1); // Remove B

        playerManager.addPlayer("D");

        assertEquals("After remove and add", 3, playerManager.getPlayerCount());
        assertEquals("A should still be first", "A", playerManager.getPlayers().get(0));
        assertEquals("C should be second", "C", playerManager.getPlayers().get(1));
        assertEquals("D should be third", "D", playerManager.getPlayers().get(2));
    }

    @Test
    public void testGetPlayers_orderIsPreserved() {
        playerManager.addPlayer("First");
        playerManager.addPlayer("Second");
        playerManager.addPlayer("Third");
        playerManager.addPlayer("Fourth");

        ArrayList<String> players = playerManager.getPlayers();

        assertEquals("Order should be preserved", "First", players.get(0));
        assertEquals("Order should be preserved", "Second", players.get(1));
        assertEquals("Order should be preserved", "Third", players.get(2));
        assertEquals("Order should be preserved", "Fourth", players.get(3));
    }

    @Test
    public void testRemovePlayer_boundaryIndexZero() {
        playerManager.addPlayer("Only");

        playerManager.removePlayer(0);

        assertEquals("Removing only player should work", 0, playerManager.getPlayerCount());
    }

    @Test
    public void testAddPlayer_withInternalSpaces() {
        playerManager.addPlayer("Anna Marie");

        assertEquals("Should preserve internal spaces", "Anna Marie", playerManager.getPlayers().get(0));
    }

    @Test
    public void testGetPlayers_consistencyAcrossMultipleCalls() {
        playerManager.addPlayer("Alice");
        playerManager.addPlayer("Bob");

        ArrayList<String> list1 = playerManager.getPlayers();
        ArrayList<String> list2 = playerManager.getPlayers();
        ArrayList<String> list3 = playerManager.getPlayers();

        assertEquals("All calls should return same content", list1, list2);
        assertEquals("All calls should return same content", list2, list3);
    }
}
