package eu.jonahbauer.wizard.client.libgdx.actors.game;

import com.badlogic.gdx.scenes.scene2d.*;
import eu.jonahbauer.wizard.client.libgdx.WizardGame;
import eu.jonahbauer.wizard.client.libgdx.screens.GameScreen;
import lombok.Data;

import java.util.*;

import static com.badlogic.gdx.scenes.scene2d.actions.Actions.*;

public class CardStack extends Group {
    private static final float EXPAND_DURATION = 0.25f;
    private static final float EXPANDED_ROTATION_DEVIATION = 10;
    private static final float COLLAPSE_DURATION = 0.25f;
    private static final float COLLAPSED_ROTATION_DEVIATION = 60;
    private static final float COLLAPSED_POSITION_DEVIATION = 15;

    private final Random random = new Random();
    private final List<Entry> cards = new ArrayList<>();

    private final Actor hover = new Actor();
    private boolean expanded;

    public CardStack() {
        this.addActor(hover);
        this.addListener(new InputListener() {

            @Override
            public void exit(InputEvent event, float x, float y, int pointer, Actor toActor) {
                if (pointer == -1 && event.getTarget() == hover && expanded) {
                    expanded = false;
                    cards.forEach(Entry::collapse);
                }
            }

            @Override
            public void enter(InputEvent event, float x, float y, int pointer, Actor fromActor) {
                if (pointer == -1 && event.getTarget() == hover && !expanded) {
                    expanded = true;
                    cards.forEach(Entry::expand);
                }
            }
        });
    }

    public void add(GameScreen.Seat seat, CardActor card) {
        var entry = new Entry(
                card,
                seat,
                (float) random.nextGaussian((WizardGame.WIDTH - card.getWidth()) / 2, COLLAPSED_POSITION_DEVIATION),
                (float) random.nextGaussian((WizardGame.HEIGHT - card.getHeight()) / 2, COLLAPSED_POSITION_DEVIATION),
                (float) random.nextGaussian(0, COLLAPSED_ROTATION_DEVIATION),
                (float) random.nextGaussian(0, EXPANDED_ROTATION_DEVIATION)
        );
        addActor(card);
        if (expanded) entry.expand();
        else entry.collapse();
        cards.add(entry);
    }

    @Override
    protected void childrenChanged() {
        hover.toFront();
    }

    @Override
    public void clearChildren(boolean unfocus) {
        super.clearChildren(unfocus);
        cards.clear();
        addActor(hover);
    }

    public void setHoverBounds(float x, float y, float width, float height) {
        hover.setBounds(x, y, width, height);
    }

    @Data
    private static class Entry {
        private final CardActor actor;
        private final GameScreen.Seat seat;
        private final float x;
        private final float y;
        private final float rotation;
        private final float expandedRotation;
        private Action action;

        public void expand() {
            if (action != null) actor.removeAction(action);

            action = parallel(
                    moveTo(seat.getCardX() - actor.getWidth() / 2, seat.getCardY() - actor.getHeight() / 2, EXPAND_DURATION),
                    rotateTo(expandedRotation, EXPAND_DURATION)
            );

            actor.addAction(action);
        }

        public void collapse() {
            if (action != null) actor.removeAction(action);

            action = parallel(
                    moveTo(x, y, COLLAPSE_DURATION),
                    rotateTo(rotation, COLLAPSE_DURATION)
            );

            actor.addAction(action);
        }
    }
}
