<?php

namespace AppBundle\Entity;

use AppBundle\Utils\Traits\IsVisibleTrait;
use AppBundle\Utils\Traits\ModerationTrait;
use AppBundle\Utils\Traits\StatusTrait;
use AppBundle\Utils\Traits\TimestampableTrait;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * Ad
 *
 * @ORM\Table(name="ad")
 * @ORM\Entity(repositoryClass="AppBundle\Repository\AdRepository")
 * @ORM\HasLifecycleCallbacks()
 */
class Ad
{

    use TimestampableTrait;
    use StatusTrait;
    use IsVisibleTrait;
    use ModerationTrait;

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

    /**
     * @var string
     *
     * @ORM\Column(name="reference", type="string", length=255)
     */
    private $reference;

    /**
     * @var string
     *
     * @ORM\Column(name="reference_tt", type="string", length=255)
     */
    private $referenceTt;

    /**
     * @var string
     *
     * @ORM\Column(name="title", type="string", length=255)
     */
    private $title;

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

    /**
     * @var string
     *
     * @ORM\Column(name="description", type="text", nullable=true)
     */
    private $description;

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="published_at", type="datetime", nullable=true)
     * @Assert\GreaterThanOrEqual("today", groups={"dates"})
     */
    private $publishedAt;

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="unpublished_at", type="datetime", nullable=true)
     */
    private $unpublishedAt;

    /**
     * @var boolean
     *
     * @ORM\Column(name="is_verified", type="boolean", nullable=true, options={"comment":"Etat de vérification"})
     */
    private $isVerified;

    /**
     * @var boolean
     *
     * @ORM\Column(name="is_promoted", type="boolean", nullable=true, options={"comment":"Peux t'on répondre"})
     */
    private $isPromoted;

    /**
     * @var boolean
     *
     * @ORM\Column(name="is_private", type="boolean", nullable=true, options={"comment":"Annonce privé, non listée en front"})
     */
    private $isPrivate;

    /**
     * @var boolean
     *
     * @ORM\Column(name="is_answerable", type="boolean", nullable=true, options={"comment":"Annonce promu ?"})
     */
    private $isAnswerable;

    /**
     * @var integer
     *
     * @ORM\Column(name="defcon", type="smallint", nullable=true, options={"comment":"Etat d'alerte de modération"})
     */
    private $defcon;

    /**
     * @var array
     *
     * @ORM\Column(name="public_tag", type="json_document", nullable=true, options={"jsonb":true})
     */
    private $publicTag;

    /**
     * @var array
     *
     * @ORM\Column(name="private_tag", type="json_document", nullable=true, options={"jsonb":true})
     */
    private $privateTag;

    /**
     * @var array
     *
     * @ORM\Column(name="extra", type="json_document", nullable=true, options={"jsonb":true})
     */
    private $extra;

    /**
     * @var array
     *
     * @ORM\Column(name="location", type="json_document", nullable=true, options={"jsonb":true})
     */
    private $location;

    /**
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Media", inversedBy="ads", cascade={"persist"})
     */
    private $video;

    /**
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Company", inversedBy="ads")
     */
    private $company;

    /**
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\User", inversedBy="ads")
     */
    private $creator;

    /**
     * @var string
     *
     * @ORM\Column(name="emphasis", type="boolean", options={"comment":"A la une"}, nullable=true)
     */
    private $emphasis;

    /**
     * @var string
     *
     * @ORM\Column(name="emphasis_order", type="integer", options={"comment":"Ordre"}, nullable=true)
     */
    private $emphasisOrder;

    /***********************
     * OneToMany Array's
     ***********************/

    /**
     * @ORM\OneToMany(targetEntity="AppBundle\Entity\Answer", mappedBy="ad", cascade={"persist", "remove"})
     * @ORM\OrderBy({"sendTime" = "DESC"})
     */
    private $answers;

    /**
     * @ORM\OneToMany(targetEntity="AppBundle\Entity\ProductAd", mappedBy="ad", cascade={"persist", "remove"})
     */
    private $products;

    /**
     * @ORM\ManyToMany(targetEntity="AppBundle\Entity\Note", cascade={"persist", "remove"})
     */
    private $draftNotes;

    /**
     * @ORM\OneToMany(targetEntity="AppBundle\Entity\TerritoryAd", mappedBy="ad", cascade={"persist", "remove"})
     */
    private $territories;

    /**
     * @ORM\OneToMany(targetEntity="AppBundle\Entity\BookmarkAd", mappedBy="ad", cascade={"persist", "remove"})
     */
    private $bookmarkAds;


    /***********************
     * Constructor
     ***********************/

    public function __construct($user = null)
    {
        $this->answers = new \Doctrine\Common\Collections\ArrayCollection();
        $this->products = new \Doctrine\Common\Collections\ArrayCollection();
        $this->draftNotes = new \Doctrine\Common\Collections\ArrayCollection();

        $this->publishedAt = new \DateTime('today');
        $this->unpublishedAt = new \DateTime('tomorrow');
        $this->status = "DRAFT";
        $this->referenceTt = uniqid('ad_');
        $this->isAnswerable = true;
        $this->isVisible = true;
        $this->isVerified = false;
        $this->defcon = 0;

        if ($user != null) {
            $this->creator = $user;
            $this->company = $user->getCompany();
        }
    }


    /**********************
     * Assert
     *********************/

    /**
     * @Assert\IsTrue(message = "La date de fin de mise en ligne doit être superieur à la date de début", groups={"dates"})
     */
    public function isUnpublishedAtValid()
    {
        return $this->unpublishedAt > $this->publishedAt;
    }

    /***********************
     * Custom Functions
     ***********************/

    /**
     * @return integer
     *
     * Return the number of month needed to publish an AD or to refund a user.
     */
    public function calcMonth()
    {
        $interval = $this->getPublishedAt()->diff($this->getUnpublishedAt());
        $numberOfMonth = $interval->format('%m');
        $numberOfDay = $interval->format('%d');

        if ($numberOfDay > 0) {
            $numberOfMonth = $numberOfMonth + 1;
        }

        $existingProductMonth = array();
        foreach ($this->getProducts() as $product) {
            if ($product->getProduct()->getType() == "MONTH" && $product->getProduct()->getStatus() !== "DISABLED") {
                $existingProductMonth[] = $product->getProduct()->getId();
            }
        }

        $numberOfMonth = $numberOfMonth - count($existingProductMonth);
        return $numberOfMonth;

    }

    /**
     * @return bool
     *
     * Check if the AD already have an "AD Token" associate it.
     */
    public function hasAd()
    {
        $boolean = false;
        foreach ($this->getProducts() as $product) {
            if ($product->getProduct()->getType() == "AD") {
                $boolean = true;
            }
        }
        return $boolean;
    }


    /**
     * @return array|null
     *
     * Search contract type in the extra field
     */
    public function getContractType()
    {
        $contract_type = null;
        $extra = $this->extra;
        if ($extra) {
            if (array_key_exists('contract_type', $extra)) {
                $contract_type = $extra['contract_type'];
            }
        }

        return $contract_type;
    }

    /**
     * @return array|null
     *
     * Search for geometry point in the gmap_address field
     */
    public function getGeoPoint()
    {
        $point = null;
        $location = $this->location;
        if ($location) {
            if (array_key_exists('gmap_address', $location)) {
                $point = $this->location['gmap_address']['geometry']['location'];
                if (array_key_exists('lng', $point)) {
                    $point['lon'] = $point['lng'];
                    unset($point['lng']);
                }
            }
        }

        return $point;
    }

    /**
     * @return array|null
     *
     * Search for address components in the gmap_address field
     */
    public function getAddress()
    {
        $address = null;
        $location = $this->location;
        if ($location) {
            if (array_key_exists('gmap_address', $location)) {
                $components = $location['gmap_address']['address_components'];
                $address = array();
                foreach ($components as $c) {
                    $address[$c['types'][0]] = $c['long_name'];
                }
            }
        }

        return $address;
    }

    /**
     * @return mixed
     *
     * Return ad's company brandname
     */
    public function getCompanyName()
    {
        return $this->company->getBrandName();
    }

    public function countAnswers()
    {
        $answers = $this->answers;
        $i = 0;
        foreach ($answers as $a) {
            if ($a->getStatus() == "SENDED") {
                $i++;
            }
        }
        return $i;
    }

    /**
     * @return string
     *
     * Return generated title for template
     */
    public function getHtmlTitle()
    {
        $address = $this->getAddress();
        $title = "Offre d'emploi " . $this->title;
        if (isset($address['locality'])) {
            $title .= ' - ' . $address['locality'];
        }
        if (isset($address['postal_code'])) {
            $zip = substr($address['postal_code'], 0, 2);
            $title .= ' (' . $zip . ')';
        }
        $title .= ' - ' . $this->getCompany()->getBrandName() . ' | Talents Tube';
        return urldecode($title);

    }

    /**
     * @return string
     *
     * Return generated description for template
     */
    public function getHtmlDescription()
    {
        $address = $this->getAddress();
        $desc = 'Découvrez la vidéo de l\'offre d\'emploi ' . $this->title;
        if (isset($address['locality'])) {
            $desc .= ' - ' .$address['locality'];
        }
        if (isset($address['postal_code'])) {
            $zip = substr($address['postal_code'], 0, 2);
            $desc .= ' (' . $zip . ')';
        }
        $desc .= '. Postulez en vidéo dès aujourd\'hui !';
        return urldecode($desc);

    }

    /**
     * @return string
     *
     * Return generated structured data for template
     */
    public function getStructuredData()
    {
        $data = array();
        $data['@context'] = 'http://schema.org';
        $data['@type'] = 'JobPosting';
        $data['datePosted'] = $this->publishedAt->format('Y-m-d');
        $data['description'] = $this->description;
        $data['title'] = $this->title;
        $data['hiringOrganization'] = $this->getCompany()->getBrandName();

        $address = $this->getAddress();
        $extra = $this->extra;

        if (isset($address['locality'])) {
            $data['jobLocation'] = $address['locality'];
        }
        if (isset($extra['contract_type'])) {
            $data['employmentType'] = $extra['contract_type'];

        }
        return json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);

    }
    /***********************
     * Getters & Setters
     ***********************/


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

    /**
     * Set reference.
     *
     * @param string $reference
     *
     * @return Ad
     */
    public function setReference($reference)
    {
        $this->reference = $reference;

        return $this;
    }

    /**
     * Get reference.
     *
     * @return string
     */
    public function getReference()
    {
        return $this->reference;
    }

    /**
     * Set referenceTt.
     *
     * @param string $referenceTt
     *
     * @return Ad
     */
    public function setReferenceTt($referenceTt)
    {
        $this->referenceTt = $referenceTt;

        return $this;
    }

    /**
     * Get referenceTt.
     *
     * @return string
     */
    public function getReferenceTt()
    {
        return $this->referenceTt;
    }

    /**
     * Set title.
     *
     * @param string $title
     *
     * @return Ad
     */
    public function setTitle($title)
    {
        $this->title = $title;

        return $this;
    }

    /**
     * Get title.
     *
     * @return string
     */
    public function getTitle()
    {
        return $this->title;
    }

    /**
     * Set description.
     *
     * @param string|null $description
     *
     * @return Ad
     */
    public function setDescription($description = null)
    {
        $this->description = $description;

        return $this;
    }

    /**
     * Get description.
     *
     * @return string|null
     */
    public function getDescription()
    {
        return $this->description;
    }

    /**
     * Set publishedAt.
     *
     * @param \DateTime|null $publishedAt
     *
     * @return Ad
     */
    public function setPublishedAt(\DateTime $publishedAt = null)
    {
        $this->publishedAt = clone $publishedAt;

        return $this;
    }

    /**
     * Get publishedAt.
     *
     * @return \DateTime|null
     */
    public function getPublishedAt()
    {
        return clone $this->publishedAt;
    }

    /**
     * Set unpublishedAt.
     *
     * @param \DateTime|null $unpublishedAt
     *
     * @return Ad
     */
    public function setUnpublishedAt(\DateTime $unpublishedAt = null)
    {
        $this->unpublishedAt = clone $unpublishedAt;

        return $this;
    }

    /**
     * Get unpublishedAt.
     *
     * @return \DateTime|null
     */
    public function getUnpublishedAt()
    {
        return clone $this->unpublishedAt;
    }

    /**
     * Set isVerified.
     *
     * @param bool|null $isVerified
     *
     * @return Ad
     */
    public function setIsVerified($isVerified = null)
    {
        $this->isVerified = $isVerified;

        return $this;
    }

    /**
     * Get isVerified.
     *
     * @return bool|null
     */
    public function getIsVerified()
    {
        return $this->isVerified;
    }

    /**
     * Set isAnswerable.
     *
     * @param bool|null $isAnswerable
     *
     * @return Ad
     */
    public function setIsAnswerable($isAnswerable = null)
    {
        $this->isAnswerable = $isAnswerable;

        return $this;
    }

    /**
     * Get isAnswerable.
     *
     * @return bool|null
     */
    public function getIsAnswerable()
    {
        return $this->isAnswerable;
    }

    /**
     * Set defcon.
     *
     * @param int|null $defcon
     *
     * @return Ad
     */
    public function setDefcon($defcon = null)
    {
        $this->defcon = $defcon;

        return $this;
    }

    /**
     * Get defcon.
     *
     * @return int|null
     */
    public function getDefcon()
    {
        return $this->defcon;
    }

    /**
     * Set publicTag.
     *
     * @param json_document|null $publicTag
     *
     * @return Ad
     */
    public function setPublicTag($publicTag = null)
    {
        $this->publicTag = $publicTag;

        return $this;
    }

    /**
     * Get publicTag.
     *
     * @return json_document|null
     */
    public function getPublicTag()
    {
        return $this->publicTag;
    }

    /**
     * Set privateTag.
     *
     * @param json_document|null $privateTag
     *
     * @return Ad
     */
    public function setPrivateTag($privateTag = null)
    {
        $this->privateTag = $privateTag;

        return $this;
    }

    /**
     * Get privateTag.
     *
     * @return json_document|null
     */
    public function getPrivateTag()
    {
        return $this->privateTag;
    }

    /**
     * Set extra.
     *
     * @param json_document|null $extra
     *
     * @return Ad
     */
    public function setExtra($extra = null)
    {
        $this->extra = $extra;

        return $this;
    }

    /**
     * Get extra.
     *
     * @return json_document|null
     */
    public function getExtra()
    {
        return $this->extra;
    }

    /**
     * Set location.
     *
     * @param json_document|null $location
     *
     * @return Ad
     */
    public function setLocation($location = null)
    {
        $this->location = $location;

        return $this;
    }

    /**
     * Get location.
     *
     * @return json_document|null
     */
    public function getLocation()
    {
        return $this->location;
    }

    /**
     * Set video.
     *
     * @param \AppBundle\Entity\Media|null $video
     *
     * @return Ad
     */
    public function setVideo(\AppBundle\Entity\Media $video = null)
    {
        $this->video = $video;

        return $this;
    }

    /**
     * Get video.
     *
     * @return \AppBundle\Entity\Media|null
     */
    public function getVideo()
    {
        return $this->video;
    }

    /**
     * Set company.
     *
     * @param \AppBundle\Entity\Company|null $company
     *
     * @return Ad
     */
    public function setCompany(\AppBundle\Entity\Company $company = null)
    {
        $this->company = $company;

        return $this;
    }

    /**
     * Get company.
     *
     * @return \AppBundle\Entity\Company|null
     */
    public function getCompany()
    {
        return $this->company;
    }

    /**
     * Set creator.
     *
     * @param \AppBundle\Entity\User|null $creator
     *
     * @return Ad
     */
    public function setCreator(\AppBundle\Entity\User $creator = null)
    {
        $this->creator = $creator;

        return $this;
    }

    /**
     * Get creator.
     *
     * @return \AppBundle\Entity\User|null
     */
    public function getCreator()
    {
        return $this->creator;
    }

    /**
     * Add answer.
     *
     * @param \AppBundle\Entity\Answer $answer
     *
     * @return Ad
     */
    public function addAnswer(\AppBundle\Entity\Answer $answer)
    {
        $this->answers[] = $answer;

        return $this;
    }

    /**
     * Remove answer.
     *
     * @param \AppBundle\Entity\Answer $answer
     *
     * @return boolean TRUE if this collection contained the specified element, FALSE otherwise.
     */
    public function removeAnswer(\AppBundle\Entity\Answer $answer)
    {
        return $this->answers->removeElement($answer);
    }

    /**
     * Get answers.
     *
     * @return \Doctrine\Common\Collections\Collection
     */
    public function getAnswers()
    {
        return $this->answers;
    }

    /**
     * Add product.
     *
     * @param \AppBundle\Entity\ProductAd $product
     *
     * @return Ad
     */
    public function addProduct(\AppBundle\Entity\ProductAd $product)
    {
        $this->products[] = $product;

        return $this;
    }

    /**
     * Remove product.
     *
     * @param \AppBundle\Entity\ProductAd $product
     *
     * @return boolean TRUE if this collection contained the specified element, FALSE otherwise.
     */
    public function removeProduct(\AppBundle\Entity\ProductAd $product)
    {
        return $this->products->removeElement($product);
    }

    /**
     * Get products.
     *
     * @return \Doctrine\Common\Collections\Collection
     */
    public function getProducts()
    {
        return $this->products;
    }

    /**
     * Add draftNote.
     *
     * @param \AppBundle\Entity\Note $draftNote
     *
     * @return Ad
     */
    public function addDraftNote(\AppBundle\Entity\Note $draftNote)
    {
        $this->draftNotes[] = $draftNote;

        return $this;
    }

    /**
     * Remove draftNote.
     *
     * @param \AppBundle\Entity\Note $draftNote
     *
     * @return boolean TRUE if this collection contained the specified element, FALSE otherwise.
     */
    public function removeDraftNote(\AppBundle\Entity\Note $draftNote)
    {
        return $this->draftNotes->removeElement($draftNote);
    }

    /**
     * Get draftNotes.
     *
     * @return \Doctrine\Common\Collections\Collection
     */
    public function getDraftNotes()
    {
        return $this->draftNotes;
    }

    /**
     * Set alias.
     *
     * @param string|null $alias
     *
     * @return Ad
     */
    public function setAlias($alias = null)
    {
        $this->alias = $alias;

        return $this;
    }

    /**
     * Get alias.
     *
     * @return string|null
     */
    public function getAlias()
    {
        return $this->alias;
    }

    /**
     * Set isPromoted.
     *
     * @param bool|null $isPromoted
     *
     * @return Ad
     */
    public function setIsPromoted($isPromoted = null)
    {
        $this->isPromoted = $isPromoted;

        return $this;
    }

    /**
     * Get isPromoted.
     *
     * @return bool|null
     */
    public function getIsPromoted()
    {
        return $this->isPromoted;
    }

    /**
     * Set emphasis.
     *
     * @param bool|null $emphasis
     *
     * @return Ad
     */
    public function setEmphasis($emphasis = null)
    {
        $this->emphasis = $emphasis;

        return $this;
    }

    /**
     * Get emphasis.
     *
     * @return bool|null
     */
    public function getEmphasis()
    {
        return $this->emphasis;
    }

    /**
     * Set emphasisOrder.
     *
     * @param int|null $emphasisOrder
     *
     * @return Ad
     */
    public function setEmphasisOrder($emphasisOrder = null)
    {
        $this->emphasisOrder = $emphasisOrder;

        return $this;
    }

    /**
     * Get emphasisOrder.
     *
     * @return int|null
     */
    public function getEmphasisOrder()
    {
        return $this->emphasisOrder;
    }

    /**
     * Add territory.
     *
     * @param \AppBundle\Entity\TerritoryAd $territory
     *
     * @return Ad
     */
    public function addTerritory(\AppBundle\Entity\TerritoryAd $territory)
    {
        $this->territories[] = $territory;

        return $this;
    }

    /**
     * Remove territory.
     *
     * @param \AppBundle\Entity\TerritoryAd $territory
     *
     * @return boolean TRUE if this collection contained the specified element, FALSE otherwise.
     */
    public function removeTerritory(\AppBundle\Entity\TerritoryAd $territory)
    {
        return $this->territories->removeElement($territory);
    }

    /**
     * Get territories.
     *
     * @return \Doctrine\Common\Collections\Collection
     */
    public function getTerritories()
    {
        return $this->territories;
    }

    /**
     * Set isPrivate.
     *
     * @param bool|null $isPrivate
     *
     * @return Ad
     */
    public function setIsPrivate($isPrivate = null)
    {
        $this->isPrivate = $isPrivate;

        return $this;
    }

    /**
     * Get isPrivate.
     *
     * @return bool|null
     */
    public function getIsPrivate()
    {
        return $this->isPrivate;
    }

    /**
     * Add bookmarkAd.
     *
     * @param \AppBundle\Entity\BookmarkAd $bookmarkAd
     *
     * @return Ad
     */
    public function addBookmarkAd(\AppBundle\Entity\BookmarkAd $bookmarkAd)
    {
        $this->bookmarkAds[] = $bookmarkAd;

        return $this;
    }

    /**
     * Remove bookmarkAd.
     *
     * @param \AppBundle\Entity\BookmarkAd $bookmarkAd
     *
     * @return boolean TRUE if this collection contained the specified element, FALSE otherwise.
     */
    public function removeBookmarkAd(\AppBundle\Entity\BookmarkAd $bookmarkAd)
    {
        return $this->bookmarkAds->removeElement($bookmarkAd);
    }

    /**
     * Get bookmarkAds.
     *
     * @return \Doctrine\Common\Collections\Collection
     */
    public function getBookmarkAds()
    {
        return $this->bookmarkAds;
    }
}
