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

use InPost\International\Api\Tracking\Model\Event;
use InPost\International\Api\Tracking\Model\Location;
use InPost\International\Api\Tracking\Model\Parcel;
use InPost\International\Api\Tracking\TrackingEvent;
use InPost\International\Country;
use InPost\International\Shipment\View\Model\TrackingDetailsView;
use InPost\International\Shipment\View\Model\TrackingEventView;
use Psr\Clock\ClockInterface;
use Symfony\Contracts\Translation\TranslatorInterface;

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

final class TrackingDetailsViewFactory
{
    /**
     * @var TranslatorInterface
     */
    private $translator;

    /**
     * @var \Context
     */
    private $context;

    /**
     * @var ClockInterface
     */
    private $clock;

    /**
     * @var \DateTimeZone|null
     */
    private $timezone;

    public function __construct(TranslatorInterface $translator, \Context $context, ClockInterface $clock)
    {
        $this->translator = $translator;
        $this->context = $context;
        $this->clock = $clock;
    }

    public function create(Parcel $parcel): TrackingDetailsView
    {
        $this->timezone = $this->clock->now()->getTimezone() ?: null;

        $destination = $this->formatDestinationAddress($parcel->getDestination());
        $events = array_map([$this, 'createEventView'], $parcel->getEvents());

        return new TrackingDetailsView($parcel->getTrackingNumber(), $destination, $events);
    }

    private function formatDestinationAddress(Location $destination): string
    {
        $parts = [];

        if ($name = $destination->getName()) {
            $parts[] = $name;
        }

        if ($address = $destination->getAddress()) {
            $parts[] = $address;
        }

        if ($city = $destination->getCity()) {
            $country = $this->getCountry($destination);
            $parts[] = trim(sprintf('%s %s, %s', $destination->getPostalCode(), $city, $country));
        }

        return implode("\n", $parts);
    }

    private function createEventView(Event $event): TrackingEventView
    {
        $timestamp = $event->getTimestamp();
        if (null !== $this->timezone) {
            $timestamp = $timestamp->setTimezone($this->timezone);
        }
        $date = $timestamp->format($this->context->language->date_format_full);

        $title = (new TrackingEvent($event->getCode()))->trans($this->translator);

        return new TrackingEventView($title, $date);
    }

    private function getCountry(Location $destination): ?string
    {
        if (null === $isoCode = $destination->getCountry()) {
            return null;
        }

        if (null === $country = Country::tryFrom($isoCode)) {
            return $isoCode;
        }

        return $country->trans($this->translator);
    }
}
