package fr.titionfire.ffsaf.ws.recv;

import fr.titionfire.ffsaf.data.model.CardModel;
import fr.titionfire.ffsaf.data.model.CategoryModel;
import fr.titionfire.ffsaf.data.model.MatchModel;
import fr.titionfire.ffsaf.data.repository.CardRepository;
import fr.titionfire.ffsaf.data.repository.CategoryRepository;
import fr.titionfire.ffsaf.data.repository.CompetitionRepository;
import fr.titionfire.ffsaf.data.repository.MatchRepository;
import fr.titionfire.ffsaf.domain.entity.MatchModelExtend;
import fr.titionfire.ffsaf.domain.service.ResultService;
import fr.titionfire.ffsaf.domain.service.TradService;
import fr.titionfire.ffsaf.rest.data.ResultCategoryData;
import fr.titionfire.ffsaf.utils.Categorie;
import fr.titionfire.ffsaf.ws.PermLevel;
import io.quarkus.hibernate.reactive.panache.common.WithSession;
import io.quarkus.runtime.annotations.RegisterForReflection;
import io.quarkus.websockets.next.WebSocketConnection;
import io.smallrye.mutiny.Multi;
import io.smallrye.mutiny.Uni;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.transaction.Transactional;
import org.hibernate.reactive.mutiny.Mutiny;

import java.util.HashMap;
import java.util.List;
import java.util.stream.Stream;

@WithSession
@ApplicationScoped
@RegisterForReflection
public class RPDF {

    @Inject
    CompetitionRepository competitionRepository;

    @Inject
    MatchRepository matchRepository;

    @Inject
    CardRepository cardRepository;

    @Inject
    CategoryRepository categoryRepository;

    @Inject
    ResultService resultService;

    @Inject
    TradService trad;

    @Transactional
    @WSReceiver(code = "getPodium", permission = PermLevel.VIEW)
    public Uni<List<PodiumEntity>> getPodium(WebSocketConnection connection, Object o) {
        List<CardModel> cards = new java.util.ArrayList<>();

        return cardRepository.list("competition.uuid = ?1", connection.pathParam("uuid"))
                .invoke(cards::addAll)
                .chain(__ -> matchRepository.list("category.compet.uuid = ?1", connection.pathParam("uuid")))
                .chain(matchs -> {
                    HashMap<CategoryModel, List<MatchModel>> map = new HashMap<>();
                    for (MatchModel match : matchs) {
                        if (!map.containsKey(match.getCategory()))
                            map.put(match.getCategory(), new java.util.ArrayList<>());
                        map.get(match.getCategory()).add(match);
                    }

                    return Multi.createFrom().iterable(map.entrySet())
                            .onItem().call(entry -> Mutiny.fetch(entry.getKey().getTree()))
                            .map(entry -> {
                                ResultCategoryData tmp = new ResultCategoryData();

                                double cmoy = entry.getValue().stream().flatMap(m -> Stream.of(m.getC1(), m.getC2()))
                                        .filter(c -> c != null && c.getCategorie() != null)
                                        .mapToInt(c -> c.getCategorie().ordinal())
                                        .average().orElse(0);
                                Categorie categorie_moy = Categorie.values()[(int) Math.ceil(cmoy)];

                                resultService.getArray2(
                                        entry.getValue().stream().map(m -> new MatchModelExtend(m, cards)).toList(),
                                        null, tmp);
                                resultService.getClassementArray(entry.getKey(), null, cards, tmp);

                                String source = "";
                                if ((entry.getKey().getType() & 2) != 0) {
                                    if (entry.getKey().isTreeAreClassement())
                                        source = trad.t("podium.source.classement", connection);
                                    else
                                        source = trad.t("podium.source.tree", connection);
                                } else if ((entry.getKey().getType() & 1) != 0)
                                    source = trad.t("podium.source.poule", connection);


                                return new PodiumEntity(entry.getKey().getName(), source, categorie_moy,
                                        tmp.getClassement());
                            })
                            .collect().asList();
                });
    }

    @WSReceiver(code = "getPodiumClub", permission = PermLevel.VIEW)
    public Uni<List<ResultService.ClubClassement>> getPodiumClub(WebSocketConnection connection, Object o) {
        return resultService.getAllClubArray(connection.pathParam("uuid"), false);
    }

    @RegisterForReflection
    public static record PodiumEntity(String poule_name, String source, Categorie categorie,
                                      List<ResultCategoryData.ClassementData> podium) {

    }
}
