<?php

/*
 * This file is part of the VitiCore 2.
 *
 * (c) CP Creation <web@cpcreation.fr>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace CpCreation\VitiCore\Shop\Model;

use CpCreation\VitiCore\Behavior\HasImage;
use CpCreation\VitiCore\Behavior\HasTimestamp;
use CpCreation\VitiCore\Behavior\HasTranslatable;
use CpCreation\VitiCore\Behavior\Impl\Image;
use CpCreation\VitiCore\Behavior\Impl\Timestamp;
use CpCreation\VitiCore\Behavior\Impl\Translatable;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Ramsey\Uuid\Uuid;
use Ramsey\Uuid\UuidInterface;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\Context\ExecutionContextInterface;

#[ORM\Table(name: 'shop_shop_config')]
#[ORM\HasLifecycleCallbacks]
#[ORM\Entity(repositoryClass: 'CpCreation\VitiCore\Shop\Repository\ShopConfigRepository')]
class ShopConfig implements HasImage, HasTimestamp, HasTranslatable
{
    use Image;
    use Timestamp;
    use Translatable;

    public const string INVOICE_PAYMENT_TERM_IMMEDIATE = 'immediate';
    public const string INVOICE_PAYMENT_TERM_RECEIPT = 'receipt';
    public const string INVOICE_PAYMENT_TERM_15_DAYS = '15_days';
    public const string INVOICE_PAYMENT_TERM_30_DAYS = '30_days';
    public const string INVOICE_PAYMENT_TERM_30_DAYS_END_OF_MONTH = '30_days_end_of_month';
    public const string INVOICE_PAYMENT_TERM_45_DAYS_END_OF_MONTH = '45_days_end_of_month';
    public const string INVOICE_PAYMENT_TERM_60_DAYS = '60_days';

    #[Assert\Valid]
    #[ORM\OneToMany(
        targetEntity: Translation\ShopConfigTranslation::class,
        mappedBy: 'translatable',
        cascade: ['all'],
        indexBy: 'locale',
        orphanRemoval: true
    )]
    protected $translations;

    #[ORM\Id]
    #[ORM\Column(type: 'uuid')]
    #[ORM\GeneratedValue(strategy: 'NONE')]
    private UuidInterface $id;

    #[ORM\Column(type: 'boolean')]
    private bool $hidePriceDefault;

    #[ORM\Column(type: 'boolean')]
    private bool $enableAwardShop;

    #[Assert\Type(type: 'integer')]
    #[ORM\Column(type: 'integer', nullable: true)]
    private ?int $maxAwardsVisibleInShop = null;

    #[ORM\OneToMany(
        targetEntity: ShopConfigDisableCountry::class,
        cascade: ['all'],
        mappedBy: 'config',
        orphanRemoval: true
    )]
    #[ORM\OrderBy(['country' => 'ASC'])]
    #[Assert\Valid]
    private Collection $disableCountries;

    #[ORM\Column(type: 'json', nullable: true, options: ['default' => '[]'])]
    private ?array $enableCountriesForShop;

    #[ORM\Column(type: 'datetime', nullable: true)]
    private ?\DateTime $vacationOf = null;

    #[ORM\Column(type: 'datetime', nullable: true)]
    private ?\DateTime $vacationAt = null;

    #[ORM\Column(type: 'boolean')]
    private bool $disableShopForVacation;

    #[ORM\OneToMany(
        targetEntity: ShopConfigMultiple::class,
        cascade: ['all'],
        mappedBy: 'config',
        orphanRemoval: true
    )]
    #[ORM\OrderBy(['qtyOf' => 'ASC'])]
    #[Assert\Valid]
    private Collection $multiples;

    #[ORM\Column(type: 'string', nullable: true)]
    private ?string $giftCardCheckToken = null;

    #[ORM\Column(type: 'dateinterval', nullable: true)]
    private ?\DateInterval $giftCardValidTime = null;

    #[ORM\Column(type: 'boolean')]
    private bool $degrissivityByItem;

    #[ORM\Column(type: 'boolean', options: ['default' => false])]
    private bool $invoice;

    #[ORM\Column(type: 'string', length: 64, nullable: true)]
    private ?string $invoicePaymentTerm = null;

    #[ORM\Column(type: 'string', length: 64, nullable: true)]
    private ?string $invoiceSuffix = null;

    #[ORM\Column(type: 'boolean', options: ['default' => true])]
    private bool $enablePartnerCodeFront;

    #[ORM\Column(type: 'boolean', options: ['default' => false])]
    private bool $showPartnerCodeWhenShopBlocked;

    #[ORM\Column(type: 'string', length: 64, nullable: true)]
    private ?string $googleTagManagerId = null;

    #[ORM\Column(type: 'json', nullable: true, options: ['default' => '[]'])]
    private ?array $googleAnalyticsIds = [];

    #[ORM\Column(type: 'json', nullable: true, options: ['default' => '[]'])]
    private ?array $facebookPixelIds = [];

    #[ORM\Column(type: 'text', nullable: true)]
    private ?string $trackingHeadScripts = null;

    #[ORM\Column(type: 'text', nullable: true)]
    private ?string $trackingBodyScripts = null;

    #[ORM\Column(type: 'text', nullable: true)]
    private ?string $trackingCheckoutScripts = null;

    #[ORM\Column(type: 'text', nullable: true)]
    private ?string $trackingPaymentConfirmationScripts = null;

    #[ORM\Column(type: 'text', nullable: true)]
    private ?string $trackingPaymentErrorScripts = null;

    #[ORM\Column(type: 'text', nullable: true)]
    private ?string $trackingPaymentCanceledScripts = null;

    #[ORM\Column(type: 'text', nullable: true)]
    private ?string $trackingContactScripts = null;

    #[ORM\Column(type: 'text', nullable: true)]
    private ?string $trackingContactSuccessScripts = null;

    #[ORM\Column(type: 'boolean', options: ['default' => false])]
    private bool $enableCheckoutEventTracking = false;

    #[ORM\Column(type: 'boolean', options: ['default' => false])]
    private bool $enablePaymentSuccessEventTracking = false;

    #[ORM\Column(type: 'boolean', options: ['default' => false])]
    private bool $enablePaymentErrorEventTracking = false;

    #[ORM\Column(type: 'boolean', options: ['default' => false])]
    private bool $enablePaymentCanceledEventTracking = false;

    #[ORM\Column(type: 'boolean', options: ['default' => false])]
    private bool $enableContactPageEventTracking = false;

    #[ORM\Column(type: 'boolean', options: ['default' => false])]
    private bool $enableContactSuccessEventTracking = false;

    public function __construct()
    {
        $this->id = Uuid::uuid4();
        $this->hidePriceDefault = false;
        $this->enableAwardShop = false;
        $this->disableCountries = new ArrayCollection();
        $this->enableCountriesForShop = [];
        $this->disableShopForVacation = false;
        $this->multiples = new ArrayCollection();
        $this->degrissivityByItem = false;
        $this->invoice = false;
        $this->enablePartnerCodeFront = true;
        $this->showPartnerCodeWhenShopBlocked = false;
    }

    public function getId(): UuidInterface
    {
        return $this->id;
    }

    public function isHidePriceDefault(): bool
    {
        return $this->hidePriceDefault;
    }

    public function setHidePriceDefault(bool $hidePriceDefault): void
    {
        $this->hidePriceDefault = $hidePriceDefault;
    }

    public function isEnableAwardShop(): bool
    {
        return $this->enableAwardShop;
    }

    public function setEnableAwardShop(bool $enableAwardShop): void
    {
        $this->enableAwardShop = $enableAwardShop;
    }

    public function addDisableCountry(ShopConfigDisableCountry $disableCountry): void
    {
        if ($this->disableCountries->contains($disableCountry)) {
            return;
        }

        $disableCountry->setConfig($this);
        $this->disableCountries->add($disableCountry);
    }

    public function removeDisableCountry(ShopConfigDisableCountry $disableCountry): void
    {
        if (!$this->disableCountries->contains($disableCountry)) {
            return;
        }

        $this->disableCountries->removeElement($disableCountry);
    }

    public function getDisableCountries(): Collection
    {
        return $this->disableCountries;
    }

    public function getEnableCountriesForShop(): ?array
    {
        return $this->enableCountriesForShop;
    }

    public function setEnableCountriesForShop(?array $enableCountriesForShop): void
    {
        $this->enableCountriesForShop = $enableCountriesForShop;
    }

    public function getMaxAwardsVisibleInShop(): ?int
    {
        return $this->maxAwardsVisibleInShop;
    }

    public function setMaxAwardsVisibleInShop(?int $maxAwardsVisibleInShop): void
    {
        $this->maxAwardsVisibleInShop = $maxAwardsVisibleInShop;
    }

    public function addMultiple(ShopConfigMultiple $multiple): void
    {
        if ($this->multiples->contains($multiple)) {
            return;
        }

        $multiple->setConfig($this);
        $this->multiples->add($multiple);
    }

    public function removeMultiple(ShopConfigMultiple $multiple): void
    {
        if (!$this->multiples->contains($multiple)) {
            return;
        }

        $multiple->setConfig(null);
        $this->multiples->removeElement($multiple);
    }

    public function getVacationOf(): ?\DateTime
    {
        return $this->vacationOf;
    }

    public function setVacationOf(?\DateTime $vacationOf): void
    {
        $this->vacationOf = $vacationOf;
    }

    public function getVacationAt(): ?\DateTime
    {
        return $this->vacationAt;
    }

    public function setVacationAt(?\DateTime $vacationAt): void
    {
        $this->vacationAt = $vacationAt;
    }

    public function isDisableShopForVacation(): bool
    {
        return $this->disableShopForVacation;
    }

    public function setDisableShopForVacation(bool $disableShopForVacation): void
    {
        $this->disableShopForVacation = $disableShopForVacation;
    }

    public function getMultiples(): Collection
    {
        return $this->multiples;
    }

    public function getGiftCardCheckToken(): ?string
    {
        return $this->giftCardCheckToken;
    }

    public function setGiftCardCheckToken(?string $giftCardCheckToken): void
    {
        $this->giftCardCheckToken = $giftCardCheckToken;
    }

    public function getGiftCardValidTime(): ?\DateInterval
    {
        return $this->giftCardValidTime;
    }

    public function setGiftCardValidTime(?\DateInterval $giftCardValidTime): void
    {
        $this->giftCardValidTime = $giftCardValidTime;
    }

    public function isDegrissivityByItem(): bool
    {
        return $this->degrissivityByItem;
    }

    public function setDegrissivityByItem(bool $degrissivityByItem): void
    {
        $this->degrissivityByItem = $degrissivityByItem;
    }

    public function isInvoice(): bool
    {
        return $this->invoice;
    }

    public function setInvoice(bool $invoice): void
    {
        $this->invoice = $invoice;
    }

    public function getInvoicePaymentTerm(): ?string
    {
        return $this->invoicePaymentTerm;
    }

    public function setInvoicePaymentTerm(?string $invoicePaymentTerm): void
    {
        $allowed = array_values(self::getInvoicePaymentTermChoices());

        if (null !== $invoicePaymentTerm && !\in_array($invoicePaymentTerm, $allowed, true)) {
            $invoicePaymentTerm = null;
        }

        $this->invoicePaymentTerm = $invoicePaymentTerm;
    }

    public function getInvoiceSuffix(): ?string
    {
        return $this->invoiceSuffix;
    }

    public function setInvoiceSuffix(?string $invoiceSuffix): void
    {
        $invoiceSuffix = null !== $invoiceSuffix ? mb_trim($invoiceSuffix) : null;
        $this->invoiceSuffix = '' !== (string) $invoiceSuffix ? $invoiceSuffix : null;
    }

    /**
     * @return array<string, string>
     */
    public static function getInvoicePaymentTermChoices(): array
    {
        return [
            'Comptant' => self::INVOICE_PAYMENT_TERM_IMMEDIATE,
            'A réception' => self::INVOICE_PAYMENT_TERM_RECEIPT,
            'Sous 15 jours' => self::INVOICE_PAYMENT_TERM_15_DAYS,
            'Sous 30 jours' => self::INVOICE_PAYMENT_TERM_30_DAYS,
            '30 jours fin de mois' => self::INVOICE_PAYMENT_TERM_30_DAYS_END_OF_MONTH,
            '45 jours fin de mois' => self::INVOICE_PAYMENT_TERM_45_DAYS_END_OF_MONTH,
            '60 jours nets' => self::INVOICE_PAYMENT_TERM_60_DAYS,
        ];
    }

    #[Assert\Callback]
    public function validateInvoiceConfiguration(ExecutionContextInterface $context): void
    {
        if ($this->invoice && (null === $this->invoicePaymentTerm || '' === $this->invoicePaymentTerm)) {
            $context
                ->buildViolation('Veuillez sélectionner des conditions de règlement lorsque la facturation est activée.')
                ->atPath('invoicePaymentTerm')
                ->addViolation();
        }
    }

    public function isEnablePartnerCodeFront(): bool
    {
        return $this->enablePartnerCodeFront;
    }

    public function setEnablePartnerCodeFront(bool $enablePartnerCodeFront): void
    {
        $this->enablePartnerCodeFront = $enablePartnerCodeFront;
    }

    public function isShowPartnerCodeWhenShopBlocked(): bool
    {
        return $this->showPartnerCodeWhenShopBlocked;
    }

    public function setShowPartnerCodeWhenShopBlocked(bool $showPartnerCodeWhenShopBlocked): void
    {
        $this->showPartnerCodeWhenShopBlocked = $showPartnerCodeWhenShopBlocked;
    }

    public function getGoogleTagManagerId(): ?string
    {
        return $this->googleTagManagerId;
    }

    public function setGoogleTagManagerId(?string $googleTagManagerId): void
    {
        $googleTagManagerId = null !== $googleTagManagerId ? mb_strtoupper(mb_trim($googleTagManagerId)) : null;
        $this->googleTagManagerId = '' !== (string) $googleTagManagerId ? $googleTagManagerId : null;
    }

    /**
     * @return list<string>
     */
    public function getGoogleAnalyticsIds(): array
    {
        return $this->normalizeTrackerIds($this->googleAnalyticsIds);
    }

    /**
     * @param array<int|string, string>|null $googleAnalyticsIds
     */
    public function setGoogleAnalyticsIds(?array $googleAnalyticsIds): void
    {
        $this->googleAnalyticsIds = $this->normalizeTrackerIds($googleAnalyticsIds);
    }

    /**
     * @return list<string>
     */
    public function getFacebookPixelIds(): array
    {
        return $this->normalizeTrackerIds($this->facebookPixelIds);
    }

    /**
     * @param array<int|string, string>|null $facebookPixelIds
     */
    public function setFacebookPixelIds(?array $facebookPixelIds): void
    {
        $this->facebookPixelIds = $this->normalizeTrackerIds($facebookPixelIds);
    }

    public function getTrackingHeadScripts(): ?string
    {
        return $this->trackingHeadScripts;
    }

    public function setTrackingHeadScripts(?string $trackingHeadScripts): void
    {
        $trackingHeadScripts = null !== $trackingHeadScripts ? mb_trim($trackingHeadScripts) : null;
        $this->trackingHeadScripts = '' !== (string) $trackingHeadScripts ? $trackingHeadScripts : null;
    }

    public function getTrackingBodyScripts(): ?string
    {
        return $this->trackingBodyScripts;
    }

    public function setTrackingBodyScripts(?string $trackingBodyScripts): void
    {
        $trackingBodyScripts = null !== $trackingBodyScripts ? mb_trim($trackingBodyScripts) : null;
        $this->trackingBodyScripts = '' !== (string) $trackingBodyScripts ? $trackingBodyScripts : null;
    }

    public function getTrackingCheckoutScripts(): ?string
    {
        return $this->trackingCheckoutScripts;
    }

    public function setTrackingCheckoutScripts(?string $trackingCheckoutScripts): void
    {
        $trackingCheckoutScripts = null !== $trackingCheckoutScripts ? mb_trim($trackingCheckoutScripts) : null;
        $this->trackingCheckoutScripts = '' !== (string) $trackingCheckoutScripts ? $trackingCheckoutScripts : null;
    }

    public function getTrackingPaymentConfirmationScripts(): ?string
    {
        return $this->trackingPaymentConfirmationScripts;
    }

    public function setTrackingPaymentConfirmationScripts(?string $trackingPaymentConfirmationScripts): void
    {
        $trackingPaymentConfirmationScripts = null !== $trackingPaymentConfirmationScripts ? mb_trim($trackingPaymentConfirmationScripts) : null;
        $this->trackingPaymentConfirmationScripts = '' !== (string) $trackingPaymentConfirmationScripts ? $trackingPaymentConfirmationScripts : null;
    }

    public function getTrackingPaymentErrorScripts(): ?string
    {
        return $this->trackingPaymentErrorScripts;
    }

    public function setTrackingPaymentErrorScripts(?string $trackingPaymentErrorScripts): void
    {
        $trackingPaymentErrorScripts = null !== $trackingPaymentErrorScripts ? mb_trim($trackingPaymentErrorScripts) : null;
        $this->trackingPaymentErrorScripts = '' !== (string) $trackingPaymentErrorScripts ? $trackingPaymentErrorScripts : null;
    }

    public function getTrackingPaymentCanceledScripts(): ?string
    {
        return $this->trackingPaymentCanceledScripts;
    }

    public function setTrackingPaymentCanceledScripts(?string $trackingPaymentCanceledScripts): void
    {
        $trackingPaymentCanceledScripts = null !== $trackingPaymentCanceledScripts ? mb_trim($trackingPaymentCanceledScripts) : null;
        $this->trackingPaymentCanceledScripts = '' !== (string) $trackingPaymentCanceledScripts ? $trackingPaymentCanceledScripts : null;
    }

    public function getTrackingContactScripts(): ?string
    {
        return $this->trackingContactScripts;
    }

    public function setTrackingContactScripts(?string $trackingContactScripts): void
    {
        $trackingContactScripts = null !== $trackingContactScripts ? mb_trim($trackingContactScripts) : null;
        $this->trackingContactScripts = '' !== (string) $trackingContactScripts ? $trackingContactScripts : null;
    }

    public function getTrackingContactSuccessScripts(): ?string
    {
        return $this->trackingContactSuccessScripts;
    }

    public function setTrackingContactSuccessScripts(?string $trackingContactSuccessScripts): void
    {
        $trackingContactSuccessScripts = null !== $trackingContactSuccessScripts ? mb_trim($trackingContactSuccessScripts) : null;
        $this->trackingContactSuccessScripts = '' !== (string) $trackingContactSuccessScripts ? $trackingContactSuccessScripts : null;
    }

    public function isEnableCheckoutEventTracking(): bool
    {
        return $this->enableCheckoutEventTracking;
    }

    public function setEnableCheckoutEventTracking(bool $enableCheckoutEventTracking): void
    {
        $this->enableCheckoutEventTracking = $enableCheckoutEventTracking;
    }

    public function isEnablePaymentSuccessEventTracking(): bool
    {
        return $this->enablePaymentSuccessEventTracking;
    }

    public function setEnablePaymentSuccessEventTracking(bool $enablePaymentSuccessEventTracking): void
    {
        $this->enablePaymentSuccessEventTracking = $enablePaymentSuccessEventTracking;
    }

    public function isEnablePaymentErrorEventTracking(): bool
    {
        return $this->enablePaymentErrorEventTracking;
    }

    public function setEnablePaymentErrorEventTracking(bool $enablePaymentErrorEventTracking): void
    {
        $this->enablePaymentErrorEventTracking = $enablePaymentErrorEventTracking;
    }

    public function isEnablePaymentCanceledEventTracking(): bool
    {
        return $this->enablePaymentCanceledEventTracking;
    }

    public function setEnablePaymentCanceledEventTracking(bool $enablePaymentCanceledEventTracking): void
    {
        $this->enablePaymentCanceledEventTracking = $enablePaymentCanceledEventTracking;
    }

    public function isEnableContactPageEventTracking(): bool
    {
        return $this->enableContactPageEventTracking;
    }

    public function setEnableContactPageEventTracking(bool $enableContactPageEventTracking): void
    {
        $this->enableContactPageEventTracking = $enableContactPageEventTracking;
    }

    public function isEnableContactSuccessEventTracking(): bool
    {
        return $this->enableContactSuccessEventTracking;
    }

    public function setEnableContactSuccessEventTracking(bool $enableContactSuccessEventTracking): void
    {
        $this->enableContactSuccessEventTracking = $enableContactSuccessEventTracking;
    }

    /**
     * @param array<int|string, mixed>|null $ids
     *
     * @return list<string>
     */
    private function normalizeTrackerIds(?array $ids): array
    {
        if (null === $ids) {
            return [];
        }

        $normalized = [];

        foreach ($ids as $id) {
            if (!\is_scalar($id)) {
                continue;
            }

            $value = mb_strtoupper(mb_trim((string) $id));

            if ('' === $value || \in_array($value, $normalized, true)) {
                continue;
            }

            $normalized[] = $value;
        }

        return $normalized;
    }

}
