<?php

namespace App\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Event\LifecycleEventArgs;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
use Sonata\UserBundle\Entity\BaseUser as BaseUser;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * @ORM\Entity()
 * @ORM\Table(name="user")
 * @UniqueEntity(
 *     fields={"firstname", "lastname", "email"},
 *     errorPath="email",
 *     message="Ce nom avec cet email est déjà utilisé !"
 * )
 */
class User extends BaseUser
{
    /**
     * @ORM\Id
     * @ORM\Column(name="id", type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @var null|string
     *
     * @ORM\Column(name="etat", type="string", length=10, nullable=true)
     */
    protected $etat;

    /**
     * @ORM\Column(type="string", length=15, nullable=true)
     */
    protected $mobile;

    /**
     * @ORM\OneToOne(targetEntity="Adherent", inversedBy="user", cascade={"all"})
     * @ORM\JoinColumn(name="adherent_id", referencedColumnName="id", nullable=true)
     */
    protected $adherent;

    /**
     * @ORM\OneToOne(targetEntity="Prestataire", inversedBy="user", cascade={"all"})
     * @ORM\JoinColumn(name="prestataire_id", referencedColumnName="id", nullable=true)
     */
    protected $prestataire;

    /**
     * @var ArrayCollection|Document[]
     *
     * @ORM\OneToMany(targetEntity="Document", mappedBy="user", cascade={"persist"})
     */
    private $documents;

    /**
     * @var ArrayCollection|Faq[]
     *
     * @ORM\OneToMany(targetEntity="Faq", mappedBy="user", cascade={"persist"})
     */
    private $faqs;

    /**
     * @var ArrayCollection|Import[]
     *
     * @ORM\OneToMany(targetEntity="Import", mappedBy="user", cascade={"persist"})
     */
    private $imports;

    /**
     * @ORM\OneToMany(targetEntity="Flux", mappedBy="operateur", cascade={"persist"})
     * @ORM\OrderBy({"createdAt" = "DESC"})
     */
    protected $flux;

    /**
     * @ORM\OneToMany(targetEntity="EmailToken", mappedBy="user", cascade={"persist", "remove"})
     * @ORM\OrderBy({"expiredAt" = "DESC"})
     */
    private $emailTokens;

    /**
     * @TODO : changer en manytomany pour qu'un user puisse géré plusieurs groupes ?
     * @ORM\ManyToOne(targetEntity="Groupe", inversedBy="gestionnaires", cascade={"all"})
     */
    private $groupesgere;

    /**
     * @TODO : changer en manytomany pour qu'un user puisse géré plusieurs comptoirs ?
     * @ORM\ManyToOne(targetEntity="Comptoir", inversedBy="gestionnaires", cascade={"all"})
     */
    private $comptoirsgere;

    /**
     * @ORM\Column(name="apiKey", type="string", length=255, nullable=true)
     */
    private $apiKey;

    /**
     * @var ArrayCollection|News[]
     * @ORM\OneToMany(targetEntity="App\Entity\News", mappedBy="user", cascade={"persist"})
     */
    private $news;

    /**
     * @var ArrayCollection|Page[]
     * @ORM\OneToMany(targetEntity="App\Entity\Page", mappedBy="user", cascade={"persist"})
     */
    private $pages;

    /**
     * @ORM\ManyToMany(targetEntity="App\Entity\Usergroup")
     * @ORM\JoinTable(name="user_usergroup",
     *      joinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id")},
     *      inverseJoinColumns={@ORM\JoinColumn(name="group_id", referencedColumnName="id")}
     * )
     */
    protected $groups;

    public function __construct()
    {
        parent::__construct();
        $this->cotisations = new ArrayCollection();
        $this->flux = new ArrayCollection();
        $this->emailTokens = new ArrayCollection();
        $this->faqs = new ArrayCollection();
        $this->news = new ArrayCollection();
        $this->createApiKey();
    }

    /**
    * Get apiKey
    * @return string
    */
    public function getApiKey()
    {
        return $this->apiKey;
    }

    public function createApiKey()
    {
        $bytes = random_bytes(64);
        $this->apiKey = rtrim(strtr(base64_encode($bytes), '+/', '-_'), '=');
    }


    public function getCommonName(): ?string
    {
        return $this->getFirstname()." ".$this->getLastname();
    }

    /**
     * @return null|string
     */
    public function getEtat(): ?string
    {
        return $this->etat;
    }

    /**
     * @param null|string $etat
     * @return Prestataire
     */
    public function setEtat(?string $etat)
    {
        $this->etat = $etat;
        return $this;
    }

    /**
     * Get mobile number
     * @return [type] [description]
     */
    public function getMobile(): ?string
    {
        return $this->mobile;
    }

    /**
     * Set mobile number
     * @param string $mobile [description]
     */
    public function setMobile(?string $mobile): self
    {
        $this->mobile = $mobile;

        return $this;
    }


    public function isGranted($role)
    {
        return in_array($role, $this->getRoles());
    }

    public function isAdmin()
    {
        if ($this->isSuperAdmin()) {
            return true;
        }
        $isAdmin = false;
        foreach ($this->getRoles() as $role) {
            if ((is_object($role) && $role->getRole() == 'ROLE_ADMIN') || $role == 'ROLE_ADMIN') {
                $isAdmin = true;
                break;
            }
        }
        return $isAdmin;
    }

    public function isSuperAdmin()
    {
        return $this->getSuperAdmin();
    }

    public function getSuperAdmin()
    {
        $isSuperAdmin = false;
        foreach ($this->getRoles() as $role) {
            if ((is_object($role) && $role->getRole() == 'ROLE_SUPER_ADMIN') || $role == 'ROLE_SUPER_ADMIN') {
                $isSuperAdmin = true;
                break;
            }
        }
        return $isSuperAdmin;
    }

    /**
    * Get adherent
    * @return
    */
    public function getAdherent()
    {
        return $this->adherent;
    }

    /**
    * Set adherent
    * @return $this
    */
    public function setAdherent($adherent): self
    {
        $this->adherent = $adherent;
        return $this;
    }

    /**
    * Get prestataire
    * @return
    */
    public function getPrestataire()
    {
        return $this->prestataire;
    }

    /**
    * Set prestataire
    * @return $this
    */
    public function setPrestataire($prestataire): self
    {
        $this->prestataire = $prestataire;
        return $this;
    }

    /**
     * @return Cotisation[]|ArrayCollection
     */
    public function getCotisations()
    {
        if (count($this->flux) > 0) {
            $return = new ArrayCollection();
            foreach ($this->flux as $flux) {
                if ($flux->getParenttype() == 'cotisation') {
                    $return->add($flux);
                }
            }
            return $return;
        }
        return new ArrayCollection();
    }

    /**
     * @param $cotisation
     * @return $this
     */
    public function addCotisation($cotisation)
    {
        if (!$this->flux->contains($cotisation)) {
            $cotisation->setOperateur($this);
            $this->flux->add($cotisation);
        }
        return $this;
    }

    /**
     * @param Cotisation $cotisation
     * @return $this
     */
    public function removeCotisation(Cotisation $cotisation)
    {
        throw new \LogicException('User::removeCotisation : This code should not be reached!');
        // if ($this->cotisations->contains($cotisation)) {
        //     $this->cotisations->removeElement($cotisation);
        // }
        return $this;
    }

    /**
     * @return Flux[]|ArrayCollection
     */
    public function getFlux()
    {
        return $this->flux;
    }

    /**
     * @param Flux $flux
     * @return $this
     */
    public function addFlux(Flux $flux)
    {
        if (!$this->flux->contains($flux)) {
            $this->flux[] = $flux;
            $flux->setUser($this);
        }
        return $this;
    }

    /**
     * @param Flux $flux
     * @return $this
     */
    public function removeFlux(Flux $flux)
    {
        throw new \LogicException('User::removeFlux : Ce code ne devrait jamais être atteint !');
        // if ($this->flux->contains($flux)) {
        //     $this->flux->removeElement($flux);
        // }
        return $this;
    }

    /**
     * @param null|Groupe $groupesgere
     * @return $this
     */
    public function setGroupesgere(?Groupe $groupesgere)
    {
        $this->groupesgere = $groupesgere;
        return $this;
    }

    /**
     * @return null|Groupe
     */
    public function getGroupesgere(): ?Groupe
    {
        return $this->groupesgere;
    }

    /**
     * @param null|Comptoir $comptoirsgere
     * @return $this
     */
    public function setComptoirsgere(?Comptoir $comptoirsgere)
    {
        $this->comptoirsgere = $comptoirsgere;
        return $this;
    }

    /**
     * @return null|Comptoir
     */
    public function getComptoirsgere(): ?Comptoir
    {
        return $this->comptoirsgere;
    }

    public function createEmailToken()
    {
        $token = new EmailToken();
        $token->setUser($this);
        $this->emailTokens->add($token);

        return $token;
    }

    public function getFirstValidEmailToken()
    {
        foreach ($this->getEmailTokens() as $emailToken) {
            if ($emailToken->isValid()) {
                return $emailToken;
            }
        }

        return null;
    }

    public function getEmailTokens()
    {
        return $this->emailTokens;
    }

    public function getEmailToken($token)
    {
        foreach ($this->emailTokens as $emailToken) {
            if ($emailToken->getToken()==$token) {
                return $emailToken;
            }
        }
    }

    public function getName()
    {
        if (empty($this->getFullname())) {
            return $this->__toString();
        }
        return $this->getFullname();
    }

    /**
     * @return Collection|News[]
     */
    public function getNews(): Collection
    {
        return $this->news;
    }

    public function addNews(News $news): self
    {
        if (!$this->news->contains($news)) {
            $this->news[] = $news;
            $news->setUser($this);
        }

        return $this;
    }

    public function removeNews(News $news): self
    {
        if ($this->news->contains($news)) {
            $this->news->removeElement($news);
            // set the owning side to null (unless already changed)
            if ($news->getUser() === $this) {
                $news->setUser(null);
            }
        }

        return $this;
    }

    /**
     * @return Collection|Page[]
     */
    public function getPage(): Collection
    {
        return $this->page;
    }

    public function addPage(Page $page): self
    {
        if (!$this->page->contains($page)) {
            $this->page[] = $page;
            $page->setUser($this);
        }

        return $this;
    }

    public function removePage(Page $page): self
    {
        if ($this->page->contains($page)) {
            $this->page->removeElement($page);
            // set the owning side to null (unless already changed)
            if ($page->getUser() === $this) {
                $page->setUser(null);
            }
        }

        return $this;
    }
}
