<?php
/**
 * Copyright since 2025 InPost S.A.
 *
 * For the full license information, please view the LICENSE file bundled with the module.
 *
 * @author InPost S.A.
 * @copyright since 2025 InPost S.A.
 * @license MIT
 */

declare(strict_types=1);

namespace InPost\International\Shipment\Message;

use InPost\International\Carrier\CarrierType;
use InPost\International\Common\DTO\Address;
use InPost\International\Common\DTO\ContactDetails;
use InPost\International\Common\DTO\Reference;
use InPost\International\Entity\PickupAddress;
use InPost\International\Shipment\DTO\Parcel;
use InPost\International\Shipment\ShippingMethod;
use Symfony\Component\Validator\Constraints as Assert;

if (!defined('_PS_VERSION_')) {
    exit;
}

final class CreateShipmentCommand
{
    /**
     * @var int|null
     *
     * @Assert\NotNull
     * @Assert\GreaterThan(0)
     */
    private $orderId;

    /**
     * @var CarrierType|null
     *
     * @Assert\NotNull
     */
    private $service;

    /**
     * @var ContactDetails|null
     *
     * @Assert\NotNull
     * @Assert\Valid
     */
    private $recipient;

    /**
     * @var Address|null
     *
     * @Assert\Valid
     */
    private $destinationAddress;

    /**
     * @var string|null
     */
    private $destinationPointId;

    /**
     * @var Parcel|null
     *
     * @Assert\NotNull
     * @Assert\Valid
     */
    private $parcel;

    /**
     * @var ShippingMethod|null
     *
     * @Assert\NotNull
     */
    private $shippingMethod;

    /**
     * @var PickupAddress|null
     */
    private $pickupAddress;

    /**
     * @var float|null
     *
     * @Assert\Range(min=0, max=5000)
     */
    private $insurance;

    /**
     * @var Reference[]
     *
     * @Assert\Valid
     */
    private $references = [];

    public function __construct()
    {
        $this->service = CarrierType::PointDelivery();
        $this->shippingMethod = ShippingMethod::FromPoint();
    }

    public function getOrderId(): ?int
    {
        return $this->orderId ?? null;
    }

    public function setOrderId(int $orderId): self
    {
        $this->orderId = $orderId;

        return $this;
    }

    public function getService(): ?CarrierType
    {
        return $this->service;
    }

    public function setService(?CarrierType $service): self
    {
        $this->service = $service;

        return $this;
    }

    public function getRecipient(): ?ContactDetails
    {
        return $this->recipient;
    }

    public function setRecipient(?ContactDetails $recipient): self
    {
        $this->recipient = $recipient;

        return $this;
    }

    public function getDestinationAddress(): ?Address
    {
        return $this->destinationAddress;
    }

    public function setDestinationAddress(?Address $address): self
    {
        $this->destinationAddress = $address;

        return $this;
    }

    public function getDestinationPointId(): ?string
    {
        return $this->destinationPointId;
    }

    public function setDestinationPointId(?string $destinationPointId): self
    {
        $this->destinationPointId = $destinationPointId;

        return $this;
    }

    /**
     * @Assert\IsTrue(message="A valid destination is required.")
     */
    public function hasDestination(): bool
    {
        switch ($this->service) {
            case CarrierType::Courier():
                return null !== $this->destinationAddress;
            case CarrierType::PointDelivery():
                return null !== $this->destinationPointId;
            default:
                return true;
        }
    }

    public function getParcel(): ?Parcel
    {
        return $this->parcel;
    }

    public function setParcel(?Parcel $parcel): self
    {
        $this->parcel = $parcel;

        return $this;
    }

    public function getShippingMethod(): ?ShippingMethod
    {
        return $this->shippingMethod;
    }

    public function setShippingMethod(?ShippingMethod $shippingMethod): self
    {
        $this->shippingMethod = $shippingMethod;

        return $this;
    }

    public function getPickupAddress(): ?PickupAddress
    {
        return $this->pickupAddress;
    }

    public function setPickupAddress(?PickupAddress $address): self
    {
        $this->pickupAddress = $address;

        return $this;
    }

    /**
     * @Assert\IsTrue(message="A pickup address is required.")
     */
    public function hasAddressForCourierPickup(): bool
    {
        if (ShippingMethod::CourierPickup() !== $this->shippingMethod) {
            return true;
        }

        return null !== $this->pickupAddress;
    }

    public function getInsurance(): ?float
    {
        return $this->insurance;
    }

    public function setInsurance(?float $insurance): self
    {
        $this->insurance = $insurance;

        return $this;
    }

    /**
     * @return Reference[]
     */
    public function getReferences(): array
    {
        return $this->references;
    }

    public function addReference(Reference $reference): self
    {
        $this->references[] = $reference;

        return $this;
    }

    public function removeReference(Reference $reference): self
    {
        if ($key = array_search($reference, $this->references, true)) {
            unset($this->references[$key]);
        }

        return $this;
    }
}
