package fr.titionfire.ffsaf.ws.recv;

import fr.titionfire.ffsaf.data.model.CompetitionGuestModel;
import fr.titionfire.ffsaf.data.model.RegisterModel;
import fr.titionfire.ffsaf.data.repository.CompetitionGuestRepository;
import fr.titionfire.ffsaf.data.repository.CompetitionRepository;
import fr.titionfire.ffsaf.data.repository.RegisterRepository;
import fr.titionfire.ffsaf.domain.entity.CombEntity;
import fr.titionfire.ffsaf.domain.service.TradService;
import fr.titionfire.ffsaf.utils.Categorie;
import fr.titionfire.ffsaf.utils.Genre;
import fr.titionfire.ffsaf.utils.Pair;
import fr.titionfire.ffsaf.ws.PermLevel;
import fr.titionfire.ffsaf.ws.send.SSRegister;
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 jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@WithSession
@ApplicationScoped
@RegisterForReflection
public class RTeam {

    @Inject
    TradService trad;

    @Inject
    CompetitionRepository competitionRepository;

    @Inject
    RegisterRepository registerRepository;

    @Inject
    CompetitionGuestRepository competitionGuestRepository;

    @WSReceiver(code = "setTeam", permission = PermLevel.ADMIN)
    public Uni<CombEntity> setTeam(WebSocketConnection connection, TeamData data) {
        return competitionRepository.find("uuid", connection.pathParam("uuid")).firstResult()
                .chain(cm -> registerRepository.list("membre.id IN ?1 AND competition = ?2",
                                data.members.stream().filter(id -> id >= 0).toList(), cm)
                        .chain(l -> competitionGuestRepository.list("id IN ?1",
                                        data.members.stream().filter(id -> id < 0).map(i -> i * -1).toList())
                                .map(l2 -> new Pair<>(l, l2)))
                        .chain(pair ->
                                competitionGuestRepository.find("fname = ?1 AND lname = ?2 AND competition = ?3",
                                                data.name, "__team", cm).firstResult()
                                        .chain(team -> {
                                            if (pair.getKey().isEmpty() && pair.getValue().isEmpty()) {
                                                if (team != null) {
                                                    CompetitionGuestModel finalTeam1 = team;
                                                    SSRegister.sendRegisterRemove(connection, finalTeam1.getId() * -1);
                                                    return Panache.withTransaction(
                                                                    () -> competitionGuestRepository.delete(finalTeam1))
                                                            .replaceWith((CombEntity) null);
                                                } else
                                                    return Uni.createFrom().item((CombEntity) null);
                                            }

                                            if (team == null) {
                                                // Create new team
                                                team = new CompetitionGuestModel();
                                                team.setFname(data.name);
                                                team.setLname("__team");
                                                team.setCompetition(cm);
                                                team.setClub("Team");
                                                team.setGenre(Genre.NA);
                                            } else {
                                                team.getComb().clear();
                                                team.getGuest().clear();
                                            }

                                            team.setCategorie(Stream.concat(
                                                            pair.getKey().stream().map(RegisterModel::getCategorie2),
                                                            pair.getValue().stream().map(CompetitionGuestModel::getCategorie))
                                                    .map(Enum::ordinal)
                                                    .max(Integer::compareTo)
                                                    .map(i -> Categorie.values()[i]).orElse(Categorie.SENIOR1));

                                            List<Float> s = Stream.concat(
                                                            pair.getKey().stream().map(RegisterModel::getWeight),
                                                            pair.getValue().stream().map(CompetitionGuestModel::getWeight))
                                                    .filter(Objects::nonNull).toList();
                                            if (s.isEmpty()) {
                                                team.setWeight(null);
                                            } else if (s.size() == 1) {
                                                team.setWeight(s.get(0));
                                            } else {
                                                team.setWeight((float) s.stream().mapToDouble(Float::doubleValue)
                                                        .average()
                                                        .orElse(0));
                                            }

                                            team.setCountry(Stream.concat(
                                                            pair.getKey().stream().map(m -> m.getMembre().getCountry()),
                                                            pair.getValue().stream().map(CompetitionGuestModel::getCountry))
                                                    .filter(Objects::nonNull)
                                                    .map(String::toUpperCase)
                                                    .collect(Collectors.groupingBy(
                                                            e -> e, // Classer par élément
                                                            Collectors.counting() // Compter les occurrences
                                                    ))
                                                    .entrySet()
                                                    .stream()
                                                    .max(Map.Entry.comparingByValue())
                                                    .map(Map.Entry::getKey)
                                                    .orElse("FR"));

                                            team.getComb().addAll(
                                                    pair.getKey().stream().map(RegisterModel::getMembre).toList());
                                            team.getGuest().addAll(pair.getValue());

                                            CompetitionGuestModel finalTeam = team;
                                            return Panache.withTransaction(
                                                            () -> competitionGuestRepository.persistAndFlush(finalTeam))
                                                    .map(CombEntity::fromModel);
                                        }))
                )
                .invoke(combEntity -> {
                    if (combEntity != null)
                        SSRegister.sendRegister(connection, combEntity);
                });
    }

    @RegisterForReflection
    public record TeamData(List<Long> members, String name) {
    }
}
