<?php

class OrderController extends Controller
{
    private array $statusFlow = ['PENDING', 'CONFIRMED', 'PREPARING', 'READY', 'OUT_FOR_DELIVERY', 'COMPLETED'];

    public function index(): void
    {
        Auth::requirePermission('orders', 'view');

        $status = $this->input('status', 'ALL');
        $search = trim($this->input('search', ''));

        $orderModel = new Order();
        $orders = $orderModel->listWithFilters($status, $search);

        $this->view('orders.index', [
            'pageTitle'    => 'Orders',
            'orders'       => $orders,
            'activeStatus' => $status,
            'search'       => $search,
            'statusCounts' => $orderModel->statusCounts(),
            'todayStats'   => $orderModel->todayStats(),
        ]);
    }

    public function create(): void
    {
        Auth::requirePermission('orders', 'add');

        $menuItemModel = new MenuItem();
        $deliveryZoneModel = new DeliveryZone();
        $deliveryModel = new Delivery();
        $db = Database::getConnection();
        $paymentMethods = $db->query("SELECT * FROM payment_methods WHERE is_active = 1")->fetchAll();

        $this->view('orders.create', [
            'pageTitle'      => 'New Order',
            'menuByCategory' => $menuItemModel->getMenuForPos(),
            'zones'          => $deliveryZoneModel->activeZones(),
            'paymentMethods' => $paymentMethods,
            'riders'         => $deliveryModel->activeRiders(),
            'csrf'           => $this->csrfField(),
        ]);
    }

    public function store(): void
    {
        Auth::requirePermission('orders', 'add');
        $this->verifyCsrf();

        $cartJson = $this->input('cart_json', '[]');
        $cart = json_decode($cartJson, true);

        if (!is_array($cart) || count($cart) === 0) {
            $this->redirect('orders/create');
            return;
        }

        $orderType = $this->input('order_type', 'DINE_IN');
        $orderSource = $this->input('order_source', '') ?: null;
        $customerPhone = trim($this->input('customer_phone', ''));
        $customerName  = trim($this->input('customer_name', ''));
        $deliveryAddress = trim($this->input('delivery_address', ''));
        $deliveryZoneId = (int) $this->input('delivery_zone_id', 0) ?: null;
        $notes = trim($this->input('notes', ''));

        $menuItemModel = new MenuItem();
        $customerModel = new Customer();
        $deliveryZoneModel = new DeliveryZone();

        // Build validated line items server-side (never trust client-submitted prices)
        $items = [];
        $subtotal = 0.0;
        foreach ($cart as $line) {
            $menuItemId = (int) ($line['menu_item_id'] ?? 0);
            $variantId  = (int) ($line['variant_id'] ?? 0) ?: null;
            $qty        = max(1, (int) ($line['quantity'] ?? 1));
            if ($menuItemId <= 0) {
                continue;
            }
            $resolved = $menuItemModel->findWithVariant($menuItemId, $variantId);
            $name = $resolved['item']['item_name'] . ($resolved['variant_name'] ? ' (' . $resolved['variant_name'] . ')' : '');
            $items[] = [
                'menu_item_id' => $menuItemId,
                'variant_id'   => $variantId,
                'name'         => $name,
                'unit_price'   => $resolved['unit_price'],
                'quantity'     => $qty,
            ];
            $subtotal += $resolved['unit_price'] * $qty;
        }

        if (count($items) === 0) {
            $this->redirect('orders/create');
            return;
        }

        // Delivery fee from zone (only relevant for ONLINE_DELIVERY)
        $deliveryFee = 0.0;
        $customerId = null;
        if ($orderType === 'ONLINE_DELIVERY') {
            if ($deliveryZoneId) {
                $zone = $deliveryZoneModel->find($deliveryZoneId);
                if ($zone) {
                    $deliveryFee = $zone['is_free_delivery'] ? 0.0 : (float) $zone['delivery_fee'];
                }
            }
            if ($customerPhone !== '') {
                $customerId = $customerModel->findOrCreate($customerPhone, $customerName, $deliveryAddress);
            }
        } elseif ($customerPhone !== '') {
            $customerId = $customerModel->findOrCreate($customerPhone, $customerName);
        }

        $total = $subtotal + $deliveryFee;

        $orderModel = new Order();
        $orderId = $orderModel->createWithItems([
            'order_type'        => $orderType,
            'order_source'      => $orderSource,
            'customer_id'       => $customerId,
            'delivery_zone_id'  => $orderType === 'ONLINE_DELIVERY' ? $deliveryZoneId : null,
            'status'            => 'PENDING',
            'subtotal'          => $subtotal,
            'delivery_fee'      => $deliveryFee,
            'discount'          => 0,
            'total_amount'      => $total,
            'delivery_address'  => $orderType === 'ONLINE_DELIVERY' ? $deliveryAddress : null,
            'notes'             => $notes ?: null,
            'created_by'        => Auth::id(),
        ], $items);

        // Optional: settle payment immediately (walk-in / takeaway style checkout)
        $paymentMethodId = (int) $this->input('payment_method_id', 0);
        $amountCollected = (float) $this->input('amount_collected', 0);
        if ($paymentMethodId > 0 && $amountCollected > 0) {
            $orderModel->recordPayment($orderId, $paymentMethodId, $amountCollected, Auth::id());
        }

        AuditLogger::log(Auth::id(), 'ORDER_CREATE', 'orders', "Created order #{$orderId} ({$orderType}), total " . formatMoney($total));

        // Optional: assign a delivery rider right away, instead of waiting until the order is Ready
        $riderId = (int) $this->input('rider_id', 0);
        if ($orderType === 'ONLINE_DELIVERY' && $riderId > 0) {
            (new Delivery())->createAndAssign($orderId, $riderId, Auth::id());
        }

        $this->redirect('orders/show?id=' . $orderId);
    }

    public function label(): void
    {
        Auth::requirePermission('orders', 'view');
        $id = (int) $this->input('id');

        $orderModel = new Order();
        $order = $orderModel->findWithDetails($id);
        if (!$order) {
            $this->redirect('orders');
            return;
        }

        $this->view('orders.label', [
            'pageTitle' => 'Order Label — ' . $order['order_number'],
            'order'     => $order,
        ], null); // standalone print layout, no sidebar
    }

    public function show(): void
    {
        Auth::requirePermission('orders', 'view');
        $id = (int) $this->input('id');

        $orderModel = new Order();
        $order = $orderModel->findWithDetails($id);
        if (!$order) {
            $this->redirect('orders');
            return;
        }

        $db = Database::getConnection();
        $paymentMethods = $db->query("SELECT * FROM payment_methods WHERE is_active = 1")->fetchAll();
        $totalPaid = $orderModel->totalPaid($id);

        $userModel = new User();
        $activeRiders = array_values(array_filter($userModel->ridersWithStats(), fn($r) => (int) $r['is_active'] === 1));

        $this->view('orders.show', [
            'pageTitle'      => 'Order ' . $order['order_number'],
            'order'          => $order,
            'statusFlow'     => $this->statusFlow,
            'paymentMethods' => $paymentMethods,
            'totalPaid'      => $totalPaid,
            'balanceDue'     => max(0, (float) $order['total_amount'] - $totalPaid),
            'activeRiders'   => $activeRiders,
            'csrf'           => $this->csrfField(),
        ]);
    }

    public function assignRider(): void
    {
        Auth::requirePermission('delivery', 'edit');
        $this->verifyCsrf();

        $orderId = (int) $this->input('order_id');
        $riderId = (int) $this->input('rider_id');

        if ($orderId > 0 && $riderId > 0) {
            (new Delivery())->createAndAssign($orderId, $riderId, Auth::id());
            AuditLogger::log(Auth::id(), 'DELIVERY_RIDER_ASSIGN', 'orders', "Rider #{$riderId} assigned to order #{$orderId}");
        }
        $this->redirect('orders/show?id=' . $orderId);
    }

    public function updateStatus(): void
    {
        Auth::requirePermission('orders', 'edit');
        $this->verifyCsrf();

        $id = (int) $this->input('id');
        $status = $this->input('status', '');
        if (!in_array($status, $this->statusFlow, true)) {
            $this->redirect('orders/show?id=' . $id);
            return;
        }

        $orderModel = new Order();

        if ($status === 'OUT_FOR_DELIVERY') {
            $existingOrder = $orderModel->find($id);
            if ($existingOrder && $existingOrder['order_type'] === 'ONLINE_DELIVERY') {
                AuditLogger::log(Auth::id(), 'ORDER_STATUS_UPDATE_BLOCKED', 'orders', "Manual attempt to set order #{$id} to OUT_FOR_DELIVERY was blocked — this must happen via rider QR scan");
                $this->redirect('orders/show?id=' . $id);
                return;
            }
        }

        $orderModel->updateStatus($id, $status, Auth::id());
        AuditLogger::log(Auth::id(), 'ORDER_STATUS_UPDATE', 'orders', "Order #{$id} -> {$status}");

        $redirectSuffix = $status === 'READY' ? '&justReady=1' : '';
        $this->redirect('orders/show?id=' . $id . $redirectSuffix);
    }

    public function cancel(): void
    {
        Auth::requirePermission('orders', 'edit');
        $this->verifyCsrf();

        $id = (int) $this->input('id');
        $orderModel = new Order();
        $orderModel->cancelAndRestock($id, Auth::id());
        AuditLogger::log(Auth::id(), 'ORDER_CANCEL', 'orders', "Order #{$id} cancelled, stock restored");

        $this->redirect('orders/show?id=' . $id);
    }

    public function recordPayment(): void
    {
        Auth::requirePermission('payments', 'add');
        $this->verifyCsrf();

        $id = (int) $this->input('id');
        $methodId = (int) $this->input('payment_method_id');
        $amount = (float) $this->input('amount', 0);

        if ($amount > 0 && $methodId > 0) {
            $orderModel = new Order();
            $orderModel->recordPayment($id, $methodId, $amount, Auth::id());
            AuditLogger::log(Auth::id(), 'PAYMENT_RECORD', 'payments', "Payment " . formatMoney($amount) . " for order #{$id}");
        }

        $this->redirect('orders/show?id=' . $id);
    }
}
