<?php

declare(strict_types=1);

/*
 * This file is part of the VITICORE2 package.
 *
 * (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\Marketing\Model;

use CpCreation\VitiCore\Behavior\HasTimestamp;
use CpCreation\VitiCore\Behavior\HasTranslatable;
use CpCreation\VitiCore\Behavior\Impl\Timestamp;
use CpCreation\VitiCore\Behavior\Impl\Translatable;
use CpCreation\VitiCore\Marketing\Model\Translation\ReviewRequestConfigurationTranslation;
use CpCreation\VitiCore\Marketing\Repository\ReviewRequestConfigurationRepository;
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\Entity(repositoryClass: ReviewRequestConfigurationRepository::class)]
#[ORM\Table(name: 'marketing_review_request_configuration')]
#[ORM\HasLifecycleCallbacks]
class ReviewRequestConfiguration implements HasTimestamp, HasTranslatable
{
    use Timestamp;
    use Translatable;

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

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

    #[Assert\Range(min: 1, max: 365)]
    #[ORM\Column(type: 'smallint', options: ['default' => 10])]
    private int $sendDelayDays = 10;

    #[Assert\Range(min: 1, max: 365)]
    #[ORM\Column(type: 'smallint', options: ['default' => 90])]
    private int $tokenLifetimeDays = 90;

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

    #[Assert\Range(min: 1, max: 365)]
    #[ORM\Column(type: 'smallint', options: ['default' => 7])]
    private int $secondReminderDelayDays = 7;

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

    #[Assert\Length(max: 2048)]
    #[Assert\Url(protocols: ['http', 'https'])]
    #[ORM\Column(type: 'text', nullable: true)]
    private ?string $googleBusinessReviewUrl = null;

    #[ORM\Column(type: 'datetime_immutable')]
    private \DateTimeImmutable $fulfilledAfter;

    public function __construct()
    {
        $this->id = Uuid::uuid4();
        $this->fulfilledAfter = new \DateTimeImmutable();
    }

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

    public function isEnabled(): bool
    {
        return $this->enabled;
    }

    public function setEnabled(bool $enabled): void
    {
        $this->enabled = $enabled;
    }

    public function getSendDelayDays(): int
    {
        return $this->sendDelayDays;
    }

    public function setSendDelayDays(int $sendDelayDays): void
    {
        $this->sendDelayDays = $sendDelayDays;
    }

    public function getTokenLifetimeDays(): int
    {
        return $this->tokenLifetimeDays;
    }

    public function setTokenLifetimeDays(int $tokenLifetimeDays): void
    {
        $this->tokenLifetimeDays = $tokenLifetimeDays;
    }

    public function isSecondReminderEnabled(): bool
    {
        return $this->secondReminderEnabled;
    }

    public function setSecondReminderEnabled(bool $secondReminderEnabled): void
    {
        $this->secondReminderEnabled = $secondReminderEnabled;
    }

    public function getSecondReminderDelayDays(): int
    {
        return $this->secondReminderDelayDays;
    }

    public function setSecondReminderDelayDays(int $secondReminderDelayDays): void
    {
        $this->secondReminderDelayDays = $secondReminderDelayDays;
    }

    public function isModerationRequired(): bool
    {
        return $this->moderationRequired;
    }

    public function setModerationRequired(bool $moderationRequired): void
    {
        $this->moderationRequired = $moderationRequired;
    }

    public function getGoogleBusinessReviewUrl(): ?string
    {
        return $this->googleBusinessReviewUrl;
    }

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

    public function getPolicyAdditionalContentForLocale(
        string $locale,
        string $fallbackLocale = 'fr',
    ): ?string {
        $translation = $this->translate($locale, false);
        if ($translation instanceof ReviewRequestConfigurationTranslation) {
            $content = $translation->getPolicyAdditionalContent();
            if (null !== $content) {
                return $content;
            }
        }

        if ($locale === $fallbackLocale) {
            return null;
        }

        $fallback = $this->translate($fallbackLocale, false);

        return $fallback instanceof ReviewRequestConfigurationTranslation
            ? $fallback->getPolicyAdditionalContent()
            : null;
    }

    public function getEmailTitleForLocale(string $locale): ?string
    {
        $locale = mb_strtolower(str_replace('_', '-', mb_trim($locale)));
        $locales = array_values(array_unique(array_filter([
            $locale,
            explode('-', $locale, 2)[0] ?? null,
        ])));

        foreach ($locales as $candidate) {
            $translation = $this->translate($candidate, false);
            if (
                $translation instanceof ReviewRequestConfigurationTranslation
                && null !== $title = $translation->getEmailTitle()
            ) {
                return $title;
            }
        }

        return null;
    }

    public function getFulfilledAfter(): \DateTimeImmutable
    {
        return $this->fulfilledAfter;
    }

    public function setFulfilledAfter(\DateTimeImmutable $fulfilledAfter): void
    {
        $this->fulfilledAfter = $fulfilledAfter;
    }

    #[Assert\Callback]
    public function validateSecondReminderDelay(ExecutionContextInterface $context): void
    {
        if ($this->secondReminderEnabled && $this->secondReminderDelayDays >= $this->tokenLifetimeDays) {
            $context
                ->buildViolation('marketing.review_request.validation.second_reminder_before_expiry')
                ->atPath('secondReminderDelayDays')
                ->addViolation()
            ;
        }
    }
}
