package fr.titionfire.ffsaf.domain.entity;

import fr.titionfire.ffsaf.data.model.*;
import fr.titionfire.ffsaf.utils.ResultPrivacy;
import fr.titionfire.ffsaf.utils.ScoreEmbeddable;
import io.quarkus.runtime.annotations.RegisterForReflection;
import lombok.Getter;

import java.util.*;

@RegisterForReflection
public class MatchModelExtend {
    final MatchModel match;

    @Getter
    boolean isEnd = false;
    @Getter
    List<ScoreEmbeddable> scoresToPrint = new ArrayList<>();
    @Getter
    List<ScoreEmbeddable> scoresToCompute = new ArrayList<>();
    @Getter
    int win = 0;


    public MatchModelExtend(MatchModel match, List<CardModel> cards) {
        this.match = match;

        List<Long> combIds = extractCombIds(match);
        List<CardModel> cards2 = cards.stream().filter(c -> combIds.contains(c.getComb()) && c.hasEffect(match))
                .sorted(Comparator.comparing(CardModel::getType).reversed()).toList();


        for (ScoreEmbeddable score : match.getScores()) {
            if (score.getS1() == -1000 || score.getS2() == -1000)
                continue;
            this.scoresToCompute.add(virtualScore(score, cards2, false));
        }

        calc_win_end(cards2);

        for (ScoreEmbeddable score : match.getScores()) {
            if (score.getS1() == -1000 || score.getS2() == -1000)
                continue;
            this.scoresToPrint.add(virtualScore(score, cards2, true));
        }
        if (this.isEnd && this.scoresToPrint.isEmpty()) {
            this.scoresToPrint.add(virtualScore(new ScoreEmbeddable(0, 0, 0), cards2, true));
        }
    }

    private ScoreEmbeddable virtualScore(ScoreEmbeddable score, List<CardModel> cards2, boolean toPrint) {
        if (cards2.size() > 1) {
            if (!Objects.equals(cards2.get(0).getComb(), cards2.get(1).getComb()))
                return new ScoreEmbeddable(score.getN_round(), toPrint ? -997 : 0, toPrint ? -997 : 0);
        }
        if (!cards2.isEmpty()) {
            if (isC1(cards2.get(0).getComb()))
                return new ScoreEmbeddable(score.getN_round(), toPrint ? -997 : 0, 10);
            else
                return new ScoreEmbeddable(score.getN_round(), 10, toPrint ? -997 : 0);
        }

        if (score.getS1() < -900 && score.getS2() < -900)
            return new ScoreEmbeddable(score.getN_round(), toPrint ? score.getS1() : 0, toPrint ? score.getS2() : 0);
        else if (score.getS1() < -900)
            return new ScoreEmbeddable(score.getN_round(), toPrint ? score.getS1() : 0, 10);
        else if (score.getS2() < -900)
            return new ScoreEmbeddable(score.getN_round(), 10, toPrint ? score.getS2() : 0);

        return new ScoreEmbeddable(score.getN_round(), score.getS1(), score.getS2());
    }

    private void calc_win_end(List<CardModel> cards2) {
        if (cards2.size() > 1) {
            if (!Objects.equals(cards2.get(0).getComb(), cards2.get(1).getComb())) {
                this.win = 0;
                this.isEnd = true;
                return;
            }
        }

        if (!cards2.isEmpty()) {
            if (match.isC1(cards2.get(0).getComb())) {
                this.win = -1;
            } else if (match.isC2(cards2.get(0).getComb())) {
                this.win = 1;
            }
            this.isEnd = true;
            return;
        }

        for (ScoreEmbeddable score : this.scoresToCompute) {
            if (score.getS1() > score.getS2())
                win++;
            else if (score.getS1() < score.getS2())
                win--;
        }
        this.isEnd = match.isEnd();
    }


    private List<Long> extractCombIds(MatchModel match) {
        List<Long> ids = new ArrayList<>();
        if (match.getC1_id() != null)
            ids.add(match.getC1_id().getId());
        if (match.getC2_id() != null)
            ids.add(match.getC2_id().getId());
        if (match.getC1_guest() != null)
            ids.add(match.getC1_guest().getId() * -1);
        if (match.getC2_guest() != null)
            ids.add(match.getC2_guest().getId() * -1);
        return ids;
    }

    //--------------- Delegation methods to MatchModel ---------------

    public Long getId() {
        return match.getId();
    }

    public MembreModel getC1_id() {
        return match.getC1_id();
    }

    public CompetitionGuestModel getC1_guest() {
        return match.getC1_guest();
    }

    public MembreModel getC2_id() {
        return match.getC2_id();
    }

    public CompetitionGuestModel getC2_guest() {
        return match.getC2_guest();
    }

    public CategoryModel getCategory() {
        return match.getCategory();
    }

    public long getCategory_ord() {
        return match.getCategory_ord();
    }

    public Date getDate() {
        return match.getDate();
    }

    public char getPoule() {
        return match.getPoule();
    }

    public String getC1Name(MembreModel model, ResultPrivacy privacy) {
        return match.getC1Name(model, privacy);
    }

    public String getC2Name(MembreModel model, ResultPrivacy privacy) {
        return match.getC2Name(model, privacy);
    }

    public String getC2Name() {
        return match.getC2Name();
    }

    public String getC1Name() {
        return match.getC1Name();
    }

    public boolean isC1(Object comb) {
        return match.isC1(comb);
    }

    public boolean isC2(Object comb) {
        return match.isC2(comb);
    }

    public CombModel getC1() {
        return match.getC1();
    }

    public CombModel getC2() {
        return match.getC2();
    }
}
