package it.polimi.ingsw.gc14.Model.Cards;

import it.polimi.ingsw.gc14.Model.Cards.Building.EffectType;
import it.polimi.ingsw.gc14.Model.Cards.Building.Effects.Building13;
import it.polimi.ingsw.gc14.Model.Player;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

class BuildingCardTest {
    @Test
    void checkOnParameters() {  // ERA CHECKED IN PlayableCardTest
        assertDoesNotThrow(() -> {
            new BuildingCard(1, 1,1);
        });

        assertDoesNotThrow(() -> {
            new BuildingCard(1, 2,1);
        });
        assertThrows(IllegalArgumentException.class, () -> {
            new BuildingCard(1, 0,1);
        });
        assertThrows(IllegalArgumentException.class, () -> {
            new BuildingCard(1, -1,1);
        });

        assertDoesNotThrow(() -> {
            new BuildingCard(1, 1,2);
        });
        assertDoesNotThrow(() -> {
            new BuildingCard(1, 1,0);
        });
        assertThrows(IllegalArgumentException.class, () -> {
            new BuildingCard(1, 1,-1);
        });
    }

    @Test
    @DisplayName("Testing the first constructor (3 parameters)")
    void testBuildingCard1() {
        // Testing correct initialization
        int era0 = 1;
        int price0 = 5;        // Testing wrong price and prestigeValue
        assertThrows(IllegalArgumentException.class, () ->  {new BuildingCard(1, 0,-1);});
        int prestigeValue0 = 10;
        BuildingCard bc0 = new BuildingCard(era0,price0,prestigeValue0);

        assertEquals(era0, bc0.getEra());
        assertEquals(price0, bc0.getPrice());
        assertEquals(prestigeValue0, bc0.getPrestigeValue());

        // Testing edge case for prestigeValue and price
        assertDoesNotThrow(() -> {new BuildingCard(1, 1,0);});

        // Testing wrong price
        assertThrows(IllegalArgumentException.class, () ->  {new BuildingCard(1, 0,1);});

        // Testing wrong prestigeValue
        assertThrows(IllegalArgumentException.class, () ->  {new BuildingCard(1, 1,-1);});

        // Testing wrong price and prestigeValue
        assertThrows(IllegalArgumentException.class, () ->  {new BuildingCard(1, 0,-1);});

        // The attribute era is tested in PlayableCardTest

    }

    @Test
    @DisplayName("Testing the second constructor (4 parameters)")
    void testBuildingCard2() {}{
        // Testing right parameters
        BuildingCard bc2 = new BuildingCard(2,1,1,1);
        BuildingCard bc3 = new BuildingCard(3,1,1,1);
        BuildingCard bc5 = new BuildingCard(5,1,1,1);
        BuildingCard bc6 = new BuildingCard(6,1,1,1);
        BuildingCard bc7 = new BuildingCard(7,1,1,1);
        BuildingCard bc9 = new BuildingCard(9,1,1,1);
        BuildingCard bc12 = new BuildingCard(12,1,1,1);

        assertEquals(EffectType.ON_EVENT, bc2.getEffectType());
        assertEquals(EffectType.ON_END_TURN, bc3.getEffectType());
        assertEquals(EffectType.ON_EVENT, bc5.getEffectType());
        assertEquals(EffectType.ON_EVENT, bc6.getEffectType());
        assertEquals(EffectType.ON_EVENT, bc7.getEffectType());
        assertEquals(EffectType.ON_EVENT, bc9.getEffectType());
        assertEquals(EffectType.ON_ROUND_END, bc12.getEffectType());

        // Testing wrong parameters
        assertThrows(IllegalArgumentException.class, () -> {new BuildingCard(0,1,1,1);});
        assertThrows(IllegalArgumentException.class, () -> {new BuildingCard(1,1,1,1);});
        assertThrows(IllegalArgumentException.class, () -> {new BuildingCard(4,1,1,1);});
        assertThrows(IllegalArgumentException.class, () -> {new BuildingCard(8,1,1,1);});
        assertThrows(IllegalArgumentException.class, () -> {new BuildingCard(10,1,1,1);});
        assertThrows(IllegalArgumentException.class, () -> {new BuildingCard(11,1,1,1);});
        assertThrows(IllegalArgumentException.class, () -> {new BuildingCard(13,1,1,1);});

    }

    @Test
    @DisplayName("Testing the getters for price, prestigeValue, effectID, effectType")
    void testGetters() {
        int effectID = 2;
        EffectType effectType = EffectType.ON_EVENT;
        int era = 1;
        int price = 1;
        int prestigeValue = 1;

        BuildingCard bc0 = new BuildingCard(effectID,era,price,prestigeValue);

        assertEquals(effectID, bc0.getEffectId());
        assertEquals(effectType, bc0.getEffectType());
        assertEquals(era, bc0.getEra());
        assertEquals(price, bc0.getPrice());
        assertEquals(prestigeValue, bc0.getPrestigeValue());
    }

    @Test
    @DisplayName("Testing the clone method")
    void testClone() {
        int effectID = 2;
        EffectType effectType = EffectType.ON_EVENT;
        int era = 1;
        int price = 1;
        int prestigeValue = 1;

        BuildingCard bc0 = new BuildingCard(effectID, era, price, prestigeValue);
        BuildingCard bc1 = bc0.clone();

        assertEquals(effectID, bc1.getEffectId());
        assertEquals(effectType, bc1.getEffectType());
        assertEquals(era, bc1.getEra());
        assertEquals(price, bc1.getPrice());
        assertEquals(prestigeValue, bc1.getPrestigeValue());
    }

    @Test
    @DisplayName("Testing the buy method")
    void testBuy() {
        Player p1 = new Player("test1");
        Player p2 = new Player("test2");
        p1.addFood(10);
        p2.addFood(10);

        BuildingCard bc0 = new BuildingCard(2, 1,1,1);

        assertTrue(bc0.buy(p1));
        assertFalse(bc0.buy(p1));
        assertFalse(bc0.buy(p2));
    }

    @Test
    @DisplayName("Testing toString method")
    void testToString() {
        Building13 b0 = new Building13(1, 2,3);

        assertEquals("Era:1 Price:2 Prestige:3", b0.toString());
    }

    @Test
    @DisplayName("Apply Effect")
    void applyEffect(){
        String user = "test";
        Player p = new Player(user);
        assertTrue(p.buildingCards.isEmpty());
        assertTrue(p.inventors.isEmpty());
        assertTrue(p.builders.isEmpty());
        assertTrue(p.gatherers.isEmpty());
        assertTrue(p.shamans.isEmpty());
        assertTrue(p.hunters.isEmpty());
        assertTrue(p.artists.isEmpty());
        assertEquals(0, p.getFoodValue());
        assertEquals(0, p.getPrestigeValue());
        assertEquals(user, p.getUserName());

        BuildingCard b = new BuildingCard(1,2,3);
        b.applyEffect(p);

        assertTrue(p.buildingCards.isEmpty());
        assertTrue(p.inventors.isEmpty());
        assertTrue(p.builders.isEmpty());
        assertTrue(p.gatherers.isEmpty());
        assertTrue(p.shamans.isEmpty());
        assertTrue(p.hunters.isEmpty());
        assertTrue(p.artists.isEmpty());
        assertEquals(0, p.getFoodValue());
        assertEquals(0, p.getPrestigeValue());
        assertEquals(user, p.getUserName());
    }
}