<?php

namespace App\Http\Controllers\Customer;

use App\Http\Controllers\Controller;
use App\Models\Order;
use App\Models\Ticket;
use App\Services\CapturedPaymentRecoveryService;
use App\Services\InventoryService;
use App\Services\RazorpayService;
use App\Support\PaymentLogger;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\View\View;

class OrderController extends Controller
{
    public function __construct(
        protected RazorpayService $razorpayService,
        protected InventoryService $inventoryService,
        protected CapturedPaymentRecoveryService $capturedPaymentRecovery
    ) {
        $this->middleware('auth');
    }

    public function index(Request $request): View
    {
        $query = Order::with('items.product')
            ->where('user_id', auth()->id());

        // Search by Order ID
        if ($request->filled('search')) {
            $search = $request->search;
            $query->where('id', 'like', "%{$search}%");
        }

        // Filter by Status
        if ($request->filled('status')) {
            $query->where('status', $request->status);
        }

        // By default, exclude failed orders with no items (empty failed orders)
        // These are typically abandoned payment attempts that will be reused on retry
        if (!$request->filled('show_failed')) {
            $query->where(function ($q) {
                $q->where('payment_status', '!=', Order::PAYMENT_FAILED)
                  ->orWhereHas('items'); // Include failed orders that have items
            });
        }

        // Sort by Date
        $sort = $request->get('sort', 'newest');
        if ($sort === 'oldest') {
            $query->oldest();
        } else {
            $query->latest();
        }

        $orders = $query->paginate(10)->withQueryString();

        // Get status options for filter dropdown
        $statusOptions = [
            'awaiting_payment' => 'Awaiting Payment',
            'placed' => 'Placed',
            'confirmed' => 'Confirmed',
            'packed' => 'Packed',
            'shipped' => 'Shipped',
            'delivered' => 'Delivered',
            'cancelled' => 'Cancelled',
        ];

        return view('customer.orders.index', compact('orders', 'statusOptions'));
    }

    public function show(Order $order): View
    {
        if ($order->user_id !== auth()->id()) {
            abort(403);
        }

        $order->load('items.product', 'coupon');
        $activeTicket = Ticket::where('order_id', $order->id)
            ->where('customer_id', auth()->id())
            ->whereIn('status', [
                Ticket::STATUS_OPEN_UNASSIGNED,
                Ticket::STATUS_ASSIGNED,
                Ticket::STATUS_IN_PROGRESS,
                Ticket::STATUS_ANSWERED,
                Ticket::STATUS_REOPENED,
            ])
            ->latest('id')
            ->first();

        return view('customer.orders.show', compact('order', 'activeTicket'));
    }

    public function retryPayment(Order $order): JsonResponse
    {
        PaymentLogger::info('Retry payment requested', [
            'order_id' => $order->id,
            'user_id' => auth()->id(),
            'payment_id' => $order->razorpay_payment_id,
            'current_payment_status' => $order->payment_status,
            'current_order_status' => $order->status,
        ]);

        // Validate order belongs to authenticated user
        if ($order->user_id !== auth()->id()) {
            return response()->json(['error' => 'Unauthorized'], 403);
        }

        // Check if payment status is failed and payment method is online
        if(!in_array($order->payment_status, [Order::PAYMENT_FAILED, Order::PAYMENT_PENDING])) {
            return response()->json(['error' => 'This order is not eligible for payment retry'], 400);
        }
        if ($order->payment_method !== 'online') {
            return response()->json(['error' => 'Payment retry is only available for online orders'], 400);
        }

        // Validate order has items
        if ($order->items()->count() === 0) {
            return response()->json(['error' => 'Order has no items'], 400);
        }

        try {
            DB::beginTransaction();

            $order = Order::whereKey($order->id)
                ->lockForUpdate()
                ->firstOrFail();

            // Revalidate state against the locked row to avoid stale/race-prone retry.
            if (!in_array($order->payment_status, [Order::PAYMENT_FAILED, Order::PAYMENT_PENDING], true)) {
                DB::rollBack();
                return response()->json(['error' => 'This order is no longer eligible for payment retry'], 400);
            }

            if ($order->payment_method !== 'online') {
                DB::rollBack();
                return response()->json(['error' => 'Payment retry is only available for online orders'], 400);
            }

            $existingPaymentId = $this->capturedPaymentRecovery->resolveCapturedPaymentId($order) ?? '';
            if (
                $existingPaymentId !== ''
                && $this->capturedPaymentRecovery->recoverCapturedPayment($order, $existingPaymentId, 'retry_payment_precheck')
            ) {
                DB::commit();

                return response()->json([
                    'success' => true,
                    'recovered' => true,
                    'order_id' => $order->id,
                    'redirect' => route('customer.orders.index'),
                    'message' => 'Your previous payment was already successful. Order has been confirmed.',
                ]);
            }

            // Release any existing pending reservations for this order to prevent duplicate stock deduction
            // This is important for retry payment scenarios where old reservations might still exist
            $this->inventoryService->releaseByOrderId($order->id);

            // Reserve stock for all order items
            foreach ($order->items as $item) {
                try {
                    $this->inventoryService->reserve(
                        $item->product_id,
                        $item->qty,
                        null, // Use default TTL (5 minutes)
                        $order->id
                    );
                } catch (\Exception $e) {
                    DB::rollBack();
                    Log::error('Payment retry failed: Stock reservation error', [
                        'order_id' => $order->id,
                        'product_id' => $item->product_id,
                        'error' => $e->getMessage(),
                    ]);
                    PaymentLogger::error('Payment retry failed: stock reservation error', [
                        'order_id' => $order->id,
                        'product_id' => $item->product_id,
                        'error' => $e->getMessage(),
                    ]);

                    return response()->json([
                        'error' => 'Failed to reserve stock: ' . $e->getMessage()
                    ], 400);
                }
            }

            // Update order status to pending
            $order->update([
                'payment_status' => Order::PAYMENT_PENDING,
                'status' => Order::STATUS_AWAITING_PAYMENT,
                'razorpay_order_id' => null, // Clear old Razorpay order ID
                'razorpay_payment_id' => null,
                'razorpay_signature' => null,
            ]);

            // Create new Razorpay order
            $razorpayOrder = $this->razorpayService->createOrder(
                $order->total_payable,
                'order_' . $order->id
            );

            $order->update([
                'razorpay_order_id' => $razorpayOrder['id'],
            ]);
            PaymentLogger::info('Retry payment order recreated', [
                'order_id' => $order->id,
                'razorpay_order_id' => $razorpayOrder['id'],
            ]);

            DB::commit();

            return response()->json([
                'success' => true,
                'order_id' => $order->id,
                'razorpay_order_id' => $razorpayOrder['id'],
                'amount' => $razorpayOrder['amount'],
                'currency' => $razorpayOrder['currency'],
                'key' => \App\Models\Setting::get('payment_razorpay_key_id') ?: config('services.razorpay.key'),
            ]);
        } catch (\Exception $e) {
            DB::rollBack();
            PaymentLogger::error('Payment retry failed', [
                'order_id' => $order->id ?? null,
                'payment_id' => $order->razorpay_payment_id ?? null,
                'error' => $e->getMessage(),
            ]);
            Log::error('Payment retry failed', [
                'order_id' => $order->id,
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
            ]);

            return response()->json([
                'error' => 'Failed to initiate payment retry: ' . $e->getMessage()
            ], 500);
        }
    }
}
