<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Models\Order;
use App\Models\Shipment;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

class EkartWebhookController extends Controller
{
    public function handle(Request $request): JsonResponse
    {
        $payload = $request->all();
        $trackingId = (string) ($payload['id'] ?? '');
        $status = (string) ($payload['status'] ?? '');
        $orderNumber = (string) ($payload['orderNumber'] ?? '');

        if ($trackingId === '' || $status === '') {
            Log::warning('Ekart webhook: invalid payload', [
                'tracking_id' => $trackingId,
                'status' => $status,
                'payload' => $payload,
            ]);

            return response()->json([
                'status' => 'error',
                'message' => 'Missing required fields: id, status',
            ], 422);
        }

        try {
            DB::beginTransaction();

            $shipment = $this->resolveShipment($trackingId, $orderNumber);
            if (!$shipment) {
                Log::warning('Ekart webhook: shipment not found', [
                    'tracking_id' => $trackingId,
                    'order_number' => $orderNumber,
                ]);

                DB::commit();

                return response()->json([
                    'status' => 'accepted',
                    'message' => 'Shipment not found',
                ], 202);
            }

            $shipmentUpdate = [
                'raw_response' => $this->appendRawResponse($shipment->raw_response, $payload),
                'metadata' => $this->mergeMetadata($shipment->metadata, $payload),
            ];

            $shipmentStatus = $this->mapShipmentStatus($status);
            if ($shipmentStatus) {
                $shipmentUpdate['status'] = $shipmentStatus;
            }

            $shipment->update($shipmentUpdate);

            $order = $shipment->order;
            $mappedOrderStatus = $this->mapOrderStatus($status);
            if ($order && $mappedOrderStatus && $this->canMoveOrderToStatus($order, $mappedOrderStatus)) {
                $oldStatus = $order->status;
                $order->update(['status' => $mappedOrderStatus]);

                Log::info('Ekart webhook: order status updated', [
                    'order_id' => $order->id,
                    'from_status' => $oldStatus,
                    'to_status' => $mappedOrderStatus,
                    'tracking_id' => $trackingId,
                    'ekart_status' => $status,
                ]);
            }

            DB::commit();

            return response()->json([
                'status' => 'ok',
                'tracking_id' => $trackingId,
            ]);
        } catch (\Throwable $e) {
            DB::rollBack();

            Log::error('Ekart webhook: processing failed', [
                'tracking_id' => $trackingId,
                'status' => $status,
                'error' => $e->getMessage(),
            ]);

            return response()->json([
                'status' => 'error',
                'message' => 'Webhook processing failed',
            ], 500);
        }
    }

    protected function resolveShipment(string $trackingId, ?string $orderNumber = null): ?Shipment
    {
        $shipment = Shipment::query()
            ->where('tracking_id', $trackingId)
            ->latest('id')
            ->first();

        if ($shipment) {
            return $shipment;
        }

        $orderId = $this->extractOrderId($orderNumber ?? '');
        if (!$orderId) {
            return null;
        }

        $order = Order::find($orderId);
        if (!$order) {
            return null;
        }

        return $order->shipments()
            ->latest('id')
            ->first();
    }

    protected function extractOrderId(string $orderNumber): ?int
    {
        if ($orderNumber === '') {
            return null;
        }

        if (preg_match('/(\d+)/', $orderNumber, $matches) !== 1) {
            return null;
        }

        $id = (int) ($matches[1] ?? 0);

        return $id > 0 ? $id : null;
    }

    protected function appendRawResponse(?array $existing, array $payload): array
    {
        $raw = is_array($existing) ? $existing : [];
        $events = $raw['webhook_events'] ?? [];

        if (!is_array($events)) {
            $events = [];
        }

        $events[] = [
            'received_at' => now()->toIso8601String(),
            'payload' => $payload,
        ];

        $raw['latest_webhook'] = $payload;
        $raw['webhook_events'] = array_slice($events, -30);

        return $raw;
    }

    protected function mergeMetadata(?array $existing, array $payload): array
    {
        $metadata = is_array($existing) ? $existing : [];
        $metadata['last_webhook_at'] = now()->toIso8601String();
        $metadata['last_ekart_status'] = $payload['status'] ?? null;
        $metadata['last_ekart_description'] = $payload['desc'] ?? null;
        $metadata['last_ekart_location'] = $payload['location'] ?? null;
        $metadata['last_ekart_attempts'] = $payload['attempts'] ?? null;
        $metadata['last_ekart_event_time'] = $payload['ctime'] ?? null;
        $metadata['last_ekart_edd'] = $payload['edd'] ?? null;
        $metadata['ekart_wbn'] = $payload['wbn'] ?? ($metadata['ekart_wbn'] ?? null);

        return $metadata;
    }

    protected function mapShipmentStatus(string $ekartStatus): ?string
    {
        return strtolower(trim($ekartStatus)) === 'delivered'
            ? Shipment::STATUS_DELIVERED
            : null;
    }

    protected function mapOrderStatus(string $ekartStatus): ?string
    {
        return match (strtolower(trim($ekartStatus))) {
            'delivered' => Order::STATUS_DELIVERED,
            'in transit', 'out for delivery', 'picked up' => Order::STATUS_SHIPPED,
            'order placed' => Order::STATUS_AWAITING_PICKUP,
            'cancelled', 'seller cancelled' => Order::STATUS_CANCELLED,
            'rto delivered' => Order::STATUS_RETURNED,
            default => null,
        };
    }

    protected function canMoveOrderToStatus(Order $order, string $nextStatus): bool
    {
        if ($order->status === $nextStatus) {
            return false;
        }

        if ($order->status === Order::STATUS_DELIVERED && $nextStatus !== Order::STATUS_DELIVERED) {
            return false;
        }

        if (in_array($order->status, [Order::STATUS_CANCELLED, Order::STATUS_RETURNED], true) && $order->status !== $nextStatus) {
            return false;
        }

        if ($nextStatus === Order::STATUS_AWAITING_PICKUP) {
            return in_array($order->status, [
                Order::STATUS_PLACED,
                Order::STATUS_CONFIRMED,
                Order::STATUS_PACKED,
                Order::STATUS_AWAITING_PICKUP,
            ], true);
        }

        if ($nextStatus === Order::STATUS_SHIPPED) {
            return !in_array($order->status, [
                Order::STATUS_AWAITING_PAYMENT,
                Order::STATUS_CANCELLED,
                Order::STATUS_RETURNED,
                Order::STATUS_DELIVERED,
            ], true);
        }

        return true;
    }
}
