<?php

class Delivery extends Model
{
    protected string $table = 'deliveries';

    public function board(): array
    {
        $sql = "SELECT d.*, o.order_number, o.total_amount, o.delivery_address, o.status as order_status,
                       c.full_name as customer_name, c.phone as customer_phone,
                       dz.zone_name, u.full_name as rider_name
                FROM deliveries d
                JOIN orders o ON o.id = d.order_id
                LEFT JOIN customers c ON c.id = o.customer_id
                LEFT JOIN delivery_zones dz ON dz.id = o.delivery_zone_id
                LEFT JOIN users u ON u.id = d.rider_id
                WHERE d.status != 'DELIVERED' OR DATE(d.delivered_at) = CURDATE()
                ORDER BY d.id DESC";
        $rows = $this->db->query($sql)->fetchAll();

        $board = ['UNASSIGNED' => [], 'ASSIGNED' => [], 'PICKED_UP' => [], 'DELIVERED' => [], 'FAILED' => []];
        foreach ($rows as $row) {
            $board[$row['status']][] = $row;
        }
        return $board;
    }

    public function activeRiders(): array
    {
        return $this->db->query(
            "SELECT u.id, u.full_name,
                    (SELECT COUNT(*) FROM deliveries d WHERE d.rider_id = u.id AND d.status IN ('ASSIGNED','PICKED_UP')) as active_count
             FROM users u JOIN roles r ON r.id = u.role_id
             WHERE r.role_name = 'RIDER' AND u.is_active = 1
             ORDER BY u.full_name ASC"
        )->fetchAll();
    }

    public function delayedCount(int $minutesThreshold = 15): int
    {
        $stmt = $this->db->prepare(
            "SELECT COUNT(*) as cnt FROM deliveries
             WHERE status = 'ASSIGNED' AND assigned_at IS NOT NULL
               AND TIMESTAMPDIFF(MINUTE, assigned_at, NOW()) > :mins"
        );
        $stmt->execute(['mins' => $minutesThreshold]);
        return (int) $stmt->fetch()['cnt'];
    }

    public function historyForRider(int $riderId, int $limit = 50): array
    {
        $stmt = $this->db->prepare(
            "SELECT d.*, o.order_number, o.total_amount, o.delivery_address,
                    c.full_name as customer_name, c.phone as customer_phone,
                    dz.zone_name
             FROM deliveries d
             JOIN orders o ON o.id = d.order_id
             LEFT JOIN customers c ON c.id = o.customer_id
             LEFT JOIN delivery_zones dz ON dz.id = o.delivery_zone_id
             WHERE d.rider_id = :rider_id
             ORDER BY d.id DESC
             LIMIT " . (int) $limit
        );
        $stmt->execute(['rider_id' => $riderId]);
        return $stmt->fetchAll();
    }

    public function assignRider(int $deliveryId, int $riderId, ?int $userId): void
    {
        $this->update($deliveryId, [
            'rider_id'    => $riderId,
            'status'      => 'ASSIGNED',
            'assigned_at' => date('Y-m-d H:i:s'),
        ]);
        AuditLogger::log($userId, 'DELIVERY_ASSIGN', 'delivery', "Delivery #{$deliveryId} assigned to rider #{$riderId}");
    }

    // Used when a rider is picked at order-creation time, before the order even reaches READY
    public function createAndAssign(int $orderId, int $riderId, ?int $userId): void
    {
        $exists = $this->db->prepare("SELECT id FROM deliveries WHERE order_id = :id");
        $exists->execute(['id' => $orderId]);
        $existing = $exists->fetch();

        if ($existing) {
            $this->assignRider((int) $existing['id'], $riderId, $userId);
            return;
        }

        $this->insert([
            'order_id'    => $orderId,
            'rider_id'    => $riderId,
            'status'      => 'ASSIGNED',
            'assigned_at' => date('Y-m-d H:i:s'),
        ]);
        AuditLogger::log($userId, 'DELIVERY_ASSIGN', 'delivery', "Order #{$orderId} - rider assigned at order creation");
    }

    public function claimAndPickup(int $orderId, int $riderId): array
    {
        $orderModel = new Order();
        $order = $orderModel->find($orderId);
        if (!$order) {
            return ['success' => false, 'message' => 'Order not found.'];
        }
        if ($order['order_type'] !== 'ONLINE_DELIVERY') {
            return ['success' => false, 'message' => 'This order is not a delivery order.'];
        }
        if ($order['status'] !== 'READY') {
            return ['success' => false, 'message' => 'This order is not ready for pickup yet (current status: ' . $order['status'] . ').'];
        }

        $existing = $this->db->prepare("SELECT * FROM deliveries WHERE order_id = :id");
        $existing->execute(['id' => $orderId]);
        $delivery = $existing->fetch();

        if (!$delivery) {
            return ['success' => false, 'message' => 'This order hasn\'t been assigned to a rider yet — ask an admin to assign it to you first.'];
        }
        if ((int) $delivery['rider_id'] !== $riderId) {
            return ['success' => false, 'message' => 'This order is assigned to a different rider. Please check with your admin.'];
        }
        if (in_array($delivery['status'], ['PICKED_UP', 'DELIVERED', 'FAILED'], true)) {
            return ['success' => false, 'message' => 'This order has already been picked up.'];
        }

        $this->update((int) $delivery['id'], [
            'status'       => 'PICKED_UP',
            'picked_up_at' => date('Y-m-d H:i:s'),
        ]);

        $orderModel->updateStatus($orderId, 'OUT_FOR_DELIVERY', null);
        AuditLogger::log(null, 'DELIVERY_SELF_CLAIM', 'delivery', "Rider #{$riderId} scanned QR and confirmed pickup of assigned order #{$orderId} — status set to OUT_FOR_DELIVERY");

        return ['success' => true, 'message' => 'Order picked up — status updated to On the Way.'];
    }

    public function markPickedUp(int $deliveryId, ?int $userId): void
    {
        $delivery = $this->find($deliveryId);
        if (!$delivery) {
            return;
        }
        $this->update($deliveryId, ['status' => 'PICKED_UP', 'picked_up_at' => date('Y-m-d H:i:s')]);

        $orderModel = new Order();
        $orderModel->updateStatus((int) $delivery['order_id'], 'OUT_FOR_DELIVERY', $userId);

        AuditLogger::log($userId, 'DELIVERY_PICKED_UP', 'delivery', "Delivery #{$deliveryId} picked up");
    }

    public function markDelivered(int $deliveryId, ?int $userId): void
    {
        $delivery = $this->find($deliveryId);
        if (!$delivery) {
            return;
        }
        $this->update($deliveryId, ['status' => 'DELIVERED', 'delivered_at' => date('Y-m-d H:i:s')]);

        $orderModel = new Order();
        $orderModel->updateStatus((int) $delivery['order_id'], 'COMPLETED', $userId);

        AuditLogger::log($userId, 'DELIVERY_DELIVERED', 'delivery', "Delivery #{$deliveryId} delivered");
    }

    public function markFailed(int $deliveryId, string $notes, ?int $userId): void
    {
        $this->update($deliveryId, ['status' => 'FAILED', 'notes' => $notes]);
        AuditLogger::log($userId, 'DELIVERY_FAILED', 'delivery', "Delivery #{$deliveryId} failed: {$notes}");
    }
}
