package de.oaa.xxx.games.vanilla;

import com.fasterxml.jackson.databind.ObjectMapper;
import de.oaa.xxx.games.common.aufgaben.Aufgabe;
import de.oaa.xxx.games.common.aufgaben.AufgabenList;
import de.oaa.xxx.games.bdsm.GeschlechtEnum;
import de.oaa.xxx.games.bdsm.RolleEnum;
import de.oaa.xxx.games.vanilla.entity.VanillaGameEntity;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class VanillaGameDurchfuehren {

    private final AufgabenList aufgabenList;
    private final List<VanillaMitspieler> mitspieler = new ArrayList<>();
    private int aufgabenProLevel;
    private int level;
    private int aufgabenAufAktuellemLevel;

    public VanillaGameDurchfuehren(VanillaGameEntity entity) throws Exception {
        ObjectMapper objectMapper = new ObjectMapper();
        aufgabenList = objectMapper.readValue(entity.getAufgaben(), AufgabenList.class);
        entity.getMitspieler().forEach(m -> mitspieler.add(m.toMitspieler()));
        this.aufgabenProLevel = entity.getAufgabenProLevel() != null ? entity.getAufgabenProLevel() : 5;
        this.level = entity.getLevel() != null ? entity.getLevel() : 1;
        this.aufgabenAufAktuellemLevel = entity.getAufgabenAufAktuellemLevel() != null ? entity.getAufgabenAufAktuellemLevel() : 0;
    }

    public int getLevel() { return level; }
    public int getAufgabenAufAktuellemLevel() { return aufgabenAufAktuellemLevel; }

    public VanillaAufgabeAnzeige getNext() {
        checkLevel();
        if (level == 6) return null;

        VanillaAufgabeAnzeige anzeige = findeAufgabe();
        if (anzeige != null) return anzeige;

        // Fallback
        VanillaMitspieler aktiv = findeMitspielerMitRolle(RolleEnum.AUFGABE_AKTIV);
        VanillaMitspieler passiv = findeMitspielerMitRolle(RolleEnum.AUFGABE_PASSIV, aktiv);
        VanillaAufgabeAnzeige fallback = new VanillaAufgabeAnzeige();
        fallback.setNameAktiverMitspieler(aktiv != null ? aktiv.getName() : "");
        if (aktiv != null) { fallback.setMitspielerId(aktiv.getId()); fallback.setEigenesGeraet(aktiv.isEigenesGeraet()); }
        fallback.setAufgabeText("Keine passende Aufgabe gefunden. Überbrückt die Zeit mit Kuscheln.");
        fallback.setTimer(120);
        return fallback;
    }

    public void backToLvl5() { this.level = 5; this.aufgabenAufAktuellemLevel = 0; }

    public List<VanillaAufgabeAnzeige> getFinisher() {
        var list = new ArrayList<VanillaAufgabeAnzeige>();
        List.of(GeschlechtEnum.WEIBLICH, GeschlechtEnum.DIVERS, GeschlechtEnum.MAENNLICH).forEach(geschlecht -> {
            mitspieler.stream().filter(m -> geschlecht == m.getGeschlecht()).toList().forEach(cumming -> {
                var partner = findeMitspielerMitRolle(RolleEnum.AUFGABE_PASSIV, cumming);
                var finishers = aufgabenList.getFinisher().stream()
                        .filter(f -> geschlecht == f.getGeschlecht() && f.isAufgabePassend(partner != null ? toMitspielerBdsm(partner) : null, toMitspielerBdsm(cumming)))
                        .toList();
                VanillaAufgabeAnzeige anzeige = new VanillaAufgabeAnzeige();
                anzeige.setNameAktiverMitspieler(cumming.getName());
                anzeige.setMitspielerId(cumming.getId());
                anzeige.setEigenesGeraet(cumming.isEigenesGeraet());
                if (!finishers.isEmpty()) {
                    var f = finishers.get(new Random().nextInt(finishers.size()));
                    anzeige.setAufgabeText(getAnzeigeText(f.getText(), cumming.getName(), partner != null ? partner.getName() : ""));
                } else {
                    anzeige.setAufgabeText(cumming.getName() + " geht heute leider leer aus...");
                }
                list.add(anzeige);
            });
        });
        return list;
    }

    private void checkLevel() {
        if (++aufgabenAufAktuellemLevel >= 1 + aufgabenProLevel) {
            aufgabenAufAktuellemLevel = 0;
            level++;
        }
    }

    private VanillaAufgabeAnzeige findeAufgabe() {
        VanillaMitspieler aktiv = findeMitspielerMitRolle(RolleEnum.AUFGABE_AKTIV);
        if (aktiv == null) return null;
        VanillaMitspieler passiv = findeMitspielerMitRolle(RolleEnum.AUFGABE_PASSIV, aktiv);
        de.oaa.xxx.games.bdsm.Mitspieler aktivBdsm = toMitspielerBdsm(aktiv);
        de.oaa.xxx.games.bdsm.Mitspieler passivBdsm = passiv != null ? toMitspielerBdsm(passiv) : null;
        List<Aufgabe> passende = aufgabenList.getAufgaben().stream()
                .filter(a -> a.isAufgabePassend(level, aktivBdsm, passivBdsm != null ? passivBdsm : aktivBdsm))
                .toList();
        if (passende.isEmpty()) return null;
        Aufgabe aufgabe = passende.get(new Random().nextInt(passende.size()));
        VanillaAufgabeAnzeige anzeige = new VanillaAufgabeAnzeige();
        anzeige.setNameAktiverMitspieler(aktiv.getName());
        anzeige.setMitspielerId(aktiv.getId());
        anzeige.setEigenesGeraet(aktiv.isEigenesGeraet());
        anzeige.setAufgabeText(getAnzeigeText(aufgabe.getText(), aktiv.getName(), passiv != null ? passiv.getName() : ""));
        if (aufgabe.getSekundenVon() != null && aufgabe.getSekundenBis() != null && aufgabe.getSekundenBis() > 0) {
            anzeige.setTimer(new Random().nextInt(aufgabe.getSekundenVon(), aufgabe.getSekundenBis() + 1));
        }
        return anzeige;
    }

    private VanillaMitspieler findeMitspielerMitRolle(RolleEnum rolle) { return findeMitspielerMitRolle(rolle, null); }
    private VanillaMitspieler findeMitspielerMitRolle(RolleEnum rolle, VanillaMitspieler ausschliessen) {
        List<VanillaMitspieler> kandidaten = mitspieler.stream()
                .filter(m -> m.getRollen().contains(rolle) && !m.equals(ausschliessen))
                .toList();
        if (kandidaten.isEmpty()) return null;
        return kandidaten.get(new Random().nextInt(kandidaten.size()));
    }

    private de.oaa.xxx.games.bdsm.Mitspieler toMitspielerBdsm(VanillaMitspieler vm) {
        de.oaa.xxx.games.bdsm.Mitspieler m = new de.oaa.xxx.games.bdsm.Mitspieler();
        m.setId(vm.getId()); m.setName(vm.getName()); m.setGeschlecht(vm.getGeschlecht());
        m.setRollen(vm.getRollen()); m.setSpieltMit(vm.getSpieltMit());
        m.setVerfuegbareWerkzeuge(vm.getVerfuegbareWerkzeuge()); m.setEigenesGeraet(vm.isEigenesGeraet());
        return m;
    }

    private String getAnzeigeText(String text, String aktiv, String passiv) {
        if (text == null) return "";
        return text.replace("{AKTIV}", aktiv != null ? aktiv : "").replace("{PASSIV}", passiv != null ? passiv : "");
    }
}
