<?php

namespace App\Services\Shipment;

use App\Models\Order;

class ShipmentOrderStatusMapper
{
    /**
     * Normalized shipment status => order status constant.
     *
     * @var array<string, string>
     */
    private const MAPPING = [
        // awaiting_pickup
        'created' => Order::STATUS_AWAITING_PICKUP,
        'awaiting pickup' => Order::STATUS_AWAITING_PICKUP,
        'manifested' => Order::STATUS_AWAITING_PICKUP,
        'pickup scheduled' => Order::STATUS_AWAITING_PICKUP,
        'not picked' => Order::STATUS_AWAITING_PICKUP,
        'pickup rescheduled' => Order::STATUS_AWAITING_PICKUP,
        'order placed' => Order::STATUS_AWAITING_PICKUP,
        'pickup pending' => Order::STATUS_AWAITING_PICKUP,
        'shipment created' => Order::STATUS_AWAITING_PICKUP,
        'booked' => Order::STATUS_AWAITING_PICKUP,
        'data received' => Order::STATUS_AWAITING_PICKUP,

        // shipped
        'picked up' => Order::STATUS_SHIPPED,
        'dispatched' => Order::STATUS_SHIPPED,
        'in transit' => Order::STATUS_SHIPPED,
        'pending' => Order::STATUS_SHIPPED,
        'arrived at hub' => Order::STATUS_SHIPPED,
        'departed from hub' => Order::STATUS_SHIPPED,
        'bagged' => Order::STATUS_SHIPPED,
        'misroute' => Order::STATUS_SHIPPED,
        'hold' => Order::STATUS_SHIPPED,
        'out for delivery' => Order::STATUS_SHIPPED,
        'out for pickup' => Order::STATUS_SHIPPED,
        'shipment delayed' => Order::STATUS_SHIPPED,
        'reached destination' => Order::STATUS_SHIPPED,
        'in network' => Order::STATUS_SHIPPED,
        'with delivery executive' => Order::STATUS_SHIPPED,
        'in route' => Order::STATUS_SHIPPED,

        // delivery_failed
        'exception' => Order::STATUS_DELIVERY_FAILED,
        'delivery attempted' => Order::STATUS_DELIVERY_FAILED,
        'failed' => Order::STATUS_DELIVERY_FAILED,
        'undelivered' => Order::STATUS_DELIVERY_FAILED,
        'address issue' => Order::STATUS_DELIVERY_FAILED,
        'customer not available' => Order::STATUS_DELIVERY_FAILED,

        // delivered
        'delivered' => Order::STATUS_DELIVERED,

        // returned
        'rto initiated' => Order::STATUS_RETURNED,
        'rto in transit' => Order::STATUS_RETURNED,
        'rto delivered' => Order::STATUS_RETURNED,
        'rto' => Order::STATUS_RETURNED,
        'customer return' => Order::STATUS_RETURNED,
        'rto requested' => Order::STATUS_RETURNED,
        'seller rto requested' => Order::STATUS_RETURNED,
        'rto out for delivery' => Order::STATUS_RETURNED,
        'rto failed' => Order::STATUS_RETURNED,
        'rto shipment delayed' => Order::STATUS_RETURNED,

        // cancelled
        'cancelled' => Order::STATUS_CANCELLED,
        'canceled' => Order::STATUS_CANCELLED,
        'seller cancelled' => Order::STATUS_CANCELLED,
        'pickup cancelled' => Order::STATUS_CANCELLED,
        'not serviceable' => Order::STATUS_CANCELLED,

        // lost
        'lost' => Order::STATUS_LOST,
        'damaged' => Order::STATUS_LOST,
    ];

    /**
     * Priority when aggregating multiple shipments (highest first).
     *
     * @var array<string, int>
     */
    public const STATUS_PRIORITY = [
        Order::STATUS_DELIVERED => 7,
        Order::STATUS_LOST => 6,
        Order::STATUS_RETURNED => 5,
        Order::STATUS_CANCELLED => 4,
        Order::STATUS_DELIVERY_FAILED => 3,
        Order::STATUS_SHIPPED => 2,
        Order::STATUS_AWAITING_PICKUP => 1,
    ];

    public function normalizeStatus(string $status): string
    {
        $normalized = strtolower(trim($status));
        $normalized = str_replace(['_', '-'], ' ', $normalized);
        $normalized = preg_replace('/\s+/', ' ', $normalized) ?? $normalized;

        return $normalized;
    }

    public function toOrderStatus(?string $shipmentStatus): ?string
    {
        if ($shipmentStatus === null || trim($shipmentStatus) === '') {
            return null;
        }

        $key = $this->normalizeStatus($shipmentStatus);

        return self::MAPPING[$key] ?? null;
    }

    /**
     * @return array<int, string> Normalized shipment status keys that map to the given order status.
     */
    public function getShipmentStatusesForOrderStatus(string $orderStatus): array
    {
        $keys = [];

        foreach (self::MAPPING as $normalizedKey => $mappedOrderStatus) {
            if ($mappedOrderStatus === $orderStatus) {
                $keys[] = $normalizedKey;
            }
        }

        return $keys;
    }

    public function isRtoDelivered(?string $shipmentStatus): bool
    {
        if ($shipmentStatus === null || trim($shipmentStatus) === '') {
            return false;
        }

        return $this->normalizeStatus($shipmentStatus) === 'rto delivered';
    }
}
