<?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\Cart\Model;

use Doctrine\ORM\Mapping as ORM;
use Ramsey\Uuid\Uuid;
use Ramsey\Uuid\UuidInterface;

#[ORM\Entity(repositoryClass: 'CpCreation\VitiCore\Cart\Repository\WithdrawalRequestRepository')]
#[ORM\Table(name: 'cart_withdrawal_request')]
class WithdrawalRequest
{
    public const int COMMENT_MAX_LENGTH = 2000;

    public const string REASON_CHANGE_OF_MIND = 'change_of_mind';
    public const string REASON_ORDERED_BY_MISTAKE = 'ordered_by_mistake';
    public const string REASON_DELIVERY_TOO_LATE = 'delivery_too_late';
    public const string REASON_PRODUCT_NOT_AS_EXPECTED = 'product_not_as_expected';
    public const string REASON_OTHER = 'other';

    public const array REASON_CODES = [
        self::REASON_CHANGE_OF_MIND,
        self::REASON_ORDERED_BY_MISTAKE,
        self::REASON_DELIVERY_TOO_LATE,
        self::REASON_PRODUCT_NOT_AS_EXPECTED,
        self::REASON_OTHER,
    ];

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

    #[ORM\OneToOne(targetEntity: Cart::class, inversedBy: 'withdrawalRequest')]
    #[ORM\JoinColumn(nullable: false, onDelete: 'CASCADE')]
    private Cart $cart;

    #[ORM\Column(length: 255)]
    private string $firstname;

    #[ORM\Column(length: 255)]
    private string $lastname;

    #[ORM\Column(length: 255)]
    private string $contractReference;

    #[ORM\Column(length: 254)]
    private string $receiptEmail;

    #[ORM\Column(nullable: true)]
    private ?bool $orderReceived;

    #[ORM\Column(type: 'date_immutable', nullable: true)]
    private ?\DateTimeImmutable $receivedAt;

    #[ORM\Column(length: 64, nullable: true)]
    private ?string $reasonCode;

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

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

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

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

    #[ORM\Column(length: 45, nullable: true)]
    private ?string $ipAddress;

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

    #[ORM\Column(length: 10)]
    private string $locale;

    public function __construct(
        Cart $cart,
        string $firstname,
        string $lastname,
        string $contractReference,
        string $receiptEmail,
        bool $orderReceived,
        string $locale,
        ?\DateTimeImmutable $receivedAt = null,
        ?string $ipAddress = null,
        ?string $userAgent = null,
        ?\DateTimeImmutable $submittedAt = null,
        ?string $reasonCode = null,
        ?string $comment = null,
    ) {
        if (null !== $reasonCode && !\in_array($reasonCode, self::REASON_CODES, true)) {
            throw new \InvalidArgumentException(sprintf('Unknown withdrawal reason code "%s".', $reasonCode));
        }

        $comment = null !== $comment ? mb_trim($comment) : null;
        if (null !== $comment && mb_strlen($comment) > self::COMMENT_MAX_LENGTH) {
            throw new \InvalidArgumentException(sprintf('Withdrawal comment cannot exceed %d characters.', self::COMMENT_MAX_LENGTH));
        }

        $this->id = Uuid::uuid4();
        $this->cart = $cart;
        $this->firstname = mb_trim($firstname);
        $this->lastname = mb_trim($lastname);
        $this->contractReference = mb_trim($contractReference);
        $this->receiptEmail = mb_strtolower(mb_trim($receiptEmail));
        $this->orderReceived = $orderReceived;
        $this->receivedAt = $orderReceived ? $receivedAt : null;
        $this->reasonCode = $reasonCode;
        $this->comment = '' !== $comment ? $comment : null;
        $this->locale = $locale;
        $this->ipAddress = $ipAddress;
        $this->userAgent = $userAgent;
        $this->submittedAt = $submittedAt ?? new \DateTimeImmutable();

        $cart->setWithdrawalRequest($this);
    }

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

    public function getCart(): Cart
    {
        return $this->cart;
    }

    public function getFirstname(): string
    {
        return $this->firstname;
    }

    public function getLastname(): string
    {
        return $this->lastname;
    }

    public function getContractReference(): string
    {
        return $this->contractReference;
    }

    public function getReceiptEmail(): string
    {
        return $this->receiptEmail;
    }

    public function isOrderReceived(): ?bool
    {
        return $this->orderReceived;
    }

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

    public function getReasonCode(): ?string
    {
        return $this->reasonCode;
    }

    public function getComment(): ?string
    {
        return $this->comment;
    }

    public function getSubmittedAt(): \DateTimeImmutable
    {
        return $this->submittedAt;
    }

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

    public function markAcknowledged(?\DateTimeImmutable $acknowledgedAt = null): void
    {
        $this->acknowledgedAt = $acknowledgedAt ?? new \DateTimeImmutable();
    }

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

    public function markProcessed(?\DateTimeImmutable $processedAt = null): void
    {
        $this->processedAt = $processedAt ?? new \DateTimeImmutable();
    }

    public function getIpAddress(): ?string
    {
        return $this->ipAddress;
    }

    public function getUserAgent(): ?string
    {
        return $this->userAgent;
    }

    public function getLocale(): string
    {
        return $this->locale;
    }
}
