<?php

namespace App\Console\Commands;

use App\Models\Shipment;
use App\Services\Carriers\CarrierServiceFactory;
use App\Services\Shipment\ShipmentStatusSyncService;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;
use Throwable;

class DelhiveryApiDeliveryStatusSyncing extends Command
{
    protected $signature = 'delhivery:sync-delivery-status';
    protected $description = 'Sync Delhivery shipment tracking and update shipment/order statuses';

    public function __construct(
        private readonly ShipmentStatusSyncService $statusSyncService
    ) {
        parent::__construct();
    }

    public function handle()
    {
        $counters = [
            'processed' => 0,
            'updated' => 0,
            'skipped' => 0,
            'failed' => 0,
            'orders_updated' => 0,
        ];

        try {
            $carrierService = CarrierServiceFactory::make('delhivery');
        } catch (Throwable $e) {
            $this->error('Unable to initialize Delhivery carrier: ' . $e->getMessage());
            Log::error('Delhivery sync bootstrap failed', ['error' => $e->getMessage()]);

            return Command::FAILURE;
        }

        $shipments = Shipment::query()
            ->whereNotNull('tracking_id')
            ->where('status', '!=', Shipment::STATUS_DELIVERED)
            ->whereHas('carrier', function ($query) {
                $query->where('slug', 'delhivery');
            })
            ->get();

        if ($shipments->isEmpty()) {
            $this->info('No pending Delhivery shipments found for syncing.');
            return Command::SUCCESS;
        }

        $shipmentIdsByTracking = $shipments
            ->groupBy('tracking_id')
            ->map(static fn ($group) => $group->pluck('id')->values()->all());

        foreach ($shipmentIdsByTracking as $trackingId => $shipmentIds) {
            $counters['processed']++;

            try {
                $trackingData = $carrierService->track((string) $trackingId);
            } catch (Throwable $e) {
                $counters['failed']++;
                Log::error('Delhivery tracking request failed', [
                    'tracking_id' => $trackingId,
                    'error' => $e->getMessage(),
                ]);
                continue;
            }

            if (!$trackingData || !is_array($trackingData)) {
                $counters['skipped']++;
                Log::warning('Delhivery tracking response missing/invalid', [
                    'tracking_id' => $trackingId,
                ]);
                continue;
            }

            $shipmentNode = $trackingData['Shipment'] ?? [];
            $statusNode = $shipmentNode['Status'] ?? [];
            $statusText = (string) ($statusNode['Status'] ?? '');
            $instructions = $statusNode['Instructions'] ?? null;

            if ($statusText === '') {
                $counters['skipped']++;
                Log::warning('Delhivery tracking status not found', [
                    'tracking_id' => $trackingId,
                    'tracking_data' => $trackingData,
                ]);
                continue;
            }

            $matchingShipments = $shipments->whereIn('id', $shipmentIds);
            if ($matchingShipments->isEmpty()) {
                $counters['skipped']++;
                continue;
            }

            foreach ($matchingShipments as $shipment) {
                $orderStatusBefore = $shipment->order?->status;
                $shipmentStatusBefore = $shipment->status;

                $this->statusSyncService->applyCourierStatus($shipment, $statusText, [
                    'source' => 'delhivery_sync',
                    'external_substatus' => $instructions,
                    'history' => $shipmentNode['Scans'] ?? [],
                ]);

                $shipment->update(['raw_response' => $trackingData]);

                $shipment->load('order');
                $shipmentChanged = $shipmentStatusBefore !== $shipment->fresh()->status;
                $orderChanged = $shipment->order && $shipment->order->status !== $orderStatusBefore;

                if ($shipmentChanged) {
                    $counters['updated']++;
                } else {
                    $counters['skipped']++;
                }

                if ($orderChanged) {
                    $counters['orders_updated']++;
                }
            }
        }

        Log::info('Delhivery delivery status sync completed', $counters);
        $this->info('Delhivery sync completed: ' . json_encode($counters));

        return Command::SUCCESS;
    }
}
