<?php

declare(strict_types=1);

namespace App\Modules\Email;

use App\Modules\Shipments\DeliveryStatus;
use App\Modules\Shipments\ShipmentPackageRepository;

final class VariableResolver
{
    public function __construct(
        private readonly ShipmentPackageRepository $shipmentPackageRepository
    ) {
    }

    /**
     * @param array<string, mixed> $order
     * @param array<int, array<string, mixed>> $addresses
     * @param array<string, mixed> $companySettings
     * @return array<string, string>
     */
    public function buildVariableMap(array $order, array $addresses, array $companySettings): array
    {
        $customerAddress = $this->findAddress($addresses, 'customer');
        $deliveryAddress = $this->findAddress($addresses, 'delivery') ?? $customerAddress;

        $buyerName = (string) ($customerAddress['name'] ?? '');
        $buyerEmail = (string) ($customerAddress['email'] ?? '');
        $buyerPhone = (string) ($customerAddress['phone'] ?? '');

        $totalFormatted = number_format((float) ($order['total_with_tax'] ?? 0), 2, ',', ' ');
        $orderedAt = (string) ($order['ordered_at'] ?? '');
        if ($orderedAt !== '' && ($ts = strtotime($orderedAt)) !== false) {
            $orderedAt = date('Y-m-d', $ts);
        }

        $baseVariables = [
            'zamowienie.numer' => (string) ($order['internal_order_number'] ?? $order['id'] ?? ''),
            'zamowienie.numer_zewnetrzny' => (string) ($order['external_order_id'] ?? $order['source_order_id'] ?? ''),
            'zamowienie.zrodlo' => ucfirst((string) ($order['source'] ?? '')),
            'zamowienie.kwota' => $totalFormatted,
            'zamowienie.waluta' => (string) ($order['currency'] ?? 'PLN'),
            'zamowienie.data' => $orderedAt,
            'kupujacy.imie_nazwisko' => $buyerName,
            'kupujacy.email' => $buyerEmail,
            'kupujacy.telefon' => $buyerPhone,
            'kupujacy.login' => (string) ($order['customer_login'] ?? ''),
            'adres.ulica' => trim(($deliveryAddress['street_name'] ?? '') . ' ' . ($deliveryAddress['street_number'] ?? '')),
            'adres.miasto' => (string) ($deliveryAddress['city'] ?? ''),
            'adres.kod_pocztowy' => (string) ($deliveryAddress['zip_code'] ?? ''),
            'adres.kraj' => (string) ($deliveryAddress['country'] ?? ''),
            'firma.nazwa' => (string) ($companySettings['company_name'] ?? ''),
            'firma.nip' => (string) ($companySettings['tax_number'] ?? ''),
        ];

        return $baseVariables + $this->resolveShipmentVariables($order);
    }

    public function resolve(string $template, array $variableMap): string
    {
        return preg_replace_callback(
            '/\{\{([a-z_]+\.[a-z_]+)\}\}/',
            static fn(array $m): string => $variableMap[$m[1]] ?? '',
            $template
        ) ?? $template;
    }

    /**
     * @param array<int, array<string, mixed>> $addresses
     * @return array<string, mixed>|null
     */
    private function findAddress(array $addresses, string $type): ?array
    {
        foreach ($addresses as $addr) {
            if (($addr['address_type'] ?? '') === $type) {
                return $addr;
            }
        }

        return null;
    }

    /**
     * @param array<string, mixed> $order
     * @return array<string, string>
     */
    private function resolveShipmentVariables(array $order): array
    {
        $orderId = (int) ($order['id'] ?? 0);
        if ($orderId <= 0) {
            return [
                'przesylka.numer' => '',
                'przesylka.link_sledzenia' => '',
            ];
        }

        $latestPackage = $this->shipmentPackageRepository->findLatestByOrderId($orderId);
        if (!is_array($latestPackage)) {
            return [
                'przesylka.numer' => '',
                'przesylka.link_sledzenia' => '',
            ];
        }

        $trackingNumber = trim((string) ($latestPackage['tracking_number'] ?? ''));
        $provider = trim((string) ($latestPackage['provider'] ?? ''));
        $carrierId = trim((string) ($latestPackage['carrier_id'] ?? ''));
        $trackingUrl = DeliveryStatus::trackingUrl($provider, $trackingNumber, $carrierId) ?? '';

        return [
            'przesylka.numer' => $trackingNumber,
            'przesylka.link_sledzenia' => $trackingUrl,
        ];
    }
}
