<?php

declare(strict_types=1);

namespace Gls\GlsPoland\Consignment\Builder;

use Gls\GlsPoland\AdePlus\Common\Services;
use Gls\GlsPoland\AdePlus\Consignment\Consignment;
use Gls\GlsPoland\Consignment\DTO\AddressDetails;
use Gls\GlsPoland\Consignment\DTO\Parcel;
use Gls\GlsPoland\Consignment\DTO\ServiceDetails;

abstract class AbstractConsignmentBuilder implements ConsignmentBuilderInterface
{
    /**
     * @var string|null
     */
    protected $references;

    /**
     * @var string|null
     */
    protected $notes;

    /**
     * @var AddressDetails|null
     */
    protected $senderDetails;

    /**
     * @var AddressDetails|null
     */
    protected $recipientDetails;

    /**
     * @var ServiceDetails|null
     */
    protected $serviceDetails;

    /**
     * @var Parcel[]
     */
    protected $parcels = [];

    /**
     * @var \DateTimeImmutable|null
     */
    protected $shippingDate;

    public function setReferences(?string $references): ConsignmentBuilderInterface
    {
        $this->references = $references;

        return $this;
    }

    public function setNotes(?string $notes): ConsignmentBuilderInterface
    {
        $this->notes = $notes;

        return $this;
    }

    public function setSenderDetails(?AddressDetails $senderDetails): ConsignmentBuilderInterface
    {
        $this->senderDetails = $senderDetails;

        return $this;
    }

    public function setRecipientDetails(?AddressDetails $recipientDetails): ConsignmentBuilderInterface
    {
        $this->recipientDetails = $recipientDetails;

        return $this;
    }

    public function setServiceDetails(?ServiceDetails $serviceDetails): ConsignmentBuilderInterface
    {
        $this->serviceDetails = $serviceDetails;

        return $this;
    }

    public function setParcels(Parcel ...$parcels): ConsignmentBuilderInterface
    {
        $this->parcels = $parcels;

        return $this;
    }

    public function setShippingDate(?\DateTimeImmutable $shippingDate): ConsignmentBuilderInterface
    {
        $this->shippingDate = $shippingDate;

        return $this;
    }

    public function build(): Consignment
    {
        $consignment = (new Consignment())
            ->withNotes($this->notes)
            ->withReferences($this->references)
            ->withServices($this->buildServices())
            ->withShippingDate($this->shippingDate);

        if (null === $this->recipientDetails) {
            return $consignment;
        }

        return $consignment
            ->withRecipientName1($this->recipientDetails->getName1())
            ->withRecipientName2($this->recipientDetails->getName2())
            ->withRecipientName3($this->recipientDetails->getName3())
            ->withRecipientCountryIsoCode($this->recipientDetails->getCountryIsoCode())
            ->withRecipientCity($this->recipientDetails->getCity())
            ->withRecipientZipCode($this->normalizeRecipientZipCode($this->recipientDetails))
            ->withRecipientStreet($this->recipientDetails->getStreet())
            ->withRecipientContactInfo($this->recipientDetails->getEmail())
            ->withRecipientPhone($this->recipientDetails->getPhone());
    }
    private function normalizeRecipientZipCode(AddressDetails $recipientDetails): string
    {
        $zipCode = trim($recipientDetails->getZipCode());
        $countryIsoCode = strtoupper($recipientDetails->getCountryIsoCode());

        if ('PL' !== $countryIsoCode) {
            return $zipCode;
        }

        $digits = preg_replace('/\D+/', '', $zipCode) ?? '';
        if (5 === strlen($digits)) {
            return $digits;
        }

        return $zipCode;
    }
    protected function buildServices(): Services
    {
        return new Services();
    }
}
