<?php

namespace App\Http\Controllers\Api\Pos;

use App\Http\Controllers\Controller;
use App\Models\Order;
use App\Models\OrderItem;
use App\Models\Product;
use App\Models\StockMovement;
use App\Models\VariantStockMovement;
use App\Models\User;
use App\Services\OrderPlacementNotificationService;
use App\Services\ProfitService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;

class SyncController extends Controller
{
    protected ProfitService $profitService;

    public function __construct(ProfitService $profitService)
    {
        $this->profitService = $profitService;
    }
    /**
     * Sync queued offline orders
     */
    public function sync(Request $request): JsonResponse
    {
        $validator = Validator::make($request->all(), [
            'orders' => 'required|array',
            'orders.*.user_id' => 'required|exists:users,id',
            'orders.*.salesman_id' => 'nullable|exists:users,id',
            'orders.*.items' => 'required|array|min:1',
            'orders.*.items.*.product_id' => 'required|exists:products,id',
            'orders.*.items.*.qty' => 'required|integer|min:1',
            'orders.*.items.*.price' => 'required|numeric|min:0',
            'orders.*.payment_method' => 'nullable|string|in:cash,card,offline,card_upi,card/upi,upi,online,digital_wallet,cod',
            'orders.*.cash_amount' => 'nullable|numeric|min:0',
            'orders.*.card_amount' => 'nullable|numeric|min:0',
            'orders.*.payment_screenshot_path' => 'nullable|string|max:500',
            'orders.*.subtotal' => 'required|numeric|min:0',
            'orders.*.discount_total' => 'nullable|numeric|min:0',
            'orders.*.total_payable' => 'required|numeric|min:0',
            'orders.*.created_at' => 'nullable|date',
        ]);

        if ($validator->fails()) {
            return response()->json([
                'success' => false,
                'message' => 'Validation failed',
                'errors' => $validator->errors(),
            ], 422);
        }

        $syncedOrders = [];
        $failedOrders = [];

        foreach ($request->orders as $orderData) {
            try {
                DB::beginTransaction();

                $orderData['payment_method'] = $this->normalizePosPaymentMethod($orderData['payment_method'] ?? null);

                $user = User::findOrFail($orderData['user_id']);
                $isStaff = $user->isAdmin() || $user->isStaff();
                
                if ($isStaff) {
                    $failedOrders[] = [
                        'data' => $orderData,
                        'error' => 'Cannot create order for staff/admin user',
                    ];
                    continue;
                }

                $isOfflinePayment = ($orderData['payment_method'] ?? '') === 'offline';
                $cashAmount = $orderData['cash_amount'] ?? 0;
                $cardAmount = $orderData['card_amount'] ?? 0;
                $totalPayable = $orderData['total_payable'];

                if (! $isOfflinePayment) {
                    if ($cashAmount == 0 && $cardAmount == 0) {
                        throw new \Exception('At least one payment amount (cash or card) must be provided');
                    }
                    $totalPaid = $cashAmount + $cardAmount;
                    if ($totalPaid < $totalPayable) {
                        throw new \Exception('Total payment amount is less than total payable amount');
                    }
                } else {
                    $cashAmount = 0;
                    $cardAmount = 0;
                }

                $paymentMethod = null;
                if ($isOfflinePayment) {
                    $finalPaymentMethod = 'offline';
                } else {
                    if ($cashAmount > 0 && $cardAmount > 0) {
                        $paymentMethod = 'card';
                    } elseif ($cashAmount > 0) {
                        $paymentMethod = 'cash';
                    } elseif ($cardAmount > 0) {
                        $paymentMethod = 'card';
                    }
                    $finalPaymentMethod = $this->normalizePosPaymentMethod($orderData['payment_method'] ?? $paymentMethod);
                }

                $order = Order::create([
                    'user_id' => $user->id,
                    'staff_id' => $orderData['salesman_id'] ?? auth()->id(),
                    'source' => 'pos',
                    'address_snapshot' => [
                        'name' => $user->name,
                        'mobile' => $user->mobile,
                        'email' => $user->email ?? '',
                    ],
                    'subtotal' => $orderData['subtotal'],
                    'discount_total' => $orderData['discount_total'] ?? 0,
                    'tax_total' => $orderData['tax_total'] ?? 0,
                    'shipping_total' => 0,
                    'total_payable' => $orderData['total_payable'],
                    'payment_status' => Order::PAYMENT_PAID,
                    'payment_method' => $finalPaymentMethod,
                    'cash_amount' => $cashAmount > 0 ? $cashAmount : null,
                    'card_amount' => $cardAmount > 0 ? $cardAmount : null,
                    'payment_screenshot_path' => $orderData['payment_screenshot_path'] ?? null,
                    'status' => Order::STATUS_CONFIRMED,
                    'placed_at' => isset($orderData['created_at']) ? $orderData['created_at'] : now(),
                    'created_at' => isset($orderData['created_at']) ? $orderData['created_at'] : now(),
                ]);

                // Process items and prepare for profit service
                $cartItems = [];
                foreach ($orderData['items'] as $item) {
                    // Unified model: product_id is the actual sellable product
                    $product = Product::lockForUpdate()->findOrFail($item['product_id']);

                    // Check product stock (unified logic)
                    if ($product->current_stock < $item['qty']) {
                        throw new \Exception("Insufficient stock for product: {$product->name}. Available: {$product->current_stock}, Requested: {$item['qty']}");
                    }

                    // Create stock movement (use VariantStockMovement for all products)
                    VariantStockMovement::create([
                        'product_id' => $product->id,
                        'type' => VariantStockMovement::TYPE_SALE,
                        'quantity' => -$item['qty'],
                        'notes' => "POS Order #{$order->id} (Synced)",
                        'created_by' => auth()->id(),
                    ]);

                    // Recalculate stock
                    $product->recalculateStock();

                    // Prepare cart item data for profit service
                    $cartItemData = [
                        'product_id' => $item['product_id'],
                        'qty' => $item['qty'],
                        'price' => $item['price'],
                    ];

                    $cartItems[] = $cartItemData;
                }

                // Use ProfitService to create order items with profit calculations and tax calculation
                $this->profitService->allocateOrderCosts($order, $cartItems);
                
                // Refresh order to get calculated tax_total
                $order->refresh();
                
                // Recalculate total_payable
                // Prices are tax-inclusive, so total = subtotal - discount + shipping
                $order->update([
                    'total_payable' => $order->subtotal - $order->discount_total + $order->shipping_total
                ]);
                
                // Calculate and store change amount
                // Change = total paid - total payable (only if total paid > total payable)
                $totalPaid = $cashAmount + $cardAmount;
                $changeAmount = 0;
                if ($totalPaid > $order->total_payable) {
                    $changeAmount = $totalPaid - $order->total_payable;
                }
                $order->update([
                    'change_amount' => $changeAmount
                ]);

                DB::commit();

                app(OrderPlacementNotificationService::class)->dispatchAfterPlacement($order, OrderPlacementNotificationService::CHANNEL_POS);

                $syncedOrders[] = [
                    'order_id' => $order->id,
                    'order_number' => '#' . str_pad($order->id, 6, '0', STR_PAD_LEFT),
                ];
            } catch (\Exception $e) {
                DB::rollBack();
                $failedOrders[] = [
                    'data' => $orderData,
                    'error' => $e->getMessage(),
                ];
            }
        }

        return response()->json([
            'success' => true,
            'synced' => count($syncedOrders),
            'failed' => count($failedOrders),
            'synced_orders' => $syncedOrders,
            'failed_orders' => $failedOrders,
        ]);
    }

    private function normalizePosPaymentMethod(?string $paymentMethod): ?string
    {
        if ($paymentMethod === null || $paymentMethod === '') {
            return $paymentMethod;
        }

        return match (strtolower(trim($paymentMethod))) {
            'cash', 'cod' => 'cash',
            'card', 'card_upi', 'card/upi', 'upi', 'online', 'digital_wallet' => 'card',
            'offline' => 'offline',
            default => $paymentMethod,
        };
    }
}
