<?php

namespace App\Http\Controllers\Api\V1;

use App\Http\Controllers\Controller;
use App\Http\Requests\Order\CheckoutRequest;
use App\Http\Requests\Order\RateOrderRequest;
use App\Http\Requests\Order\RateOrderItemRequest;
use App\Http\Resources\CartResource;
use App\Http\Resources\OrderResource;
use App\Models\Cart;
use App\Models\Coupon;
use App\Models\Order;
use App\Models\OrderItem;
use App\Models\ProductRating;
use App\Models\Setting;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
use Illuminate\Support\Facades\DB;

class OrderController extends Controller
{
    public function index(Request $request): AnonymousResourceCollection
    {
        $user = $request->user();

        $query = Order::query();

        // For customers, show only their orders
        if ($user && $user->isCustomer()) {
            $query->where('user_id', $user->id);
        }

        // Filter by status
        if ($request->has('status')) {
            $query->where('status', $request->status);
        }

        $orders = $query->with(['items', 'payments'])
            ->orderBy('created_at', 'desc')
            ->paginate($request->get('per_page', 15));

        return OrderResource::collection($orders);
    }

    public function show(Order $order): OrderResource
    {
        // Check authorization
        $user = request()->user();
        if ($user && $user->isCustomer() && $order->user_id !== $user->id) {
            return response()->json([
                'message' => 'Unauthorized',
            ], 403);
        }

        $order->load(['items.product', 'items.variant', 'payments']);
        $ratings = ProductRating::where('order_id', $order->id)->get()->keyBy('product_id');
        foreach ($order->items as $item) {
            $item->setRelation('productRating', $ratings->get($item->product_id));
        }

        return new OrderResource($order);
    }

    public function checkout(CheckoutRequest $request): JsonResponse
    {
        $user = $request->user();

        // Get cart
        $cart = $user
            ? Cart::where('user_id', $user->id)->first()
            : Cart::where('guest_uuid', $request->cookie('guest_uuid'))
                ->orWhere('session_id', $request->session()->getId())
                ->first();

        if (! $cart || $cart->isEmpty()) {
            return response()->json([
                'message' => 'Cart is empty',
            ], 422);
        }

        // Validate cart items
        foreach ($cart->items as $item) {
            if ($item->variant) {
                if (! $item->variant->isInStock($item->quantity)) {
                    return response()->json([
                        'message' => "Insufficient stock for {$item->product->name} ({$item->variant->name})",
                    ], 422);
                }
            }
        }

        $subtotal = $cart->subtotal;
        $discount = 0;
        $coupon = null;
        $couponCode = trim((string) $request->input('coupon_code', ''));
        if ($couponCode !== '') {
            $coupon = Coupon::where('code', $couponCode)->first();
            if ($coupon && $coupon->isValid() && $subtotal >= $coupon->minimum_order_amount) {
                $discount = $coupon->calculateDiscount($subtotal);
            }
        }
        $total = max(0, $subtotal - $discount);

        DB::beginTransaction();

        try {
            // Create order
            $order = Order::create([
                'user_id' => $user?->id,
                'status' => 'pending',
                'subtotal' => $subtotal,
                'tax' => 0,
                'shipping' => 0,
                'discount' => $discount,
                'total' => $total,
                'currency' => 'USD',
                'coupon_id' => $coupon?->id,
                'shipping_name' => $request->shipping_name,
                'shipping_email' => $request->shipping_email,
                'shipping_phone' => $request->shipping_phone,
                'shipping_address' => $request->shipping_address,
                'shipping_city' => $request->shipping_city,
                'shipping_state' => $request->shipping_state,
                'shipping_postal_code' => $request->shipping_postal_code,
                'shipping_country' => $request->shipping_country,
                'notes' => $request->notes,
            ]);

            // Create order items
            foreach ($cart->items as $cartItem) {
                OrderItem::create([
                    'order_id' => $order->id,
                    'product_id' => $cartItem->product_id,
                    'product_variant_id' => $cartItem->product_variant_id,
                    'product_name' => $cartItem->product->name,
                    'variant_name' => $cartItem->variant?->name,
                    'sku' => $cartItem->variant?->sku ?? $cartItem->product->sku,
                    'quantity' => $cartItem->quantity,
                    'price' => $cartItem->price,
                    'subtotal' => $cartItem->subtotal,
                ]);

                // Update stock
                if ($cartItem->variant) {
                    $cartItem->variant->decrement('stock_quantity', $cartItem->quantity);
                }
            }

            // Clear cart
            $cart->clear();

            if ($coupon) {
                $coupon->incrementUsage();
            }

            DB::commit();

            $order->load(['items', 'payments']);

            return response()->json([
                'message' => 'Order created successfully',
                'data' => new OrderResource($order),
            ], 201);
        } catch (\Exception $e) {
            DB::rollBack();

            return response()->json([
                'message' => 'Failed to create order',
                'error' => $e->getMessage(),
            ], 500);
        }
    }

    public function cancel(Request $request, Order $order): JsonResponse
    {
        // Check authorization
        $user = $request->user();
        if ($user && $user->isCustomer() && $order->user_id !== $user->id) {
            return response()->json([
                'message' => 'Unauthorized',
            ], 403);
        }

        if (! $order->canBeCancelled()) {
            return response()->json([
                'message' => 'Order cannot be cancelled',
            ], 422);
        }

        DB::beginTransaction();

        try {
            $order->update([
                'status' => 'cancelled',
                'cancelled_at' => now(),
            ]);

            // Restore stock
            foreach ($order->items as $item) {
                if ($item->product_variant_id) {
                    $variant = \App\Models\ProductVariant::find($item->product_variant_id);
                    if ($variant) {
                        $variant->increment('stock_quantity', $item->quantity);
                    }
                }
            }

            DB::commit();

            return response()->json([
                'message' => 'Order cancelled successfully',
                'data' => new OrderResource($order->load(['items', 'payments'])),
            ]);
        } catch (\Exception $e) {
            DB::rollBack();

            return response()->json([
                'message' => 'Failed to cancel order',
                'error' => $e->getMessage(),
            ], 500);
        }
    }

    public function reorder(Request $request, Order $order): JsonResponse
    {
        $user = $request->user();
        if (! $user || $order->user_id !== $user->id) {
            return response()->json(['message' => 'Unauthorized'], 403);
        }

        if ($order->items->isEmpty()) {
            return response()->json(['message' => 'Order has no items to reorder'], 422);
        }

        $cart = Cart::firstOrCreate(
            ['user_id' => $user->id],
            ['expires_at' => now()->addDays(30)]
        );

        $order->load('items.product', 'items.variant');
        $added = 0;
        $errors = [];

        foreach ($order->items as $item) {
            if (! $item->product || ! $item->product->is_active) {
                $errors[] = "{$item->product_name} is no longer available.";
                continue;
            }
            $variant = $item->product_variant_id ? $item->variant : null;
            if ($variant && ! $variant->is_active) {
                $errors[] = "{$item->product_name} ({$item->variant_name}) is no longer available.";
                continue;
            }
            $qty = (int) $item->quantity;
            if ($qty < 1) {
                continue;
            }
            if ($variant && ! $variant->isInStock($qty)) {
                $errors[] = "Insufficient stock for {$item->product_name}. Available: {$variant->stock_quantity}";
                continue;
            }
            $existing = $cart->items()
                ->where('product_id', $item->product_id)
                ->where('product_variant_id', $item->product_variant_id)
                ->first();
            if ($existing) {
                $newQty = $existing->quantity + $qty;
                if ($variant && ! $variant->isInStock($newQty)) {
                    $errors[] = "Insufficient stock for {$item->product_name}. Available: {$variant->stock_quantity}";
                    continue;
                }
                $existing->update(['quantity' => $newQty]);
            } else {
                $price = $variant ? $variant->price : $item->product->base_price;
                $cart->items()->create([
                    'product_id' => $item->product_id,
                    'product_variant_id' => $item->product_variant_id,
                    'quantity' => $qty,
                    'price' => $price,
                ]);
            }
            $added++;
        }

        $cart->load(['items.product.images', 'items.variant']);

        return response()->json([
            'message' => $added > 0 ? 'Items added to cart' : 'No items could be added',
            'added_count' => $added,
            'errors' => $errors,
            'data' => new CartResource($cart),
        ], $added > 0 ? 200 : 422);
    }

    public function rate(RateOrderRequest $request, Order $order): JsonResponse
    {
        $user = $request->user();
        if (! $user || $order->user_id !== $user->id) {
            return response()->json(['message' => 'Unauthorized'], 403);
        }

        $completed = in_array($order->status, ['delivered', 'paid'], true);
        if (! $completed) {
            return response()->json([
                'message' => 'You can only rate delivered or completed orders',
            ], 422);
        }

        $rating = (int) $request->input('rating');
        $reviewText = $request->input('review_text');

        $order->update([
            'rating' => $rating,
            'review_text' => $reviewText ? trim($reviewText) : null,
        ]);

        foreach ($order->items as $item) {
            ProductRating::updateOrCreate(
                [
                    'order_id' => $order->id,
                    'product_id' => $item->product_id,
                ],
                [
                    'rating' => $rating,
                    'review_text' => $reviewText ? trim($reviewText) : null,
                ]
            );
        }

        $order->load(['items.product', 'items.variant', 'payments']);
        $ratings = ProductRating::where('order_id', $order->id)->get()->keyBy('product_id');
        foreach ($order->items as $item) {
            $item->setRelation('productRating', $ratings->get($item->product_id));
        }

        return response()->json([
            'message' => 'Thank you for your rating!',
            'data' => new OrderResource($order),
        ]);
    }

    public function rateItem(RateOrderItemRequest $request, Order $order): JsonResponse
    {
        $user = $request->user();
        if (! $user || $order->user_id !== $user->id) {
            return response()->json(['message' => 'Unauthorized'], 403);
        }

        $completed = in_array($order->status, ['delivered', 'paid'], true);
        if (! $completed) {
            return response()->json([
                'message' => 'You can only rate products from delivered or completed orders',
            ], 422);
        }

        $orderItemId = (int) $request->input('order_item_id');
        $orderItem = $order->items()->find($orderItemId);
        if (! $orderItem) {
            return response()->json(['message' => 'Order item not found'], 404);
        }

        $rating = (int) $request->input('rating');
        $reviewText = $request->input('review_text');

        ProductRating::updateOrCreate(
            [
                'order_id' => $order->id,
                'product_id' => $orderItem->product_id,
            ],
            [
                'rating' => $rating,
                'review_text' => $reviewText ? trim($reviewText) : null,
            ]
        );

        $order->load(['items.product', 'items.variant', 'payments']);
        $ratings = ProductRating::where('order_id', $order->id)->get()->keyBy('product_id');
        foreach ($order->items as $item) {
            $item->setRelation('productRating', $ratings->get($item->product_id));
        }

        return response()->json([
            'message' => 'Thank you for your review!',
            'data' => new OrderResource($order),
        ]);
    }

    public function invoice(Order $order): JsonResponse
    {
        $user = request()->user();
        if (! $user || $order->user_id !== $user->id) {
            return response()->json(['message' => 'Unauthorized'], 403);
        }

        $order->load('items');
        $symbol = Setting::get('currency_symbol', '$');
        $storeName = Setting::get('store_name', config('app.name'));

        return response()->json([
            'data' => [
                'order' => new OrderResource($order),
                'store_name' => $storeName,
                'currency_symbol' => $symbol,
            ],
        ]);
    }
}
