package com.ghost.technic.server.game;

import com.ghost.technic.server.Player;
import com.ghost.technic.server.board.Flank;
import com.ghost.technic.server.card.playable.PlayableCard;
import com.ghost.technic.server.game.event.UsageType;
import com.ghost.technic.server.game.event.UsedEventData;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import com.ghost.technic.server.card.misc.House;
import com.ghost.technic.server.card.playable.usable.impl.CreatureCard;
import com.ghost.technic.server.game.GameActionService;
import com.ghost.technic.server.game.GameState;
import com.ghost.technic.server.game.event.EventBus;
import com.ghost.technic.server.game.event.EventType;

import java.util.concurrent.atomic.AtomicBoolean;

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

@Slf4j
class ReapTest {

    private GameActionService gameActionService;
    private Player player;
    private CreatureCard creature;

    @BeforeEach
    void setUp() {
        gameActionService = new GameActionService(new GameState(new EventBus()));
        gameActionService.getGameState().trackRuleOfSix(); // make sure listener is registered

        player = Player.builder().name("Test Player").build();
        creature = CreatureCard.builder().name("Test Creature").house(House.LOGOS).build();
        creature.setReady(true); // simulate creature is ready
    }

    @Test
    void testReapGainsAmberAndExhaustsCreature() {
        gameActionService.reap(creature, player);

        assertEquals(1, player.getAmber(), "Player should gain 1 amber after reaping");
        assertFalse(creature.isReady(), "Creature should be exhausted (not ready) after reaping");
    }

    @Test
    void testReapPublishesReapedEvent() {
        AtomicBoolean reapEventTriggered = new AtomicBoolean(false);

        gameActionService.getEventBus().subscribe(EventType.USED, event -> {
            UsedEventData usedData = event.get("usedEventData");
            PlayableCard card = usedData.getCard();
            UsageType usage = usedData.getUsageType();

            if (usage.equals(UsageType.REAP)) {
                reapEventTriggered.set(true);
            }
            log.info("Card used: {}, Usage type: {}", card.getName(), usage);
        });

        gameActionService.reap(creature, player);

        assertTrue(reapEventTriggered.get(), "REAPED event should have been published");
    }

    @Test
    void testCannotReapIfExhausted() {
        creature.setReady(false); // simulate exhausted

        gameActionService.reap(creature, player);

        assertEquals(0, player.getAmber(), "No amber should be gained if creature is exhausted");
        assertFalse(creature.isReady(), "Creature should remain exhausted");
    }

    @Test
    void testReapLimitedByRuleOfSix() {
        gameActionService.playCreature(player, creature, Flank.RIGHT);

        // Attempt to reap 6 times, forcefully readying the creature each time, only 5 successful reap should fire
        for (int i = 0; i < 6; i++) {
            creature.setReady(true);
            gameActionService.reap(creature, player);
        }

        assertTrue(creature.isReady(), "Creature should not exhaust since it was played once and reaped 5 times from rule of six");
        assertEquals(5, player.getAmber(), "Player should gain 5 amber after 5 legal reaps");
    }
}
