<?php

namespace App\Console\Commands;

use App\Models\Order;
use App\Models\OrderCourierShipment;
use App\Models\OrderCourierShipmentLog;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;

class AuditCourierOutForDeliveryCommand extends Command
{
    protected $signature = 'courier:audit-out-for-delivery
        {--limit=500 : Maximum courier-managed picked-up orders to inspect}
        {--apply : Correct reviewed invalid statuses to handover}';

    protected $description = 'Audit courier-managed Out for Delivery orders and optionally correct unconfirmed legacy statuses.';

    public function handle(): int
    {
        if (! $this->hasRequiredSchema()) {
            $this->error('Required courier Out for Delivery schema is missing. No data changed.');

            return self::FAILURE;
        }

        $limit = max(1, min((int) $this->option('limit'), 5000));
        $orders = Order::query()
            ->with('courierShipment')
            ->where('order_status', 'picked_up')
            ->whereHas('courierShipment')
            ->orderBy('id')
            ->limit($limit)
            ->get();

        $report = $orders->map(function (Order $order) {
            $shipment = $order->courierShipment;
            $valid = $shipment?->isCourierConfirmedOutForDelivery() === true;

            return [
                'order_id' => $order->id,
                'provider' => $shipment?->provider ?: '-',
                'status' => $shipment?->courier_status ?: '-',
                'status_code' => $shipment?->courier_status_code ?: '-',
                'rider' => $shipment?->hasConfirmedCourierRider() ? 'YES' : 'NO',
                'result' => $valid ? 'VALID' : 'INVALID',
                'reason' => $this->reason($shipment, $valid),
            ];
        });

        $this->table(
            ['Order', 'Provider', 'Courier Status', 'Status Code', 'Rider', 'Result', 'Reason'],
            $report->all()
        );

        $invalidIds = $report->where('result', 'INVALID')->pluck('order_id')->all();
        $this->newLine();

        if (! $this->option('apply')) {
            $this->info(
                'Dry run only: '.count($invalidIds).' invalid of '.$report->count()
                .' courier-managed Out for Delivery orders. No data changed.'
            );
            $this->line('After reviewing this report, run again with --apply to move only invalid legacy orders to handover.');

            return self::SUCCESS;
        }

        $corrected = 0;
        $skipped = 0;

        foreach ($invalidIds as $orderId) {
            DB::transaction(function () use ($orderId, &$corrected, &$skipped) {
                $order = Order::query()->with('courierShipment')->lockForUpdate()->find($orderId);
                $shipment = $order?->courierShipment;

                if (! $order
                    || $order->order_status !== 'picked_up'
                    || ! $shipment
                    || $shipment->isCourierConfirmedOutForDelivery()
                ) {
                    $skipped++;

                    return;
                }

                $order->order_status = 'handover';

                if (Schema::hasColumn($order->getTable(), 'handover')) {
                    $order->handover = $order->handover ?: $shipment->sent_to_courier_at ?: now();
                }

                if (Schema::hasColumn($order->getTable(), 'picked_up')) {
                    $order->picked_up = null;
                }

                $order->save();

                if (Schema::hasTable('order_courier_shipment_logs')) {
                    OrderCourierShipmentLog::query()->create([
                        'order_courier_shipment_id' => $shipment->id,
                        'order_id' => $order->id,
                        'action' => 'legacy_ofd_corrected',
                        'provider' => $shipment->provider,
                        'success' => true,
                        'request_payload' => [
                            'previous_order_status' => 'picked_up',
                            'requested_by' => 'courier:audit-out-for-delivery --apply',
                        ],
                        'response_payload' => [
                            'corrected_order_status' => 'handover',
                            'reason' => $this->reason($shipment, false),
                        ],
                    ]);
                }

                $corrected++;
            });
        }

        $this->info("Correction complete: {$corrected} changed to handover; {$skipped} skipped after revalidation.");

        return self::SUCCESS;
    }

    private function hasRequiredSchema(): bool
    {
        if (! Schema::hasTable('orders') || ! Schema::hasTable('order_courier_shipments')) {
            return false;
        }

        foreach ([
            'out_for_delivery_at',
            'courier_rider_id',
            'courier_rider_name',
            'courier_rider_phone',
            'status_mapping_result',
        ] as $column) {
            if (! Schema::hasColumn('order_courier_shipments', $column)) {
                return false;
            }
        }

        return true;
    }

    private function reason(?OrderCourierShipment $shipment, bool $valid): string
    {
        if ($valid) {
            return 'provider_status_and_rider_confirmed';
        }

        if (! $shipment?->hasConfirmedCourierRider()) {
            return 'provider_rider_data_missing';
        }

        if ($shipment->status_mapping_result !== 'out_for_delivery') {
            return 'approved_provider_status_missing';
        }

        if ($shipment->out_for_delivery_at === null) {
            return 'confirmation_time_missing';
        }

        return 'out_for_delivery_not_confirmed';
    }
}
