package fr.titionfire.ffsaf.ws.recv;

import fr.titionfire.ffsaf.data.model.CardboardModel;
import fr.titionfire.ffsaf.data.model.MatchModel;
import fr.titionfire.ffsaf.data.repository.CardboardRepository;
import fr.titionfire.ffsaf.data.repository.MatchRepository;
import fr.titionfire.ffsaf.domain.entity.CardboardEntity;
import fr.titionfire.ffsaf.rest.exception.DForbiddenException;
import fr.titionfire.ffsaf.rest.exception.DNotFoundException;
import fr.titionfire.ffsaf.ws.PermLevel;
import fr.titionfire.ffsaf.ws.send.SSCardboard;
import io.quarkus.hibernate.reactive.panache.Panache;
import io.quarkus.hibernate.reactive.panache.common.WithSession;
import io.quarkus.runtime.annotations.RegisterForReflection;
import io.quarkus.websockets.next.WebSocketConnection;
import io.smallrye.mutiny.Uni;
import io.smallrye.mutiny.unchecked.Unchecked;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import lombok.Data;

import java.util.Objects;

@WithSession
@ApplicationScoped
@RegisterForReflection
public class RCardboard {

    @Inject
    MatchRepository matchRepository;

    @Inject
    CardboardRepository cardboardRepository;

    private Uni<MatchModel> getById(long id, WebSocketConnection connection) {
        return matchRepository.findById(id)
                .invoke(Unchecked.consumer(o -> {
                    if (o == null)
                        throw new DNotFoundException("Matche non trouver");
                    if (!o.getCategory().getCompet().getUuid().equals(connection.pathParam("uuid")))
                        throw new DForbiddenException("Permission denied");
                }));
    }

    @WSReceiver(code = "sendCardboardChange", permission = PermLevel.TABLE)
    public Uni<Void> sendCardboardChange(WebSocketConnection connection, SendCardboard card) {
        return getById(card.matchId, connection)
                .chain(matchModel -> cardboardRepository.find("(comb.id = ?1 OR guestComb.id = ?2) AND match.id = ?3",
                                card.combId, card.combId * -1, card.matchId).firstResult()
                        .chain(model -> {
                            if (model != null) {
                                model.setRed(model.getRed() + card.red);
                                model.setYellow(model.getYellow() + card.yellow);
                                return Panache.withTransaction(() -> cardboardRepository.persist(model));
                            }
                            CardboardModel cardboardModel = new CardboardModel();

                            cardboardModel.setCompet(matchModel.getCategory().getCompet());
                            cardboardModel.setMatch(matchModel);
                            cardboardModel.setRed(card.red);
                            cardboardModel.setYellow(card.yellow);
                            cardboardModel.setComb(null);
                            cardboardModel.setGuestComb(null);

                            if (card.combId >= 0) {
                                if (matchModel.getC1_id() != null && matchModel.getC1_id().getId() == card.combId)
                                    cardboardModel.setComb(matchModel.getC1_id());
                                if (matchModel.getC2_id() != null && matchModel.getC2_id().getId() == card.combId)
                                    cardboardModel.setComb(matchModel.getC2_id());
                            } else {
                                if (matchModel.getC1_guest() != null && matchModel.getC1_guest()
                                        .getId() == card.combId * -1)
                                    cardboardModel.setGuestComb(matchModel.getC1_guest());
                                if (matchModel.getC2_guest() != null && matchModel.getC2_guest()
                                        .getId() == card.combId * -1)
                                    cardboardModel.setGuestComb(matchModel.getC2_guest());
                            }

                            if (cardboardModel.getComb() == null && cardboardModel.getGuestComb() == null)
                                return Uni.createFrom().nullItem();
                            return Panache.withTransaction(() -> cardboardRepository.persist(cardboardModel));
                        }))
                .call(model -> SSCardboard.sendCardboard(connection, CardboardEntity.fromModel(model)))
                .replaceWithVoid();
    }

    @WSReceiver(code = "getCardboardWithoutThis", permission = PermLevel.VIEW)
    public Uni<CardboardAllMatch> getCardboardWithoutThis(WebSocketConnection connection, Long matchId) {
        return getById(matchId, connection)
                .chain(matchModel -> cardboardRepository.list("compet = ?1 AND match != ?2", matchModel.getCategory().getCompet(), matchModel)
                        .map(models -> {
                            CardboardAllMatch out = new CardboardAllMatch();

                            models.stream().filter(c -> (matchModel.getC1_id() != null
                                            && Objects.equals(c.getComb(), matchModel.getC1_id()))
                                            || (matchModel.getC1_guest() != null
                                            && Objects.equals(c.getGuestComb(), matchModel.getC1_guest())))
                                    .forEach(c -> {
                                        out.c1_yellow += c.getYellow();
                                        out.c1_red += c.getRed();
                                    });

                            models.stream().filter(c -> (matchModel.getC2_id() != null
                                            && Objects.equals(c.getComb(), matchModel.getC2_id()))
                                            || (matchModel.getC2_guest() != null
                                            && Objects.equals(c.getGuestComb(), matchModel.getC2_guest())))
                                    .forEach(c -> {
                                        out.c2_yellow += c.getYellow();
                                        out.c2_red += c.getRed();
                                    });

                            return out;
                        }));
    }

    @RegisterForReflection
    public record SendCardboard(long matchId, long combId, int yellow, int red) {
    }

    @Data
    @RegisterForReflection
    public static class CardboardAllMatch {
        int c1_yellow = 0;
        int c1_red = 0;
        int c2_yellow = 0;
        int c2_red = 0;
    }
}
