<?php

namespace App\Services\Courier;

class CourierEventMetadataExtractor
{
    public function extract(array $payload, ?string $fallbackStatus = null): array
    {
        $statusCode = $this->firstFilled($payload, [
            'status_code',
            'delivery_status',
            'status',
            'data.status_code',
            'data.delivery_status',
            'data.status',
            'parcel.status',
        ]) ?? $this->clean($fallbackStatus);

        $riderId = $this->firstFilled($payload, [
            'rider.id',
            'rider.rider_id',
            'delivery_man.id',
            'delivery_man.delivery_man_id',
            'deliveryman.id',
            'delivery_boy.id',
            'data.rider.id',
            'data.delivery_man.id',
            'rider_id',
            'delivery_man_id',
            'deliveryman_id',
            'delivery_boy_id',
        ]);

        $riderName = $this->firstFilled($payload, [
            'rider.name',
            'rider.full_name',
            'delivery_man.name',
            'delivery_man.full_name',
            'deliveryman.name',
            'delivery_boy.name',
            'data.rider.name',
            'data.delivery_man.name',
            'rider_name',
            'delivery_man_name',
            'deliveryman_name',
            'delivery_boy_name',
        ]);

        $riderPhone = $this->normalizePhone($this->firstFilled($payload, [
            'rider.phone',
            'rider.mobile',
            'rider.phone_number',
            'delivery_man.phone',
            'delivery_man.mobile',
            'delivery_man.phone_number',
            'deliveryman.phone',
            'deliveryman.mobile',
            'delivery_boy.phone',
            'delivery_boy.mobile',
            'data.rider.phone',
            'data.rider.mobile',
            'data.delivery_man.phone',
            'data.delivery_man.mobile',
            'rider_phone',
            'rider_mobile',
            'delivery_man_phone',
            'delivery_man_mobile',
            'deliveryman_phone',
            'deliveryman_mobile',
            'delivery_boy_phone',
            'delivery_boy_mobile',
        ]));

        return [
            'status_code' => $statusCode,
            'status_text' => $this->firstFilled($payload, [
                'status_text',
                'tracking_message',
                'message',
                'data.status_text',
                'data.tracking_message',
            ]) ?? $statusCode,
            'rider_id' => $riderId,
            'rider_name' => $riderName,
            'rider_phone' => $riderPhone,
            'has_rider' => filled($riderId) || filled($riderName) || filled($riderPhone),
            'event_reference' => $this->firstFilled($payload, [
                'event_id',
                'webhook_id',
                'notification_id',
                'tracking_event_id',
                'reference_id',
                'reference',
                'data.event_id',
                'data.reference_id',
            ]),
            'event_time' => $this->firstFilled($payload, [
                'event_time',
                'occurred_at',
                'assigned_at',
                'out_for_delivery_at',
                'status_updated_at',
                'updated_at',
                'data.event_time',
                'data.updated_at',
            ]),
        ];
    }

    private function firstFilled(array $payload, array $paths): ?string
    {
        foreach ($paths as $path) {
            $value = $this->clean(data_get($payload, $path));
            if (filled($value)) {
                return $value;
            }
        }

        return null;
    }

    private function clean(mixed $value): ?string
    {
        if (is_array($value) || is_object($value) || is_bool($value) || $value === null) {
            return null;
        }

        $value = trim((string) $value);

        return $value === '' ? null : mb_substr($value, 0, 255);
    }

    private function normalizePhone(?string $phone): ?string
    {
        if (! filled($phone)) {
            return null;
        }

        $phone = preg_replace('/(?!^\+)\D+/', '', trim($phone));

        return filled($phone) ? mb_substr($phone, 0, 50) : null;
    }
}
