package de.oaa.xxx.games.vanilla;

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

import com.fasterxml.jackson.databind.ObjectMapper;

import de.oaa.xxx.games.bdsm.GeschlechtEnum;
import de.oaa.xxx.games.common.aufgaben.Aufgabe;
import de.oaa.xxx.games.common.aufgaben.AufgabenList;
import de.oaa.xxx.games.vanilla.entity.VanillaGameEntity;

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;
        // Fallback
        VanillaMitspieler aktiv = findeMitspielerMitRolle();
        VanillaMitspieler passiv = findeMitspielerMitRolle(aktiv);

        VanillaAufgabeAnzeige anzeige = findeAufgabe(aktiv, passiv);
        if (anzeige != null) return anzeige;

        
        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().forEach(cumming -> {
                var partner = findeMitspielerMitRolle(cumming);
                var finishers = aufgabenList.getFinisher().stream()
                        .filter(f -> geschlecht == f.getGeschlecht() && f.isAufgabePassend(cumming, partner))
                        .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, VanillaMitspieler passiv) {
        List<Aufgabe> passende = aufgabenList.getAufgaben().stream()
                .filter(a -> a.isAufgabePassend(level, aktiv, passiv))
                .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() { 
    	return findeMitspielerMitRolle(null); 
    }
    
    private VanillaMitspieler findeMitspielerMitRolle(VanillaMitspieler ausschliessen) {
        List<VanillaMitspieler> kandidaten = mitspieler.stream()
                .filter(m -> !m.equals(ausschliessen))
                .toList();
        if (kandidaten.isEmpty()) return null;
        return kandidaten.get(new Random().nextInt(kandidaten.size()));
    }

    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 : "");
    }
}
