package de.oaa.xxx.games.common.aufgaben;

import de.oaa.xxx.games.common.entity.AufgabeEntity;
import de.oaa.xxx.games.common.entity.AufgabenGruppeEntity;
import de.oaa.xxx.games.common.entity.FinisherEntity;
import de.oaa.xxx.games.common.entity.SperreEntity;
import de.oaa.xxx.games.common.entity.StrafeEntity;
import de.oaa.xxx.games.common.entity.ToyEntity;
import de.oaa.xxx.games.common.repository.AufgabeRepository;
import de.oaa.xxx.games.common.repository.AufgabenGruppeRepository;
import de.oaa.xxx.games.common.repository.FinisherRepository;
import de.oaa.xxx.games.common.repository.SperreRepository;
import de.oaa.xxx.games.common.repository.StrafeRepository;
import de.oaa.xxx.games.common.repository.ToyRepository;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;

/**
 * Service für komplexe AufgabenGruppen-Operationen.
 * Kapselt die Kopier-Logik (Systemgruppe → eigene Gruppe) inkl. Toy-Mapping.
 */
@Service
public class AufgabenGruppeService {

    private static final Logger LOGGER = LoggerFactory.getLogger(AufgabenGruppeService.class);

    private final AufgabenGruppeRepository gruppeRepository;
    private final AufgabeRepository aufgabeRepository;
    private final StrafeRepository strafeRepository;
    private final SperreRepository sperreRepository;
    private final FinisherRepository finisherRepository;
    private final ToyRepository toyRepository;

    public AufgabenGruppeService(AufgabenGruppeRepository gruppeRepository,
                                  AufgabeRepository aufgabeRepository,
                                  StrafeRepository strafeRepository,
                                  SperreRepository sperreRepository,
                                  FinisherRepository finisherRepository,
                                  ToyRepository toyRepository) {
        this.gruppeRepository = gruppeRepository;
        this.aufgabeRepository = aufgabeRepository;
        this.strafeRepository = strafeRepository;
        this.sperreRepository = sperreRepository;
        this.finisherRepository = finisherRepository;
        this.toyRepository = toyRepository;
    }

    /**
     * Kopiert eine öffentliche (System-)Gruppe in die eigene Sammlung des Users.
     *
     * @param sourceId UUID der Quellgruppe
     * @param userId   UUID des Ziel-Users
     * @return UUID der neu erstellten Gruppe
     * @throws IllegalStateException    wenn das Gruppen-Limit (10) erreicht ist
     * @throws IllegalArgumentException wenn die Quellgruppe nicht gefunden oder nicht kopierbar ist
     */
    @Transactional
    public UUID copyGruppe(UUID sourceId, UUID userId) {
        if (gruppeRepository.countByUserId(userId) >= 10) {
            throw new IllegalStateException("Gruppen-Limit erreicht");
        }

        AufgabenGruppeEntity source = gruppeRepository.findById(sourceId)
                .orElseThrow(() -> new IllegalArgumentException("Gruppe nicht gefunden: " + sourceId));
        if (source.isPrivateGruppe()) {
            throw new IllegalArgumentException("Privat-Gruppen können nicht kopiert werden");
        }
        if (userId.equals(source.getUserId())) {
            throw new IllegalArgumentException("Eigene Gruppen können nicht kopiert werden");
        }

        // Toy-Mapping aufbauen: Source-ToyId → Ziel-ToyEntity
        Set<ToyEntity> allSourceToys = new HashSet<>();
        source.getAufgaben().forEach(a -> { if (a.getBenoetigteToys() != null) allSourceToys.addAll(a.getBenoetigteToys()); });
        source.getStrafen().forEach(s -> { if (s.getBenoetigteToys() != null) allSourceToys.addAll(s.getBenoetigteToys()); });
        source.getSperren().forEach(sp -> { if (sp.getBenoetigteToys() != null) allSourceToys.addAll(sp.getBenoetigteToys()); });
        source.getFinisher().forEach(f -> { if (f.getBenoetigteToys() != null) allSourceToys.addAll(f.getBenoetigteToys()); });

        Map<UUID, ToyEntity> toyMapping = new HashMap<>();
        for (ToyEntity sourceToy : allSourceToys) {
            if (sourceToy.getUserId() == null) {
                // System-Toy: direkt referenzieren
                toyMapping.put(sourceToy.getToyId(), sourceToy);
            } else {
                // User-Toy: gleichnamiges Toy suchen oder kopieren
                ToyEntity mapped = toyRepository.findByNameIgnoreCaseAndUserId(sourceToy.getName(), userId)
                        .orElseGet(() -> {
                            ToyEntity tc = new ToyEntity();
                            tc.setToyId(UUID.randomUUID());
                            tc.setName(sourceToy.getName());
                            tc.setBeschreibung(sourceToy.getBeschreibung());
                            tc.setBild(sourceToy.getBild());
                            tc.setUserId(userId);
                            return toyRepository.save(tc);
                        });
                toyMapping.put(sourceToy.getToyId(), mapped);
            }
        }

        // Neue Gruppe anlegen
        AufgabenGruppeEntity copy = new AufgabenGruppeEntity();
        copy.setGruppenId(UUID.randomUUID());
        copy.setName(source.getName());
        copy.setBeschreibung(source.getBeschreibung());
        copy.setVon(source.getVon());
        copy.setBild(source.getBild());
        copy.setUserId(userId);
        copy.setPrivateGruppe(true);
        gruppeRepository.save(copy);

        // Aufgaben kopieren
        for (AufgabeEntity a : source.getAufgaben()) {
            AufgabeEntity ac = new AufgabeEntity();
            ac.setAufgabeId(UUID.randomUUID());
            ac.setAufgabenGruppe(copy);
            ac.setKurzText(a.getKurzText());
            ac.setText(a.getText());
            ac.setLevel(a.getLevel());
            ac.setSekundenVon(a.getSekundenVon());
            ac.setSekundenBis(a.getSekundenBis());
            ac.setBenoetigtAktiv(a.getBenoetigtAktiv() != null ? new ArrayList<>(a.getBenoetigtAktiv()) : null);
            ac.setBenoetigtPassiv(a.getBenoetigtPassiv() != null ? new ArrayList<>(a.getBenoetigtPassiv()) : null);
            ac.setBenoetigteToys(mapToys(a.getBenoetigteToys(), toyMapping));
            aufgabeRepository.save(ac);
        }

        // Strafen kopieren
        for (StrafeEntity s : source.getStrafen()) {
            StrafeEntity sc = new StrafeEntity();
            sc.setStrafeId(UUID.randomUUID());
            sc.setAufgabenGruppe(copy);
            sc.setKurzText(s.getKurzText());
            sc.setText(s.getText());
            sc.setLevel(s.getLevel());
            sc.setSekundenVon(s.getSekundenVon());
            sc.setSekundenBis(s.getSekundenBis());
            sc.setBenoetigtAktiv(s.getBenoetigtAktiv() != null ? new ArrayList<>(s.getBenoetigtAktiv()) : null);
            sc.setBenoetigtPassiv(s.getBenoetigtPassiv() != null ? new ArrayList<>(s.getBenoetigtPassiv()) : null);
            sc.setBenoetigteToys(mapToys(s.getBenoetigteToys(), toyMapping));
            strafeRepository.save(sc);
        }

        // Sperren kopieren
        for (SperreEntity sp : source.getSperren()) {
            SperreEntity spc = new SperreEntity();
            spc.setSperreId(UUID.randomUUID());
            spc.setAufgabenGruppe(copy);
            spc.setKurzText(sp.getKurzText());
            spc.setText(sp.getText());
            spc.setReleaseText(sp.getReleaseText());
            spc.setMinutenVon(sp.getMinutenVon());
            spc.setMinutenBis(sp.getMinutenBis());
            spc.setSperreFuer(sp.getSperreFuer() != null ? new ArrayList<>(sp.getSperreFuer()) : null);
            spc.setBenoetigteToys(mapToys(sp.getBenoetigteToys(), toyMapping));
            sperreRepository.save(spc);
        }

        // Finisher kopieren
        for (FinisherEntity f : source.getFinisher()) {
            FinisherEntity fc = new FinisherEntity();
            fc.setFinisherId(UUID.randomUUID());
            fc.setAufgabenGruppe(copy);
            fc.setKurzText(f.getKurzText());
            fc.setText(f.getText());
            fc.setGeschlecht(f.getGeschlecht());
            fc.setBenoetigtAktiv(f.getBenoetigtAktiv() != null ? new ArrayList<>(f.getBenoetigtAktiv()) : null);
            fc.setBenoetigtPassiv(f.getBenoetigtPassiv() != null ? new ArrayList<>(f.getBenoetigtPassiv()) : null);
            fc.setBenoetigteToys(mapToys(f.getBenoetigteToys(), toyMapping));
            finisherRepository.save(fc);
        }

        LOGGER.info("User {} hat AufgabenGruppe {} kopiert (Quelle: {})", userId, copy.getGruppenId(), sourceId);
        return copy.getGruppenId();
    }

    private List<ToyEntity> mapToys(List<ToyEntity> source, Map<UUID, ToyEntity> mapping) {
        if (source == null || source.isEmpty()) return new ArrayList<>();
        return source.stream().map(t -> mapping.getOrDefault(t.getToyId(), t)).toList();
    }
}
