<?php

namespace App\Manager;

use App\Entity\Entry;
use App\Entity\Group;
use App\Entity\Headword;
use App\Entity\Label;
use App\Entity\LabelInvisibility;
use App\Entity\Lexicon;
use App\Entity\User;
use App\Languages\LanguagesIso;
use Doctrine\Persistence\ManagerRegistry;
use JsonSchema\Validator;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Serializer\SerializerAwareInterface;
use Symfony\Component\Serializer\SerializerInterface;

class LabelManager
{
    /**
     * @var ManagerRegistry
     */
    protected $doctrine;

    protected $searchString;

    public function __construct(ManagerRegistry $doctrine)
    {
        $this->doctrine = $doctrine;
    }

    public function setSearchString($searchString)
    {
        $this->searchString = $searchString;
    }

    public function mergeLabels(Label $labelDeleted, Label $labelMerged)
    {
        foreach ($labelDeleted->getHeadwords() as $headword) {
            $headword->addLabel($labelMerged);
        }
        // On ne reporte pas les invisibilités du label supprimé dans le label fusionné

//        // pour chaque invisibilité liée à labelDeleted, on regarde si on a une invisibilité pour le même lexique dans labelMerged
//        // Si ce n'est pas le cas, on en ajoute une
//        foreach ($labelDeleted->getLabelInvisibilities() as $labelInvisibilityDeleted) {
//            $labelMergedHasSameLexiconVisibility = false;
//            foreach ($labelMerged->getLabelInvisibilities() as $labelInvisibilityMerged) {
//                if ($labelInvisibilityDeleted->getLexicon() == $labelInvisibilityMerged->getLexicon()) {
//                    $labelMergedHasSameLexiconVisibility = true; break;
//                }
//            }
//            if (false === $labelMergedHasSameLexiconVisibility) {
//                $labelInvisibility = new LabelInvisibility();
//                $labelInvisibility->setLexicon($labelInvisibilityDeleted->getLexicon());
//                $labelInvisibility->setLabel($labelMerged);
//                $labelInvisibility->setUser($labelInvisibilityDeleted->getUser());
//                $this->doctrine->getManager()->persist($labelInvisibility);
//            }
//        }
        $this->doctrine->getManager()->remove($labelDeleted);
    }

    /**
     * @param Label $label
     * @return Label|null
     */
    public function getIdenticalLabel(Label $label)
    {
        $identicalLabels = $this->doctrine->getRepository(Label::class)->filter([
            'user' => $label->getUser(),
            'group' => $label->getGroup(),
            'category' => $label->getCategory(),
            'milestone' => $label->getMilestone(),
            'name' => $label->getName(),
            'graphyList' => $label->getGraphyList(),
        ]);

        $identicalLabel = $identicalLabels ? $identicalLabels[0] : null;

        // On s'assure que le label identique n'est le label passé en paramètre (ça peut être le cas en edit si on a pas encore modifié label)
        return $identicalLabel && $identicalLabel->getId() !== $label->getId() ? $identicalLabel : null;
    }

    // vrai si le label est visible pour user dans un lexique donné
    public function isVisible(Label $label, Lexicon $lexicon, User $user)
    {
        return $this->doctrine->getRepository(LabelInvisibility::class)->count(
                [
                    'label'   => $label,
                    'lexicon' => $lexicon,
                    'user'    => $user,
                ]
            ) == 0;
    }

    // Retourne les 5 derniers labels visibles par un user classés par date de création DESC
    public function getLastLabels(User $user)
    {
        return $this->doctrine->getRepository(Label::class)->getLastVisiblesByUser($user);
    }

    // Retourne les labels visibles dans un lexique pour un user (pour une catégorie si renseignée)
    public function getVisibleLabelsInLexicon(Lexicon $lexicon, User $user, $category = null)
    {
        if ($lexicon->isZero()) {
            return $this->doctrine->getRepository(Label::class)->queryVisiblesByUser($user, $category)->getQuery()->getresult();
        }
        return $this->doctrine->getRepository(Label::class)->getVisiblesByUserInLexicon($user, $lexicon, $category);
    }

    // Retourne les labels de l'entrée visibles pour un user (en fonction de leur visibilité dans le lexique et des permissions si non public) (pour une catégorie si renseignée)
    public function getEntryVisibleLabels(Entry $entry, User $user, $category = null)
    {
        $labelsVisiblesInLexicon = $this->getVisibleLabelsInLexicon($entry->getLexicon(), $user, $category);

        return array_intersect($entry->getHeadword()->getLabelsForCategory($category), $labelsVisiblesInLexicon);
    }

    // Retourne les labels visibles pour un user, sans tenir compte des invisibilités (pour une catégorie si renseignée)
    public function getVisibleLabelsForUser(User $user, $category = null)
    {
        return $this->doctrine->getRepository(Label::class)->queryVisiblesByUser($user, $category)->getQuery()->getresult();
    }

    public function filter($filter)
    {
        if ($this->searchString) {
            $filter['searchString'] = $this->searchString;
        }
        return $this->doctrine->getRepository(Label::class)->filter($filter);
    }

    // Retourne le nb total de mot-vedettes portant le label
    // Si $user est renseigné, Retourne le nb total de mot-vedettes portant le label ayant au moins une entrée dans un lexique de l'utilisateur
    public function getHeadwordsNbWithLabel(Label $label, User $user = null)
    {
        return $this->doctrine->getRepository(Headword::class)->countHavingLabel($label, $user);
    }
}