<?php

declare(strict_types=1);

namespace Gls\GlsPoland\PrestaShop\Order;

use Gls\GlsPoland\Consignment\DTO\AddressDetails;
use Gls\GlsPoland\PrestaShop\ObjectModel\Repository\AddressRepository;
use Gls\GlsPoland\PrestaShop\ObjectModel\Repository\CountryRepository;
use Gls\GlsPoland\PrestaShop\ObjectModel\Repository\CustomerRepository;

final class AddressDetailsFactory implements AddressDetailsFactoryInterface
{
    private $addressRepository;
    private $customerRepository;
    private $countryRepository;

    public function __construct(AddressRepository $addressRepository, CustomerRepository $customerRepository, CountryRepository $countryRepository)
    {
        $this->addressRepository = $addressRepository;
        $this->customerRepository = $customerRepository;
        $this->countryRepository = $countryRepository;
    }

    public function create(int $addressId): AddressDetails
    {
        if (null === $address = $this->addressRepository->find($addressId)) {
            return new AddressDetails();
        }

        $customer = $this->customerRepository->find((int) $address->id_customer);
        $country = $this->countryRepository->find((int) $address->id_country);
        $countryIsoCode = $country->iso_code ?? null;

        return (new AddressDetails())
            ->setName1($address->lastname)
            ->setName2($address->firstname)
            ->setName3($address->company)
            ->setStreet($this->getStreetAddress($address))
            ->setCity($address->city)
            ->setZipCode($this->normalizeZipCode($address->postcode, $countryIsoCode))
            ->setCountryIsoCode($countryIsoCode)
            ->setPhone($address->phone_mobile ?: $address->phone)
            ->setEmail($customer->email ?? null);
    }

    private function getStreetAddress(\Address $address): ?string
    {
        if ('' === $address2 = (string) $address->address2) {
            return $address->address1;
        }

        return sprintf('%s %s', $address->address1, $address2);
    }

    private function normalizeZipCode(?string $zipCode, ?string $countryIsoCode): ?string
    {
        if (null === $zipCode) {
            return null;
        }

        $zipCode = trim($zipCode);
        if ('' === $zipCode) {
            return $zipCode;
        }

        $zipCode = preg_replace('/\s+/', '', $zipCode) ?? $zipCode;

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

        $digits = preg_replace('/\D+/', '', $zipCode) ?? '';
        if (5 === strlen($digits)) {
            return sprintf('%s-%s', substr($digits, 0, 2), substr($digits, 2, 3));
        }

        return strtoupper($zipCode);
    }
}
