package fr.titionfire.ffsaf.ws.recv;

import fr.titionfire.ffsaf.ws.PermLevel;
import fr.titionfire.ffsaf.ws.send.SSState;
import io.quarkus.runtime.annotations.RegisterForReflection;
import io.quarkus.websockets.next.UserData;
import io.quarkus.websockets.next.WebSocketConnection;
import io.smallrye.mutiny.Uni;
import jakarta.enterprise.context.ApplicationScoped;
import lombok.Data;

import java.util.HashMap;
import java.util.List;
import java.util.UUID;

@ApplicationScoped
@RegisterForReflection
public class RState {

    private static final HashMap<WebSocketConnection, TableState> tableStates = new HashMap<>();

    @WSReceiver(code = "subscribeToState", permission = PermLevel.VIEW)
    public Uni<List<TableState>> sendCurrentScore(WebSocketConnection connection, Boolean subscribe) {
        connection.userData().put(UserData.TypedKey.forBoolean("needState"), subscribe);

        if (subscribe) {
            String uuid = connection.pathParam("uuid");
            return Uni.createFrom().item(() ->
                    tableStates.values().stream().filter(s -> s.getCompetitionUuid().equals(uuid)).toList()
            );
        }
        return Uni.createFrom().nullItem();
    }

    @WSReceiver(code = "sendState", permission = PermLevel.TABLE)
    public Uni<Void> sendState(WebSocketConnection connection, TableState tableState) {
        tableState.setCompetitionUuid(connection.pathParam("uuid"));

        if (tableStates.containsKey(connection))
            tableState.setId(tableStates.get(connection).getId());
        if (tableState.getChronoState().isRunning() && tableState.getChronoState().state == 0)
            tableState.setState(MatchState.IN_PROGRESS);
        tableStates.put(connection, tableState);
        SSState.sendStateFull(connection, tableState);
        return Uni.createFrom().voidItem();
    }

    @WSReceiver(code = "sendSelectCategory", permission = PermLevel.TABLE)
    public Uni<Void> sendSelectCategory(WebSocketConnection connection, Long catId) {
        TableState tableState = tableStates.get(connection);
        if (tableState != null) {
            tableState.setSelectedCategory(catId);
            tableState.setState(MatchState.NOT_STARTED);
            SSState.sendStateFull(connection, tableState);
        }
        return Uni.createFrom().voidItem();
    }

    @WSReceiver(code = "sendSelectMatch", permission = PermLevel.TABLE)
    public Uni<Void> sendSelectMatch(WebSocketConnection connection, Long matchId) {
        TableState tableState = tableStates.get(connection);
        if (tableState != null) {
            tableState.setSelectedMatch(matchId);
            tableState.setState(MatchState.NOT_STARTED);
            SSState.sendStateFull(connection, tableState);
        }
        return Uni.createFrom().voidItem();
    }

    @WSReceiver(code = "sendCurentChrono", permission = PermLevel.TABLE)
    public Uni<Void> sendCurentChrono(WebSocketConnection connection, ChronoState chronoState) {
        TableState tableState = tableStates.get(connection);
        if (tableState != null) {
            tableState.setChronoState(chronoState);
            if (chronoState.isRunning())
                tableState.setState(MatchState.IN_PROGRESS);
            SSState.sendStateFull(connection, tableState);
        }
        return Uni.createFrom().voidItem();
    }

    @WSReceiver(code = "sendLicenceName", permission = PermLevel.TABLE)
    public Uni<Void> sendCurrentScore(WebSocketConnection connection, String name) {
        TableState tableState = tableStates.get(connection);
        if (tableState != null) {
            tableState.setLiceName(name);
            SSState.sendStateFull(connection, tableState);
        }
        return Uni.createFrom().voidItem();
    }

    @WSReceiver(code = "sendCurrentScore", permission = PermLevel.TABLE)
    public Uni<Void> sendCurrentScore(WebSocketConnection connection, ScoreState scoreState) {
        TableState tableState = tableStates.get(connection);
        if (tableState != null) {
            tableState.setScoreState(scoreState);
            SSState.sendStateFull(connection, tableState);
        }
        return Uni.createFrom().voidItem();
    }

    public void removeConnection(WebSocketConnection connection) {
        if (tableStates.containsKey(connection)) {
            SSState.sendRmStateFull(connection, tableStates.get(connection).getId());
            tableStates.remove(connection);
        }
    }

    public void setMatchEnd(WebSocketConnection connection, RMatch.MatchEnd matchEnd) {
        if (tableStates.containsKey(connection)) {
            TableState tableState = tableStates.get(connection);
            if (matchEnd.end())
                tableState.setState(MatchState.ENDED);
            else
                tableState.setState(MatchState.IN_PROGRESS);
            SSState.sendStateFull(connection, tableState);
        }
    }

    @RegisterForReflection
    public record ChronoState(long time, long startTime, long configTime, long configPause, int state) {
        public boolean isRunning() {
            return startTime != 0 || state != 0;
        }
    }

    @RegisterForReflection
    public record ScoreState(int scoreRouge, int scoreBleu) {
    }

    @Data
    @RegisterForReflection
    public static class TableState {
        UUID id = UUID.randomUUID();
        String competitionUuid;
        Long selectedCategory;
        Long selectedMatch;
        ChronoState chronoState;
        ScoreState scoreState;
        String liceName = "???";
        MatchState state = MatchState.NOT_STARTED;
    }

    public enum MatchState {
        NOT_STARTED,
        IN_PROGRESS,
        ENDED
    }
}
