<?php

namespace App\Entity;

use App\Entity\Traits\TimestampableTrait;
use App\Entity\User\Note;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * Class User.
 *
 * @ORM\Entity
 * @ORM\EntityListeners({"App\EntityListener\UserListener"})
 */
class User implements UserInterface
{
    use TimestampableTrait;

    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     *
     * @var int
     */
    private $id;

    /**
     * @ORM\Column(type="string")
     *
     * @var string
     * @Assert\NotBlank()
     * @Assert\Length(
     *      min = 2,
     *      max = 50,
     *      minMessage = "Your first name must be at least {{ limit }} characters long",
     *      maxMessage = "Your first name cannot be longer than {{ limit }} characters"
     * )
     */
    private $firstName;

    /**
     * @ORM\Column(type="string")
     *
     * @var string
     * @Assert\NotBlank()
     * @Assert\Length(
     *      min = 2,
     *      max = 50,
     *      minMessage = "Your last name must be at least {{ limit }} characters long",
     *      maxMessage = "Your last name cannot be longer than {{ limit }} characters"
     * )
     */
    private $lastName;

    /**
     * @ORM\Column(type="string")
     * @Assert\Email()
     * @Assert\NotBlank()
     *
     * @var string
     */
    private $email;

    /**
     * @ORM\Column(type="string")
     *
     * @var string
     * @Assert\NotBlank()
     * @Assert\Length(
     *      min = 2,
     *      max = 50,
     *      minMessage = "Your job title must be at least {{ limit }} characters long",
     *      maxMessage = "Your job title cannot be longer than {{ limit }} characters"
     * )
     */
    private $jobTitle;

    /**
     * @ORM\Column(type="string", length=64, nullable=true)
     */
    private $password;

    /**
     * @Assert\Length(min=8,max=256)
     */
    private $plainPassword;

    /**
     * @ORM\Column(type="boolean", options={"default": false})
     */
    private $active;

    /**
     * @ORM\OneToMany(targetEntity="App\Entity\Negotiation", mappedBy="user")
     */
    private $negotiations;

    /**
     * @ORM\OneToMany(targetEntity="App\Entity\NegotiationMessage", mappedBy="user")
     */
    private $negotiationMessages;

    /**
     * @ORM\ManyToMany(targetEntity="App\Entity\Role", inversedBy="users")
     */
    private $groups;

    /**
     * @ORM\OneToMany(targetEntity="App\Entity\Dashboard", mappedBy="user")
     */
    private $dashboards;

    /**
     * @ORM\OneToMany(targetEntity="App\Entity\User\Note", mappedBy="createdBy")
     */
    private $notes;

    /**
     * @ORM\OneToMany(targetEntity="App\Entity\PasswordToken", mappedBy="user")
     */
    private $passwordTokens;

    /**
     * @ORM\OneToOne(targetEntity="App\Entity\File", cascade={"persist", "remove"})
     */
    private $avatar;

    /**
     * @ORM\ManyToOne(targetEntity="App\Entity\Client", inversedBy="users")
     * @ORM\JoinColumn(onDelete="CASCADE")
     */
    private $client;

    public function __construct()
    {
        $this->negotiations = new ArrayCollection();
        $this->negotiationMessages = new ArrayCollection();
        $this->groups = new ArrayCollection();
        $this->dashboards = new ArrayCollection();
        $this->notes = new ArrayCollection();
        $this->passwordTokens = new ArrayCollection();
    }

    /**
     * @return int
     */
    public function getId(): int
    {
        return $this->id;
    }

    /**
     * @param int $id
     */
    public function setId(int $id): void
    {
        $this->id = $id;
    }

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

    /**
     * @param string $firstName
     */
    public function setFirstName(string $firstName): void
    {
        $this->firstName = $firstName;
    }

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

    /**
     * @param string $lastName
     */
    public function setLastName(string $lastName): void
    {
        $this->lastName = $lastName;
    }

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

    /**
     * @param string $email
     */
    public function setEmail(string $email): void
    {
        $this->email = $email;
    }

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

    /**
     * @param string $jobTitle
     */
    public function setJobTitle(string $jobTitle): void
    {
        $this->jobTitle = $jobTitle;
    }

    public function getPassword(): ?string
    {
        return $this->password;
    }

    public function setPassword(string $password): void
    {
        $this->password = $password;
    }

    public function getPlainPassword()
    {
        return $this->plainPassword;
    }

    public function setPlainPassword($password)
    {
        $this->plainPassword = $password;
    }

    public function isActive(): ?bool
    {
        return $this->active;
    }

    public function setActive(?bool $active)
    {
        $this->active = $active;
    }

    /**
     * Returns the roles granted to the user.
     * <code>
     * public function getRoles()
     * {
     *     return array('ROLE_USER');
     * }
     * </code>
     * Alternatively, the roles might be stored on a ``roles`` property,
     * and populated in any number of different ways when the user object
     * is created.
     *
     * @return array (Role|string)[] The user roles
     */
    public function getRoles()
    {
        $roles = array_map(function (Role $role) {
            return $role->getRole();
        }, $this->groups->toArray());

        // guarantee every user at least has ROLE_USER
        $roles[] = 'ROLE_USER';

        return array_unique($roles);
    }

    /**
     * @return ArrayCollection
     */
    public function getGroups()
    {
        return $this->groups;
    }

    /**
     * Returns the salt that was originally used to encode the password.
     * This can return null if the password was not encoded using a salt.
     *
     * @return void
     */
    public function getSalt()
    {
        // TODO: Implement getSalt() method.
    }

    /**
     * Returns the username used to authenticate the user.
     *
     * @return void
     */
    public function getUsername()
    {
        // TODO: Implement getUsername() method.
    }

    /**
     * Removes sensitive data from the user.
     * This is important if, at any given point, sensitive information like
     * the plain-text password is stored on this object.
     */
    public function eraseCredentials()
    {
        // TODO: Implement eraseCredentials() method.
    }

    public function addGroup(Role $role): self
    {
        if (!$this->groups->contains($role)) {
            $this->groups[] = $role;
        }

        return $this;
    }

    public function removeGroup(Role $role): self
    {
        if ($this->groups->contains($role)) {
            $this->groups->removeElement($role);
        }

        return $this;
    }

    /**
     * @return Collection
     */
    public function getDashboards(): Collection
    {
        return $this->dashboards;
    }

    public function addDashboard(Dashboard $dashboard): self
    {
        if (!$this->dashboards->contains($dashboard)) {
            $this->dashboards[] = $dashboard;
            $dashboard->setUser($this);
        }

        return $this;
    }

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

        return $this;
    }

    /**
     * @return Collection
     */
    public function getNotes(): Collection
    {
        return $this->notes;
    }

    public function addNote(Note $note): self
    {
        if (!$this->notes->contains($note)) {
            $this->notes[] = $note;
            $note->setCreatedBy($this);
        }

        return $this;
    }

    public function removeNote(Note $note): self
    {
        if ($this->notes->contains($note)) {
            $this->notes->removeElement($note);
            // set the owning side to null (unless already changed)
            if ($note->getCreatedBy() === $this) {
                $note->setCreatedBy(null);
            }
        }

        return $this;
    }

    /**
     * @return Collection
     */
    public function getPasswordTokens(): Collection
    {
        return $this->passwordTokens;
    }

    public function addPasswordToken(PasswordToken $passwordToken): self
    {
        if (!$this->passwordTokens->contains($passwordToken)) {
            $this->passwordTokens[] = $passwordToken;
            $passwordToken->setUser($this);
        }

        return $this;
    }

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

        return $this;
    }

    public function getAvatar(): ?File
    {
        return $this->avatar;
    }

    public function setAvatar(?File $avatar): self
    {
        $this->avatar = $avatar;

        return $this;
    }

    public function getCampaignIds(): array
    {
        $result = [];

        if ($client = $this->getClient()) {
            $client->getCampaigns()->map(function (Campaign $campaign) use (&$result) {
                $result[] = $campaign->getId();
            });
        }

        return $result;
    }

    public function getClient(): ?Client
    {
        return $this->client;
    }

    public function setClient(?Client $client): self
    {
        $this->client = $client;

        return $this;
    }

    /**
     * @return Collection
     */
    public function getNegotiations(): Collection
    {
        return $this->negotiations;
    }

    public function addNegotiation(Negotiation $negotiation): self
    {
        if (!$this->negotiations->contains($negotiation)) {
            $this->negotiations[] = $negotiation;
            $negotiation->setUser($this);
        }

        return $this;
    }

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

        return $this;
    }

    /**
     * @return Collection
     */
    public function getNegotiationMessages(): Collection
    {
        return $this->negotiationMessages;
    }

    public function addNegotiationMessage(NegotiationMessage $negotiationMessage): self
    {
        if (!$this->negotiationMessages->contains($negotiationMessage)) {
            $this->negotiationMessages[] = $negotiationMessage;
            $negotiationMessage->setUser($this);
        }

        return $this;
    }

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

        return $this;
    }
}
