<?php
declare(strict_types=1);

namespace App\Modules\Shipments;

use App\Modules\Settings\PolkurierApiClient;
use App\Modules\Settings\PolkurierIntegrationRepository;
use Throwable;

/**
 * polkurier.pl Tracking service (Phase 128).
 *
 * Cron pinguje API polkurier po status zamowienia (apimetod=get_status) i zwraca dane do
 * `ShipmentTrackingHandler`, ktory zapisuje znormalizowany status do `shipment_packages.delivery_status`
 * przez `delivery_status_mappings(provider='polkurier')`. Wpisy mappings sa seedowane w migracji Phase 128
 * po obserwacji realnych statusow z live testu na #114/#115.
 */
final class PolkurierTrackingService implements ShipmentTrackingInterface
{
    public function __construct(
        private readonly PolkurierApiClient $apiClient,
        private readonly PolkurierIntegrationRepository $integrationRepository,
        private readonly DeliveryStatusMappingRepository $mappingRepository
    ) {
    }

    public function supports(string $provider): bool
    {
        return strtolower(trim($provider)) === 'polkurier';
    }

    /**
     * @param array<string, mixed> $package
     * @return array{status: string, status_raw: string, description: string}|null
     */
    public function getDeliveryStatus(array $package): ?array
    {
        $orderno = trim((string) ($package['shipment_id'] ?? $package['command_id'] ?? ''));
        if ($orderno === '') {
            return null;
        }

        $credentials = $this->resolveCredentials();
        if ($credentials === null) {
            return null;
        }

        try {
            $response = $this->apiClient->getStatus($credentials['login'], $credentials['api_token'], $orderno);
        } catch (Throwable) {
            return null;
        }

        $rawStatus = $this->extractRawStatus($response);
        $statusName = trim((string) (
            $response['status']
            ?? $response['status_name']
            ?? $response['statusname']
            ?? $rawStatus
        ));

        if ($rawStatus === '') {
            return null;
        }

        $normalized = $this->normalizeStatus($rawStatus);

        return [
            'status' => $normalized,
            'status_raw' => $rawStatus,
            'description' => $statusName !== '' ? $statusName : $rawStatus,
        ];
    }

    /**
     * @param array<string, mixed>|mixed $response
     */
    private function extractRawStatus(mixed $response): string
    {
        if (!is_array($response)) {
            return '';
        }

        // Polkurier potrafi zwracac liste statusow (per orderno z get_label-style query)
        if (isset($response[0]) && is_array($response[0])) {
            $response = $response[0];
        }

        $candidate = trim((string) (
            $response['statuscode']
            ?? $response['status_code']
            ?? $response['statusCode']
            ?? $response['status']
            ?? ''
        ));
        return $candidate;
    }

    private function normalizeStatus(string $rawStatus): string
    {
        try {
            $overrides = $this->mappingRepository->getAllOverrides();
        } catch (Throwable) {
            $overrides = [];
        }
        return DeliveryStatus::normalizeWithOverrides('polkurier', $rawStatus, $overrides);
    }

    /**
     * @return array{login: string, api_token: string, default_label_format: string, integration_id: int}|null
     */
    private function resolveCredentials(): ?array
    {
        try {
            return $this->integrationRepository->getCredentials();
        } catch (Throwable) {
            return null;
        }
    }
}
