<?php

namespace App\Service;


use App\Entity\GradingGroup;
use App\Entity\Player;
use App\Entity\Score;
use App\Entity\User;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\EntityManagerInterface;

class EvaluationService
{
    private $em;
    private $tiebreakerService;
    
    public function __construct(EntityManagerInterface $em, TiebreakerService $tiebreakerService)
    {
        $this->em = $em;
        $this->tiebreakerService = $tiebreakerService;
    }

    public function createScoresFromParamsAndJudge($params,User $judge): int {

        $player = $this->em->getRepository(Player::class)->find($params['id']);
        $playersScoresOfJudge = $this->em->getRepository(Score::class)->findBy(['player' => $player, 'judge' => $judge]);
        if (count($playersScoresOfJudge) >=1 ) {
            return 0;
        }
        
        $score = new Score();
        $score->setScore($params['tech']);
        $score->setScoreType(Score::TECHNICAL);
        $score->setPlayer($player);
        $score->setJudge($judge);
        $this->em->persist($score);

        $scores = new ArrayCollection([$score]);
        /** @var Player $player */
        $player->setScores($scores);

        $this->em->persist($player);

        $this->em->flush();

//        echo $score->getId().'-Score-'.$params['tech'];exit;

        return $this->checkAndUpdtePlayerStatus($player);
    }

    public function checkAndUpdtePlayerStatus(Player $player): int
    {
        $this->em->refresh($player);
        if($this->isPlayerEvaluationCompleted($player)) {

            $this->updateScoreStatus($player);

            $scoreTech = $scoreAtl = 0.0;
            array_map(function ($score) use (&$scoreTech, &$scoreAtl){
                if(!$score->getIsRemoved() && $score->getScoreType() === Score::TECHNICAL) {
                    $scoreTech += $score->getScore();
                } else if(!$score->getIsRemoved() && $score->getScoreType() === Score::ATLETIC){
                    $scoreAtl += floatval($score->getScore());
                }
            }, $player->getScores()->toArray());

            if($player->getStatus() === Player::STATUS_PLAYING) {
                $player->setStatus(Player::STATUS_FINISHED);
            }
            $player->setTotalAtl($scoreAtl);
            $player->setTotalTech($scoreTech);

            $player->setTotal($scoreAtl);

            $this->em->persist($player);
            $this->em->flush();

            return 1;
        }

        return 0;
    }

    private function isPlayerEvaluationCompleted(Player $player)
    {
        $this->em->refresh($player);
        $judges = $player->getGgroup()->getJudges();
        $scores = $player->getScores();
        $pendingJudges = array_filter($judges,function($judge) use ($scores){
            $matchedScore = array_filter($scores->toArray(), function($score) use ($judge){
                return $judge === $score->getJudge();
            });
            return count($matchedScore) < 1;
        });
        return count($pendingJudges) == 0 ;
    }

    public function updateScoreStatus($player)
    {
        $judges = $player->getGgroup()->getJudges();
        if(count($judges) == 5 ) {
            $this->scoreRemoval5($player);
        }

        if(count($judges) == 7 ) {
            $this->scoreRemoval7($player);
        }

    }

    public function scoreRemoval5($player)
    {
        $scores = $player->getScores()->toArray();

        $techScores = array_filter($scores, function ($s) {
            return $s->getScoreType() === Score::TECHNICAL;
        });

        usort($techScores, function ($a, $b) { return ($a->getScore() - $b->getScore()) >=0 ? 1 : -1;});

        $techScores[0]->setIsRemoved(true);
        $techScores[count($techScores)-1]->setIsRemoved(true);

        $em = $this->em;
        $em->persist($techScores[0]);
        $em->persist($techScores[count($techScores)-1]);
        $em->flush();
        return;
    }


    public function scoreRemoval7($player)
    {
        $scores = $player->getScores()->toArray();

        $techScores = array_filter($scores, function ($s) {
            return $s->getScoreType() === Score::TECHNICAL;
        });

        usort($techScores, function ($a, $b) { return ($a->getScore() - $b->getScore()) >=0 ? 1 : -1;});

        $techScores[0]->setIsRemoved(true);
        $techScores[1]->setIsRemoved(true);
        $techScores[count($techScores)-1]->setIsRemoved(true);
        $techScores[count($techScores)-2]->setIsRemoved(true);

        $em = $this->em;
        $em->persist($techScores[0]);
        $em->persist($techScores[1]);
        $em->persist($techScores[count($techScores)-1]);
        $em->persist($techScores[count($techScores)-2]);
        $em->flush();
        return;
    }

}
