<?php

namespace App\Http\Controllers\Admin;

use App\Exceptions\CarrierCreateFailedException;
use App\Http\Controllers\Controller;
use App\Http\Requests\Admin\UpdateOrderStatusRequest;
use App\Jobs\ProcessShipmentJob;
use App\Models\Carrier;
use App\Models\Country;
use App\Models\Order;
use App\Models\Shipment;
use App\Models\State;
use App\Services\OrderTrackingNotificationService;
use App\Services\AddressCityResolver;
use App\Services\InventoryService;
use App\Services\LedgerService;
use App\Services\Shipment\ShipmentOrderStatusMapper;
use App\Exceptions\StockException;
use Illuminate\Validation\Rule;
use Illuminate\Validation\Validator;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Schema;
use Illuminate\View\View;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Route;
use Illuminate\Validation\ValidationException;
use PDF;

class OrderController extends Controller
{
    public function __construct(
        protected InventoryService $inventoryService
    ) {}

    public function index(Request $request): View
    {
        $allowedPerPage = [10, 20, 50, 100];
        $perPage = (int) $request->input('per_page', 10);
        if (!in_array($perPage, $allowedPerPage, true)) {
            $perPage = 10;
        }

        $query = Order::with(['user', 'shipments.carrier']);

        // Handle merged cancelled/failed filter
        if ($request->filled('filter') && $request->filter === 'cancelled_failed') {
            $query->where(function ($mergedFilterQuery) {
                $mergedFilterQuery->where('status', Order::STATUS_CANCELLED)
                    ->orWhere('payment_status', Order::PAYMENT_FAILED);
            });
        } else {
            if ($request->filled('status')) {
                $query->where('status', $request->status);
            }

            if ($request->filled('payment_status')) {
                $query->where('payment_status', $request->payment_status);
            }
        }

        if ($request->filled('source')) {
            $query->where('source', $request->source);
        }

        $this->applyOrderSearchFilter($query, $this->resolveOrderSearchTerm($request));

        if ($request->filled('shipment_status')) {
            $mapper = app(ShipmentOrderStatusMapper::class);
            $normalizedFilter = $mapper->normalizeStatus($request->shipment_status);
            $query->whereHas('shipments', function ($sq) use ($normalizedFilter) {
                $sq->whereRaw("LOWER(REPLACE(REPLACE(status, '_', ' '), '-', ' ')) = ?", [$normalizedFilter]);
            });
        }

        $this->applyDateFilter($query, $request);

        $orders = $query->latest()->paginate($perPage)->withQueryString();

        // Get status counts for filter pills
        $statusCounts = $this->getStatusCounts($request);

        $shipmentStatusCounts = [];
        $showShipmentFilter = in_array($request->input('status'), [
            Order::STATUS_AWAITING_PICKUP,
            Order::STATUS_SHIPPED,
            Order::STATUS_RETURNED,
        ], true);

        if ($showShipmentFilter) {
            $shipmentStatusCounts = $this->getShipmentStatusCounts($request, $request->input('status'));
        }

        return view('admin.orders.index', compact(
            'orders', 'statusCounts', 'perPage', 'allowedPerPage',
            'shipmentStatusCounts', 'showShipmentFilter'
        ));
    }

    /**
     * Get counts for each status filter
     */
    private function getStatusCounts(Request $request): array
    {
        $baseQuery = Order::query();

        $this->applyOrderSearchFilter($baseQuery, $this->resolveOrderSearchTerm($request));

        if ($request->filled('source')) {
            $baseQuery->where('source', $request->source);
        }

        $this->applyDateFilter($baseQuery, $request);

        return [
            'all_orders'        => (clone $baseQuery)->count(),
            'awaiting_payment'  => (clone $baseQuery)->where('status', Order::STATUS_AWAITING_PAYMENT)->count(),
            'order_placed'      => (clone $baseQuery)->where('status', Order::STATUS_PLACED)->count(),
            'order_confirmed'   => (clone $baseQuery)->where('status', Order::STATUS_CONFIRMED)->count(),
            'order_packed'      => (clone $baseQuery)->where('status', Order::STATUS_PACKED)->count(),
            'shipment_created'  => (clone $baseQuery)->where('status', Order::STATUS_AWAITING_PICKUP)->count(),
            'shipped'           => (clone $baseQuery)->where('status', Order::STATUS_SHIPPED)->count(),
            'delivery_failed'   => (clone $baseQuery)->where('status', Order::STATUS_DELIVERY_FAILED)->count(),
            'completed'         => (clone $baseQuery)->where('status', Order::STATUS_DELIVERED)->count(),
            'returned'          => (clone $baseQuery)->where('status', Order::STATUS_RETURNED)->count(),
            'lost'              => (clone $baseQuery)->where('status', Order::STATUS_LOST)->count(),
            'cancelled_failed'  => (clone $baseQuery)
                ->where(function ($mergedCountQuery) {
                    $mergedCountQuery->where('status', Order::STATUS_CANCELLED)
                        ->orWhere('payment_status', Order::PAYMENT_FAILED);
                })->count(),
        ];
    }

    private function getShipmentStatusCounts(Request $request, string $orderStatus): array
    {
        $mapper = app(ShipmentOrderStatusMapper::class);

        $baseQuery = Order::query()->where('status', $orderStatus);

        $this->applyOrderSearchFilter($baseQuery, $this->resolveOrderSearchTerm($request));

        if ($request->filled('source')) {
            $baseQuery->where('source', $request->source);
        }

        $this->applyDateFilter($baseQuery, $request);

        $rows = DB::table('shipments')
            ->whereIn('shipments.order_id', (clone $baseQuery)->select('id'))
            ->select('shipments.status', DB::raw('COUNT(DISTINCT shipments.order_id) as order_count'))
            ->groupBy('shipments.status')
            ->get();

        $counts = [];
        $allCount = 0;

        foreach ($rows as $row) {
            $normalized = $mapper->normalizeStatus($row->status);

            if (!isset($counts[$normalized])) {
                $counts[$normalized] = 0;
            }
            $counts[$normalized] += $row->order_count;
            $allCount += $row->order_count;
        }

        arsort($counts);

        return ['all' => $allCount] + $counts;
    }

    private function applyDateFilter($query, Request $request): void
    {
        if (!$request->filled('date_filter')) {
            return;
        }

        switch ($request->date_filter) {
            case 'today':
                $query->whereDate('created_at', today());
                break;
            case 'yesterday':
                $query->whereDate('created_at', today()->subDay());
                break;
            case 'last_7_days':
                $query->where('created_at', '>=', now()->subDays(7));
                break;
            case 'last_month':
                $query->where('created_at', '>=', now()->subMonth());
                break;
            case 'last_year':
                $query->where('created_at', '>=', now()->subYear());
                break;
            case 'custom':
                if ($request->filled('date_from')) {
                    $query->whereDate('created_at', '>=', $request->date_from);
                }
                if ($request->filled('date_to')) {
                    $query->whereDate('created_at', '<=', $request->date_to);
                }
                break;
        }
    }

    private function resolveOrderSearchTerm($request): ?string
    {
        foreach (['search', 'order_id', 'customer_phone', 'awb_number'] as $key) {
            if ($request && $request->filled($key)) {
                return trim((string) $request->input($key));
            }
        }

        return null;
    }

    private function applyOrderSearchFilter($query, ?string $search): void
    {
        $search = trim((string) $search);
        if ($search === '') {
            return;
        }

        $query->where(function ($searchQuery) use ($search) {
            $normalizedOrderId = preg_replace('/\D+/', '', $search);
            if ($normalizedOrderId !== '') {
                $searchQuery->orWhere('id', (int) $normalizedOrderId);
            }

            $searchQuery->orWhereHas('user', fn ($userQuery) => $userQuery->where('mobile', 'like', "%{$search}%"))
                ->orWhere('address_snapshot->mobile', 'like', "%{$search}%")
                ->orWhere('address_snapshot->phone', 'like', "%{$search}%")
                ->orWhere('address_snapshot->contact', 'like', "%{$search}%")
                ->orWhere('delhivery_awb', 'like', "%{$search}%")
                ->orWhereHas('shipments', fn ($shipmentQuery) => $shipmentQuery->where('tracking_id', 'like', "%{$search}%"));
        });
    }

    public function show(Order $order): View
    {
        try {
            $order->load('items.product', 'user', 'coupon', 'staff');
            
            // Load shipments if table exists
            if (Schema::hasTable('shipments')) {
                $order->load('shipments.carrier');
            }
        } catch (\Exception $e) {
            // If shipments table doesn't exist or relationship fails, continue without it
            Log::warning('Failed to load shipments for order: ' . $e->getMessage());
        }

        // Get enabled carriers for shipment initiation
        $carriers = collect();
        try {
            if (Schema::hasTable('carriers')) {
                $carriers = Carrier::enabled()->get();
            }
        } catch (\Exception $e) {
            // Carriers table might not exist
        }

        return view('admin.orders.show', compact('order', 'carriers'));
    }

    public function printInvoice(Order $order): View
    {
        $order->loadMissing('items.product', 'user', 'staff');

        return view('admin.orders.thermal_invoice', [
            'order' => $order,
            'autoPrint' => true,
        ]);
    }

    /**
     * Get status sequence order for forward-only validation
     */
    private function getStatusSequence(): array
    {
        return [
            Order::STATUS_AWAITING_PAYMENT => 1,
            Order::STATUS_PLACED => 2,
            Order::STATUS_CONFIRMED => 3,
            Order::STATUS_PACKED => 4,
            Order::STATUS_AWAITING_PICKUP => 5,
            Order::STATUS_SHIPPED => 6,
            Order::STATUS_DELIVERED => 7,
            // cancelled and returned are special cases
        ];
    }

    /**
     * Check if status change is forward (or special case)
     */
    private function isStatusForward(string $currentStatus, string $newStatus): bool
    {
        // Special cases: cancelled can be set from any status, returned from delivered
        if ($newStatus === Order::STATUS_CANCELLED) {
            return true; // Can always cancel
        }
        if ($newStatus === Order::STATUS_RETURNED && $currentStatus === Order::STATUS_DELIVERED) {
            return true; // Can return from delivered
        }
        
        $sequence = $this->getStatusSequence();
        $currentOrder = $sequence[$currentStatus] ?? 0;
        $newOrder = $sequence[$newStatus] ?? 0;
        
        return $newOrder > $currentOrder;
    }

    public function updateStatus(UpdateOrderStatusRequest $request, Order $order): RedirectResponse
    {
        $newStatus = $request->validated('status');
        $currentStatus = $order->status;
        $user = auth()->user();

        // Skip closed-day check for admins or users with reopen permission
        if (!$user->isAdmin() && !$user->can('reports.day-ledger.reopen')) {
            try {
                app(LedgerService::class)->assertDayOpen($order->created_at->toDateString());
            } catch (ValidationException $e) {
                $message = $e->errors()['date'][0] ?? 'This day is closed. Reopen it before updating order status.';
                return redirect()->back()->with('error', $message);
            }
        }

        // Check if status change is backward (for non-admin users)
        if (!$user->isAdmin()) {
            if (!$this->isStatusForward($currentStatus, $newStatus)) {
                return redirect()->back()->with('error', 'Order status can only be moved forward.');
            }
        }

        try {
            DB::transaction(function () use ($order, $currentStatus, $newStatus) {
                $lockedOrder = Order::whereKey($order->id)
                    ->lockForUpdate()
                    ->with('items')
                    ->firstOrFail();

                $this->inventoryService->handleOrderStatusChange(
                    $lockedOrder,
                    $currentStatus,
                    $newStatus
                );

                $lockedOrder->update(['status' => $newStatus]);
            });
        } catch (StockException $e) {
            return redirect()->back()->with('error', 'Failed to update order status: ' . $e->getMessage());
        }

        return redirect()->back()->with('success', 'Order status updated successfully!');
    }

    public function updateAddress(Request $request, Order $order, AddressCityResolver $cityResolver): JsonResponse|RedirectResponse
    {
        // Skip closed-day check for admins or users with reopen permission
        $user = auth()->user();
        if (!$user || (!$user->isAdmin() && !$user->can('reports.day-ledger.reopen'))) {
            try {
                app(LedgerService::class)->assertDayOpen($order->created_at->toDateString());
            } catch (ValidationException $e) {
                $message = $e->errors()['date'][0] ?? 'This day is closed. Reopen it before editing order details.';
                if ($request->expectsJson()) {
                    return response()->json([
                        'success' => false,
                        'message' => $message,
                    ], 422);
                }

                return redirect()->back()->with('error', $message);
            }
        }

        // Check if order status allows editing
        $allowedStatuses = [Order::STATUS_AWAITING_PAYMENT, Order::STATUS_PLACED, Order::STATUS_CONFIRMED, Order::STATUS_PACKED];
        if (!in_array($order->status, $allowedStatuses)) {
            if ($request->expectsJson()) {
                return response()->json([
                    'success' => false,
                    'message' => 'Address can only be edited for orders awaiting payment, placed, confirmed, or packed.',
                ], 403);
            }
            return redirect()->back()->with('error', 'Address can only be edited for orders awaiting payment, placed, confirmed, or packed.');
        }

        if ($request->has('city_custom')) {
            $custom = strip_tags(trim((string) $request->input('city_custom')));
            $custom = preg_replace('/\s+/u', ' ', $custom) ?? '';
            $request->merge(['city_custom' => $custom !== '' ? $custom : null]);
        }

        $request->merge([
            'mobile' => $this->formatIndianMobileForStorage($request->input('mobile')),
        ]);

        $validator = \Illuminate\Support\Facades\Validator::make($request->all(), [
            'name' => 'required|string|max:255',
            'mobile' => ['required', 'string', 'regex:/^\+91[6-9]\d{9}$/'],
            'line1' => 'required|string|max:255',
            'line2' => 'nullable|string|max:255',
            'country_id' => ['required', 'integer', Rule::exists('countries', 'id')->where('status', 1)],
            'state_id' => [
                'required',
                'integer',
                Rule::exists('states', 'id')
                    ->where('status', 1)
                    ->where(fn ($q) => $q->where('country_id', $request->input('country_id'))),
            ],
            'city_id' => [
                'nullable',
                'integer',
                'prohibited_if:city_custom,*',
                Rule::exists('cities', 'id')
                    ->where('status', 1)
                    ->where(fn ($q) => $q->where('state_id', $request->input('state_id'))),
            ],
            'city_custom' => [
                'nullable',
                'string',
                'min:2',
                'max:100',
                'regex:/^[\p{L}\p{M}\s.\-\']+$/u',
                'prohibited_if:city_id,*',
            ],
            'pin' => 'required|string|regex:/^[1-9]\d{5}$/',
        ], [
            'mobile.regex' => 'Please enter a valid 10-digit Indian mobile number.',
            'city_custom.regex' => 'City name may only contain letters, spaces, hyphens, apostrophes, and periods.',
        ]);

        $validator->after(function (Validator $v) use ($request) {
            if (!$request->filled('city_id') && !$request->filled('city_custom')) {
                $v->errors()->add('city_id', 'Please select a city or enter your city name.');
            }
        });

        $validated = $validator->validate();

        $state = State::find($validated['state_id']);
        $country = Country::find($validated['country_id']);
        $city = $cityResolver->resolve(
            cityId: $validated['city_id'] ?? null,
            customName: $validated['city_custom'] ?? null,
            stateId: (int) $validated['state_id'],
            countryId: (int) $validated['country_id'],
            userId: auth()->id(),
        );

        $addressSnapshot = [
            'name' => $validated['name'],
            'mobile' => $validated['mobile'],
            'line1' => $validated['line1'],
            'line2' => $validated['line2'] ?? null,
            'city' => $city->name,
            'state' => $state?->name,
            'country' => $country?->name,
            'country_id' => $country?->id,
            'state_id' => $state?->id,
            'city_id' => $city->id,
            'pin' => $validated['pin'],
        ];

        // Update order address snapshot
        $order->update([
            'address_snapshot' => $addressSnapshot,
        ]);

        if ($request->expectsJson()) {
            return response()->json([
                'success' => true,
                'message' => 'Shipping address updated successfully!',
                'address' => $addressSnapshot,
            ]);
        }

        return redirect()->back()->with('success', 'Shipping address updated successfully!');
    }

    /**
     * Get carriers list for shipment initiation modal
     */
    public function initiateShipment(Order $order): JsonResponse
    {
        // Check permission
        $user = auth()->user();
        if (!$user->can('manage shipping') && !$user->isAdmin() && !$user->isStaff()) {
            return response()->json(['error' => 'Unauthorized'], 403);
        }

        // Check if order is packed (or delivery_failed from an earlier failed booking)
        if (!in_array($order->status, [Order::STATUS_PACKED, Order::STATUS_DELIVERY_FAILED], true)) {
            return response()->json(['error' => 'Order must be in packed status'], 400);
        }

        // Check if shipment already exists
        if ($order->shipments()->where('status', '!=', Shipment::STATUS_FAILED)->exists()) {
            return response()->json(['error' => 'Shipment already exists for this order'], 400);
        }

        // Get enabled carriers (include process_type for front-end)
        $carriers = Carrier::enabled()->get()->map(function ($carrier) {
            return [
                'id' => $carrier->id,
                'name' => $carrier->name,
                'slug' => $carrier->slug,
                'process_type' => $carrier->process_type ?? \App\Models\Carrier::PROCESS_TYPE_AUTOMATIC,
                'config_schema' => $carrier->config_schema ?? [],
            ];
        });

        return response()->json([
            'success' => true,
            'carriers' => $carriers,
        ]);
    }

    /**
     * Check delivery availability for a carrier and pincode
     */
    public function checkDeliveryAvailability(Request $request, Order $order): JsonResponse
    {
        try {
            // Check permission
            $user = auth()->user();
            if (!$user->can('manage shipping') && !$user->isAdmin() && !$user->isStaff()) {
                return response()->json(['error' => 'Unauthorized'], 403);
            }

            // Validate carrier_id
            $validated = $request->validate([
                'carrier_id' => 'required|exists:carriers,id',
            ]);

            $carrier = Carrier::findOrFail($validated['carrier_id']);

            // Manual carriers: no API check, assume available
            if ($carrier->isManual()) {
                return response()->json([
                    'available' => true,
                    'message' => 'Manual carrier tracking will be entered on the order.',
                    'carrier' => $carrier->slug,
                ]);
            }

            // Get pincode from order address
            $address = $order->address_snapshot;
            if (empty($address['pin'])) {
                return response()->json([
                    'error' => 'Order address does not have a pincode',
                ], 400);
            }

            $pincode = $address['pin'];

            // Get carrier service and check availability
            $carrierService = \App\Services\Carriers\CarrierServiceFactory::makeFromModel($carrier);
            $result = $carrierService->checkDeliveryAvailability($pincode);

            return response()->json([
                'available' => $result['available'],
                'message' => $result['message'],
                'carrier' => $carrier->slug,
                'carrier_name' => $carrier->name,
                'pincode' => $pincode,
                'action' => $result['available']
                    ? null
                    : 'Please choose another shipping service from the carrier dropdown.',
            ]);
        } catch (\Illuminate\Validation\ValidationException $e) {
            return response()->json([
                'error' => 'Validation failed',
                'errors' => $e->errors(),
            ], 422);
        } catch (\Exception $e) {
            Log::error('Failed to check delivery availability', [
                'order_id' => $order->id,
                'error' => $e->getMessage(),
            ]);

            return response()->json([
                'error' => 'Failed to check delivery availability: ' . $e->getMessage(),
            ], 500);
        }
    }

    /**
     * Store shipment and dispatch job
     */
    public function storeShipment(Request $request, Order $order): JsonResponse|RedirectResponse
    {
        try {
            // Check permission
            $user = auth()->user();
            if (!$user->can('manage shipping') && !$user->isAdmin() && !$user->isStaff()) {
                if ($request->expectsJson()) {
                    return response()->json(['error' => 'Unauthorized'], 403);
                }
                return redirect()->back()->with('error', 'Unauthorized');
            }

            // Check if shipments table exists
            if (!Schema::hasTable('shipments')) {
                if ($request->expectsJson()) {
                    return response()->json(['error' => 'Shipments table does not exist. Please run migrations.'], 500);
                }
                return redirect()->back()->with('error', 'Shipments table does not exist. Please run migrations.');
            }

            // Check if order is packed (keep delivery_failed retryable after a failed booking)
            if (!in_array($order->status, [Order::STATUS_PACKED, Order::STATUS_DELIVERY_FAILED], true)) {
                if ($request->expectsJson()) {
                    return response()->json(['error' => 'Order must be in packed status'], 400);
                }
                return redirect()->back()->with('error', 'Order must be in packed status');
            }

            // Delete any failed shipments first
            try {
                $order->shipments()->where('status', Shipment::STATUS_FAILED)->delete();
            } catch (\Exception $e) {
                Log::warning('Failed to delete failed shipments: ' . $e->getMessage());
            }

            // Check if shipment already exists (excluding deleted ones)
            try {
                if ($order->shipments()->exists()) {
                    if ($request->expectsJson()) {
                        return response()->json(['error' => 'Shipment already exists for this order'], 400);
                    }
                    return redirect()->back()->with('error', 'Shipment already exists for this order');
                }
            } catch (\Exception $e) {
                // Relationship might fail if table structure is wrong, continue anyway
                Log::warning('Failed to check existing shipments: ' . $e->getMessage());
            }

            // Validate carrier_id first
            $data = $request->validate([
                'carrier_id' => 'required|exists:carriers,id',
                'tracking_number' => 'nullable|string|max:255',
            ]);

            $carrier = Carrier::findOrFail($data['carrier_id']);

            if (!$carrier->enabled) {
                if ($request->expectsJson()) {
                    return response()->json(['error' => 'Carrier is disabled'], 400);
                }
                return redirect()->back()->with('error', 'Carrier is disabled');
            }

            if ($carrier->isManual()) {
                $request->validate(['tracking_number' => 'required|string|max:255']);
                $trackingNumber = trim($data['tracking_number'] ?? '');

                $shipment = Shipment::create([
                    'order_id' => $order->id,
                    'carrier_id' => $carrier->id,
                    'tracking_id' => $trackingNumber,
                    'status' => Shipment::STATUS_CREATED,
                    'metadata' => null,
                ]);

                app(\App\Services\Shipment\ShipmentStatusSyncService::class)->applyCourierStatus(
                    $shipment,
                    'Created',
                    ['source' => 'manual_shipment']
                );

                $order->update([
                    'status' => Order::STATUS_SHIPPED,
                    'delhivery_awb' => $trackingNumber,
                ]);

                app(OrderTrackingNotificationService::class)->sendIfEnabled($order);

                if ($request->expectsJson()) {
                    return response()->json([
                        'success' => true,
                        'message' => 'Manual shipment recorded successfully!',
                        'shipment_id' => $shipment->id,
                    ]);
                }
                return redirect()->back()->with('success', 'Manual shipment recorded successfully!');
            }

            // Automatic: handle form_data
            $formData = $request->input('form_data');
            if (is_string($formData) && !empty($formData)) {
                $decoded = json_decode($formData, true);
                $formData = (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) ? $decoded : [];
            }
            $data['form_data'] = is_array($formData) ? $formData : [];

            // Create shipment record
            $shipment = Shipment::create([
                'order_id' => $order->id,
                'carrier_id' => $carrier->id,
                'status' => Shipment::STATUS_PENDING,
                'metadata' => !empty($data['form_data']) ? $data['form_data'] : null,
            ]);

            (new ProcessShipmentJob($shipment, $data['form_data'] ?? []))->execute();

            $shipment->refresh()->load('carrier');
            $fallback = is_array($shipment->metadata) ? ($shipment->metadata['fallback'] ?? null) : null;
            $successMessage = is_array($fallback)
                ? sprintf(
                    'Shipment created via %s after %s failed.',
                    $shipment->carrier?->name ?? ($fallback['to'] ?? 'fallback carrier'),
                    $fallback['from'] ?? 'the first carrier'
                )
                : 'Shipment initiated successfully!';

            if ($request->expectsJson()) {
                return response()->json([
                    'success' => true,
                    'message' => $successMessage,
                    'shipment_id' => $shipment->id,
                    'fallback' => $fallback,
                ]);
            }

            return redirect()->back()->with('success', $successMessage);
        } catch (\Illuminate\Validation\ValidationException $e) {
            if ($request->expectsJson()) {
                return response()->json([
                    'error' => 'Validation failed',
                    'errors' => $e->errors(),
                ], 422);
            }
            return redirect()->back()->withErrors($e->errors())->withInput();
        } catch (CarrierCreateFailedException $e) {
            Log::error('Failed to create shipment', [
                'order_id' => $order->id,
                'error' => $e->getMessage(),
                'failure_reason' => $e->getFailureReason(),
            ]);

            $payload = $this->carrierShipmentFailurePayload($e, $order);

            if ($request->expectsJson()) {
                return response()->json($payload, 422);
            }

            $flashMessage = ($payload['message'] ?? $e->getMessage())
                . (isset($payload['action']) ? ' ' . $payload['action'] : '');

            return redirect()->back()->with('error', $flashMessage);
        } catch (\Exception $e) {
            Log::error('Failed to create shipment', [
                'order_id' => $order->id,
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
            ]);

            if ($request->expectsJson()) {
                return response()->json([
                    'error' => $e->getMessage(),
                ], 500);
            }

            return redirect()->back()->with('error', $e->getMessage());
        }
    }

    protected function carrierShipmentFailurePayload(CarrierCreateFailedException $e, Order $order): array
    {
        $pincode = trim((string) ($order->address_snapshot['pin'] ?? ''));
        $pinText = $pincode !== '' ? " (PIN: {$pincode})" : '';

        $payload = [
            'error' => $e->getMessage(),
            'failure_reason' => $e->getFailureReason(),
        ];

        $attempts = $e->getRawResponse()['attempts'] ?? [];
        $triedBoth = is_array($attempts) && count($attempts) >= 2;

        if ($triedBoth) {
            return array_merge($payload, [
                'title' => 'Delhivery and Ekart both failed',
                'message' => "Shipment could not be created{$pinText}. The order is still packed so you can initiate shipping again.",
                'action' => 'Fix the carrier wallet/pincode issue, then try again from this order.',
            ]);
        }

        if ($e->getFailureReason() === CarrierCreateFailedException::FAILURE_NON_SERVICEABLE_PINCODE) {
            return array_merge($payload, [
                'title' => 'Delivery Pincode Not Serviceable',
                'message' => "This customer's delivery pincode{$pinText} is not covered by the selected carrier.",
                'action' => 'The order is still packed. Choose another shipping service and try again.',
            ]);
        }

        if ($e->getFailureReason() === CarrierCreateFailedException::FAILURE_INSUFFICIENT_BALANCE) {
            return array_merge($payload, [
                'title' => 'Carrier Wallet Low',
                'message' => 'The selected carrier reported insufficient wallet balance.',
                'action' => 'The order is still packed. Top up the wallet or try again after the fallback carrier is available.',
            ]);
        }

        return $payload;
    }

    /**
     * API endpoint for orders with cursor pagination and KPIs
     */
    public function apiIndex(Request $request): JsonResponse
    {
        // Validate inputs
        $validated = $request->validate([
            'status' => 'nullable|string|in:all,placed,processing,shipped,delivered,cancelled,returned',
            'per_page' => 'nullable|integer|min:1|max:100',
            'cursor' => 'nullable|string',
        ]);

        $status = $validated['status'] ?? 'placed';
        $perPage = $validated['per_page'] ?? 15;

        // Build base query
        $query = Order::with(['user', 'items.product:id,name,image_path'])
            ->select('orders.*');

        // Apply status filter
        $query->byStatus($status);

        // Apply cursor pagination
        if ($request->filled('cursor')) {
            $cursor = json_decode(base64_decode($request->cursor), true);
            if (isset($cursor['id'])) {
                $query->where('id', '<', $cursor['id']);
            }
        }

        // Order by id desc for cursor pagination
        $query->orderBy('id', 'desc');

        // Get orders
        $orders = $query->limit($perPage + 1)->get();

        // Check if there are more results
        $hasMore = $orders->count() > $perPage;
        if ($hasMore) {
            $orders = $orders->take($perPage);
        }

        // Prepare next cursor
        $nextCursor = null;
        if ($hasMore && $orders->isNotEmpty()) {
            $lastOrder = $orders->last();
            $nextCursor = base64_encode(json_encode(['id' => $lastOrder->id]));
        }

        // Format orders for response
        $formattedOrders = $orders->map(function ($order) {
            return [
                'id' => $order->id,
                'order_number' => '#' . $order->id,
                'created_at' => $order->created_at->toIso8601String(),
                'status' => $order->status,
                'status_label' => $order->status_label,
                'status_badge_class' => $order->status_badge_class,
                'items_count' => $order->items->count(),
                'total_payable' => number_format($order->total_payable, 2, '.', ''),
                'payment_status' => $order->payment_status,
                'payment_method' => $order->payment_method,
                'source' => $order->source ?? 'online',
                'user' => [
                    'id' => $order->user->id,
                    'name' => $order->user->name,
                    'mobile' => $order->user->mobile,
                ],
                'address_snapshot' => $order->address_snapshot ?? [],
                'items' => $order->items->take(3)->map(function ($item) {
                    $product = $item->product;
                    if (!$product) {
                        // Product was deleted, use item name as fallback
                        return [
                            'product' => [
                                'id' => null,
                                'name' => $item->name ?? 'N/A',
                                'image_path' => null,
                            ],
                        ];
                    }
                    return [
                        'product' => [
                            'id' => $product->id,
                            'name' => $product->name ?? $item->name ?? 'N/A',
                            'image_path' => $product->image_path ?? null,
                        ],
                    ];
                })->filter(function ($item) {
                    // Keep items even if product is deleted (show item name)
                    return true;
                }),
            ];
        });

        // Calculate KPIs based on status filter
        $kpis = $this->calculateKpis($status);

        return response()->json([
            'data' => $formattedOrders,
            'next_cursor' => $nextCursor,
            'has_more' => $hasMore,
            'meta' => [
                'per_page' => $perPage,
                'status' => $status,
            ],
            'kpis' => $kpis,
        ]);
    }

    public function orderLabel($id){
        $order = Order::find(decrypt($id));
        // $order = $orderDetail->order;
        
        $pdf = PDF::loadView('admin.orders.label', [
            'order' => $order,
        ], [], [
            'format' =>  [100, 150],
            'orientation' => 'P',
            'margin_left' => 1,
            'margin_right' => 1,
            'margin_top' => 4,
            'margin_bottom' => 1,
            'dpi' => 300,
        ]);

        $fileName = "label-{$order->code}.pdf";

        return $pdf->stream($fileName);
    }

    /**
     * Calculate KPIs for orders (Shopify-style)
     */
    private function calculateKpis(string $status): array
    {
        $today = now()->startOfDay();
        $baseQuery = Order::query();

        // Apply status filter to base query for KPI calculations
        if ($status !== 'all') {
            $baseQuery->byStatus($status);
        }

        // Total Orders (filtered by status)
        $totalOrders = (clone $baseQuery)->count();

        // Total Revenue (filtered by status, only paid orders)
        $totalRevenue = (clone $baseQuery)
            ->where('payment_status', Order::PAYMENT_PAID)
            ->sum('total_payable');

        // Average Order Value
        $avgOrderValue = $totalOrders > 0 ? ($totalRevenue / $totalOrders) : 0;

        // Today's Orders (filtered by status)
        $todayOrders = (clone $baseQuery)
            ->whereDate('created_at', $today)
            ->count();

        // Today's Revenue (filtered by status, only paid orders)
        $todayRevenue = (clone $baseQuery)
            ->whereDate('created_at', $today)
            ->where('payment_status', Order::PAYMENT_PAID)
            ->sum('total_payable');

        // Pending Orders (placed + processing)
        $pendingOrders = Order::whereIn('status', [
            Order::STATUS_PLACED,
            Order::STATUS_CONFIRMED,
            Order::STATUS_PACKED
        ])->count();

        // Fulfilled Orders (shipped + delivered)
        $fulfilledOrders = Order::whereIn('status', [Order::STATUS_SHIPPED, Order::STATUS_DELIVERED])
            ->count();

        // Unfulfilled Orders (placed + confirmed + packed)
        $unfulfilledOrders = Order::whereIn('status', [
            Order::STATUS_PLACED,
            Order::STATUS_CONFIRMED,
            Order::STATUS_PACKED
        ])->count();

        return [
            'total_orders' => $totalOrders,
            'total_revenue' => number_format($totalRevenue, 2, '.', ''),
            'avg_order_value' => number_format($avgOrderValue, 2, '.', ''),
            'today_orders' => $todayOrders,
            'today_revenue' => number_format($todayRevenue, 2, '.', ''),
            'pending_orders' => $pendingOrders,
            'fulfilled_orders' => $fulfilledOrders,
            'unfulfilled_orders' => $unfulfilledOrders,
        ];
    }

    /**
     * Generate order labels for a given date range and status.
     */
    public function orderMakingLabels(Request $request)
    {
        $date_from = $request->date_from;
        $date_to   = $request->date_to;
        $status      = $request->status ?? 'placed';
        $sort_search = $request->search ?? null;
	
	    $baseQuery = Order::query()->whereIn('status', ['placed','confirmed','packed','awaiting_pickup']);
	
        if (!empty($date_from)) {
            $date_to = $date_to ?? now()->format('Y-m-d');
            $baseQuery->whereBetween('created_at', [
                date('Y-m-d 00:00:00', strtotime($date_from)),
                date('Y-m-d 23:59:59', strtotime($date_to))
            ]);
        }else {
            $date_to = null;
        }

        if (!empty($sort_search)) {
            $baseQuery->where('id', $sort_search);
        }

        $orderStatusCounts = (clone $baseQuery)
            ->selectRaw('status, COUNT(*) as total')
            ->groupBy('status')
            ->pluck('total', 'status')
            ->toArray();

        $orderStatusCounts['all'] = (clone $baseQuery)->count();

        if (!empty($request->status)) {
            $baseQuery->where('status', $request->status);
            $status = $request->status;
        }

        $orders = $baseQuery->with(['items.product'])->orderByDesc('id')->get();

        if (Route::currentRouteName() === 'admin.making.orders.pdf') {
            $pdf = PDF::loadView('admin.orders.making_labels_pdf', 
                                compact('orders', 'date_from', 'date_to', 'status'), 
                                [], [
                                    'format'      => 'A4',
                                    'orientation' => 'P',
                                ]);

            $fileDate = $date_from ?? now()->format('Y-m-d') . ($date_to ? "_to_{$date_to}" : '');

            // Auto update placed -> confirmed
            if ($status === 'placed') {
                $placedIds = $orders->pluck('id');

                if ($placedIds->isNotEmpty()) {
                    Order::whereIn('id', $placedIds)->update([
                        'status' => 'confirmed'
                    ]);
                }
            }
            $pdf->download("order-labels-{$fileDate}.pdf");
        }
        
        return view('admin.orders.making_labels', compact('orders','status','date_from', 'date_to','orderStatusCounts','sort_search'));
    }

    private function formatIndianMobileForStorage(?string $mobile): string
    {
        $digits = preg_replace('/\D/', '', trim((string) $mobile));

        if (preg_match('/^(?:91|0)?([6-9]\d{9})$/', $digits, $matches)) {
            return '+91' . $matches[1];
        }

        if (preg_match('/^[6-9]\d{9}$/', $digits)) {
            return '+91' . $digits;
        }

        return trim((string) $mobile);
    }
}
