<?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\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use InPost\International\PickupAddress\Exception\PickupAddressException;
use InPost\International\PickupAddress\PickupAddressRepository;

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

/**
 * @final
 *
 * @ORM\Entity(repositoryClass=PickupAddressRepository::class)
 * @ORM\Table(name=PickupAddress::TABLE_NAME)
 */
class PickupAddress implements \Stringable
{
    /**
     * @internal
     */
    public const TABLE_NAME = _DB_PREFIX_ . 'inpost_intl_pickup_address';

    /**
     * @var int|null
     *
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(type="string")
     */
    private $name;

    /**
     * @var ContactPerson
     *
     * @ORM\Embedded(class=ContactPerson::class, columnPrefix=false)
     */
    private $contactPerson;

    /**
     * @var Address
     *
     * @ORM\Embedded(class=Address::class, columnPrefix=false)
     */
    private $address;

    /**
     * @var bool
     *
     * @ORM\Column(type="boolean", name="is_default")
     */
    private $default = false;

    /**
     * @var bool
     *
     * @ORM\Column(type="boolean", name="is_deleted")
     */
    private $deleted = false;

    /**
     * @var Collection<int, Shipment>
     *
     * @ORM\OneToMany(targetEntity=Shipment::class, mappedBy="pickupAddress", fetch="EXTRA_LAZY")
     */
    private $shipments;

    /**
     * @var Collection<int, PickupOrder>
     *
     * @ORM\OneToMany(targetEntity=PickupOrder::class, mappedBy="pickupAddress", fetch="EXTRA_LAZY")
     */
    private $pickupOrders;

    public function __construct(string $name, ContactPerson $contactPerson, Address $address)
    {
        $this->setName($name);
        $this->contactPerson = $contactPerson;
        $this->address = $address;
        $this->shipments = new ArrayCollection();
        $this->pickupOrders = new ArrayCollection();
    }

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

    public function getName(): string
    {
        return $this->name;
    }

    public function setName(string $name): void
    {
        if ('' === $name = trim($name)) {
            throw new PickupAddressException('Pickup address name cannot be empty.');
        }

        $this->name = $name;
    }

    public function getContactPerson(): ContactPerson
    {
        return $this->contactPerson;
    }

    public function setContactPerson(ContactPerson $contactPerson): void
    {
        if ($this->wasUsed()) {
            throw new PickupAddressException('Cannot modify a pickup address that has been used.');
        }

        $this->contactPerson = $contactPerson;
    }

    public function getAddress(): Address
    {
        return $this->address;
    }

    public function setAddress(Address $address): void
    {
        if ($this->wasUsed()) {
            throw new PickupAddressException('Cannot modify a pickup address that has been used.');
        }

        $this->address = $address;
    }

    public function isDefault(): bool
    {
        return $this->default;
    }

    public function setDefault(bool $default): void
    {
        if ($this->deleted) {
            throw new PickupAddressException('Deleted pickup address cannot be set as default.');
        }

        $this->default = $default;
    }

    public function isDeleted(): bool
    {
        return $this->deleted;
    }

    public function delete(): void
    {
        if (!$this->wasUsed()) {
            throw new PickupAddressException('Cannot mark an unused pickup address as deleted.');
        }

        $this->deleted = true;
        $this->default = false;
    }

    public function wasUsed(): bool
    {
        if (!isset($this->id)) {
            return false;
        }

        if ($this->deleted) {
            return true;
        }

        if ($this->shipments->count() > 0) {
            return true;
        }

        return $this->pickupOrders->count() > 0;
    }

    public function __toString(): string
    {
        return $this->name;
    }

    public function __clone()
    {
        if (!isset($this->id)) {
            return;
        }

        $this->deleted = false;
        $this->default = false;
    }
}
