<?php

/*
 * 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\Impl\Timestamp;
use CpCreation\VitiCore\Marketing\Emailing\BrevoSecretCipher;
use CpCreation\VitiCore\Marketing\Repository\BrevoConfigurationRepository;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity(repositoryClass: BrevoConfigurationRepository::class)]
#[ORM\Table(name: 'marketing_brevo_configuration')]
#[ORM\HasLifecycleCallbacks]
class BrevoConfiguration implements HasTimestamp
{
    use Timestamp;

    public const string SINGLETON_ID = 'default';

    #[ORM\Id]
    #[ORM\Column(length: 32)]
    private string $id = self::SINGLETON_ID;

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

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

    #[ORM\Column(length: 12, nullable: true)]
    private ?string $apiKeyHint = null;

    #[ORM\Column(length: 255, nullable: true)]
    private ?string $accountEmail = null;

    #[ORM\Column(length: 255, nullable: true)]
    private ?string $companyName = null;

    #[ORM\Column(length: 20, options: ['default' => 'not_configured'])]
    private string $connectionStatus = 'not_configured';

    #[ORM\Column(type: Types::DATETIMETZ_IMMUTABLE, nullable: true)]
    private ?\DateTimeImmutable $lastCheckedAt = null;

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

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

    public function setEnabled(bool $enabled): void
    {
        $this->enabled = $enabled;
        if (!$enabled) {
            $this->connectionStatus = 'disabled';
            $this->lastError = null;
        } elseif (!$this->hasApiKey()) {
            $this->connectionStatus = 'not_configured';
        }
    }

    public function hasApiKey(): bool
    {
        return null !== $this->apiKeyCiphertext;
    }

    public function replaceApiKey(#[\SensitiveParameter] string $apiKey, BrevoSecretCipher $cipher): void
    {
        $apiKey = mb_trim($apiKey);
        $this->apiKeyCiphertext = $cipher->encrypt($apiKey);
        $this->apiKeyHint = '••••'.mb_substr($apiKey, -4);
        $this->connectionStatus = 'unchecked';
        $this->lastError = null;
    }

    public function revealApiKey(BrevoSecretCipher $cipher): string
    {
        if (null === $this->apiKeyCiphertext) {
            throw new \LogicException('Aucune clé API Brevo n’est configurée.');
        }

        return $cipher->decrypt($this->apiKeyCiphertext);
    }

    public function markHealthy(?string $accountEmail, ?string $companyName): void
    {
        $this->connectionStatus = 'healthy';
        $this->accountEmail = self::trimToNull($accountEmail);
        $this->companyName = self::trimToNull($companyName);
        $this->lastCheckedAt = new \DateTimeImmutable('now', new \DateTimeZone('UTC'));
        $this->lastError = null;
    }

    public function markFailure(string $message): void
    {
        $this->connectionStatus = 'failed';
        $this->lastCheckedAt = new \DateTimeImmutable('now', new \DateTimeZone('UTC'));
        $this->lastError = mb_substr(mb_trim($message), 0, 2000);
    }

    public function getApiKeyHint(): ?string
    {
        return $this->apiKeyHint;
    }

    public function getAccountEmail(): ?string
    {
        return $this->accountEmail;
    }

    public function getCompanyName(): ?string
    {
        return $this->companyName;
    }

    public function getConnectionStatus(): string
    {
        return $this->connectionStatus;
    }

    public function getLastCheckedAt(): ?\DateTimeImmutable
    {
        return $this->lastCheckedAt;
    }

    public function getLastError(): ?string
    {
        return $this->lastError;
    }

    private static function trimToNull(?string $value): ?string
    {
        $value = null === $value ? null : mb_trim($value);

        return '' === $value ? null : $value;
    }
}
