<?php

// JSON API powering the rider's delivery management in the Rider App.
// All actions require an active rider session (set by RiderAuthController::login).
class RiderApiController extends Controller
{
    private function requireRider(): ?int
    {
        if (empty($_SESSION['rider_id'])) {
            $this->json(['success' => false, 'message' => 'Please log in.'], 401);
            return null;
        }
        return (int) $_SESSION['rider_id'];
    }

    private function jsonInput(): array
    {
        $raw = file_get_contents('php://input');
        $data = json_decode($raw, true);
        return is_array($data) ? $data : [];
    }

    public function myDeliveries(): void
    {
        $riderId = $this->requireRider();
        if ($riderId === null) {
            return;
        }

        $db = Database::getConnection();
        $stmt = $db->prepare(
            "SELECT d.*, o.order_number, o.total_amount, o.delivery_address, o.notes as order_notes,
                    c.full_name as customer_name, c.phone as customer_phone,
                    dz.zone_name,
                    (SELECT COUNT(*) FROM order_items oi WHERE oi.order_id = o.id) as item_count,
                    (SELECT COALESCE(SUM(p.amount),0) FROM payments p WHERE p.order_id = o.id AND p.status='PAID') as total_paid
             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 AND d.status IN ('ASSIGNED', 'PICKED_UP')
             ORDER BY d.assigned_at ASC"
        );
        $stmt->execute(['rider_id' => $riderId]);
        $rows = $stmt->fetchAll();

        $this->json(['success' => true, 'deliveries' => array_map([$this, 'formatDelivery'], $rows)]);
    }

    public function history(): void
    {
        $riderId = $this->requireRider();
        if ($riderId === null) {
            return;
        }

        $db = Database::getConnection();
        $stmt = $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,
                    (SELECT COUNT(*) FROM order_items oi WHERE oi.order_id = o.id) as item_count,
                    0 as total_paid
             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 AND d.status IN ('DELIVERED', 'FAILED')
             ORDER BY d.id DESC LIMIT 50"
        );
        $stmt->execute(['rider_id' => $riderId]);
        $rows = $stmt->fetchAll();

        $this->json(['success' => true, 'deliveries' => array_map([$this, 'formatDelivery'], $rows)]);
    }

    public function stats(): void
    {
        $riderId = $this->requireRider();
        if ($riderId === null) {
            return;
        }

        $db = Database::getConnection();
        $stmt = $db->prepare(
            "SELECT
                (SELECT COUNT(*) FROM deliveries WHERE rider_id = :r1 AND status IN ('ASSIGNED','PICKED_UP')) as active_count,
                (SELECT COUNT(*) FROM deliveries WHERE rider_id = :r2 AND status = 'DELIVERED' AND DATE(delivered_at) = CURDATE()) as delivered_today,
                (SELECT COUNT(*) FROM deliveries WHERE rider_id = :r3 AND status = 'DELIVERED') as delivered_total"
        );
        $stmt->execute(['r1' => $riderId, 'r2' => $riderId, 'r3' => $riderId]);
        $stats = $stmt->fetch();

        $this->json([
            'success' => true,
            'stats' => [
                'active_count'    => (int) $stats['active_count'],
                'delivered_today' => (int) $stats['delivered_today'],
                'delivered_total' => (int) $stats['delivered_total'],
            ],
        ]);
    }

    public function claimAndPickup(): void
    {
        $riderId = $this->requireRider();
        if ($riderId === null) {
            return;
        }
        $orderNumber = trim($this->jsonInput()['order_number'] ?? '');
        if ($orderNumber === '') {
            $this->json(['success' => false, 'message' => 'Missing order number.'], 422);
            return;
        }

        $db = Database::getConnection();
        $stmt = $db->prepare("SELECT id FROM orders WHERE order_number = :num LIMIT 1");
        $stmt->execute(['num' => $orderNumber]);
        $row = $stmt->fetch();
        if (!$row) {
            $this->json(['success' => false, 'message' => 'Order not found.'], 404);
            return;
        }

        $result = (new Delivery())->claimAndPickup((int) $row['id'], $riderId);
        $this->json($result, $result['success'] ? 200 : 422);
    }

    public function pickedUp(): void
    {
        $riderId = $this->requireRider();
        if ($riderId === null) {
            return;
        }
        $deliveryId = (int) ($this->jsonInput()['delivery_id'] ?? 0);
        if (!$this->ownsDelivery($deliveryId, $riderId)) {
            $this->json(['success' => false, 'message' => 'Delivery not found.'], 404);
            return;
        }

        (new Delivery())->markPickedUp($deliveryId, null);
        $this->json(['success' => true]);
    }

    public function delivered(): void
    {
        $riderId = $this->requireRider();
        if ($riderId === null) {
            return;
        }
        $body = $this->jsonInput();
        $deliveryId = (int) ($body['delivery_id'] ?? 0);
        $collectCash = (bool) ($body['collect_cash'] ?? false);

        if (!$this->ownsDelivery($deliveryId, $riderId)) {
            $this->json(['success' => false, 'message' => 'Delivery not found.'], 404);
            return;
        }

        $deliveryModel = new Delivery();
        $delivery = $deliveryModel->find($deliveryId);

        if ($collectCash && $delivery) {
            $orderModel = new Order();
            $order = $orderModel->find((int) $delivery['order_id']);
            if ($order) {
                $totalPaid = $orderModel->totalPaid((int) $order['id']);
                $balanceDue = max(0, (float) $order['total_amount'] - $totalPaid);
                if ($balanceDue > 0) {
                    $codMethodId = $this->getOrCreateCodPaymentMethod();
                    $orderModel->recordPayment((int) $order['id'], $codMethodId, $balanceDue, null);
                    AuditLogger::log(null, 'RIDER_COD_COLLECTED', 'payments', "Rider #{$riderId} collected COD " . formatMoney($balanceDue) . " for order #{$order['id']}");
                }
            }
        }

        $deliveryModel->markDelivered($deliveryId, null);
        $this->json(['success' => true]);
    }

    private function getOrCreateCodPaymentMethod(): int
    {
        $db = Database::getConnection();
        $stmt = $db->prepare("SELECT id FROM payment_methods WHERE method_name = 'COD' LIMIT 1");
        $stmt->execute();
        $method = $stmt->fetch();
        if ($method) {
            return (int) $method['id'];
        }
        $db->prepare("INSERT INTO payment_methods (method_name, finance_account_id, fee_percentage, is_active) VALUES ('COD', NULL, 0, 1)")->execute();
        return (int) $db->lastInsertId();
    }

    public function failed(): void
    {
        $riderId = $this->requireRider();
        if ($riderId === null) {
            return;
        }
        $body = $this->jsonInput();
        $deliveryId = (int) ($body['delivery_id'] ?? 0);
        $notes = trim($body['notes'] ?? '');

        if (!$this->ownsDelivery($deliveryId, $riderId)) {
            $this->json(['success' => false, 'message' => 'Delivery not found.'], 404);
            return;
        }

        (new Delivery())->markFailed($deliveryId, $notes ?: 'Marked failed by rider', null);
        $this->json(['success' => true]);
    }

    private function ownsDelivery(int $deliveryId, int $riderId): bool
    {
        if ($deliveryId <= 0) {
            return false;
        }
        $db = Database::getConnection();
        $stmt = $db->prepare("SELECT COUNT(*) as cnt FROM deliveries WHERE id = :id AND rider_id = :rider_id");
        $stmt->execute(['id' => $deliveryId, 'rider_id' => $riderId]);
        return (int) $stmt->fetch()['cnt'] > 0;
    }

    private function formatDelivery(array $d): array
    {
        return [
            'id'               => (int) $d['id'],
            'order_number'     => $d['order_number'],
            'status'           => $d['status'],
            'customer_name'    => $d['customer_name'] ?? 'Walk-in',
            'customer_phone'   => $d['customer_phone'] ?? null,
            'delivery_address' => $d['delivery_address'],
            'zone_name'        => $d['zone_name'] ?? null,
            'item_count'       => (int) $d['item_count'],
            'total_amount'     => (float) $d['total_amount'],
            'balance_due'      => max(0, (float) $d['total_amount'] - (float) ($d['total_paid'] ?? 0)),
            'assigned_at'      => $d['assigned_at'] ? date('d M, h:i A', strtotime($d['assigned_at'])) : null,
            'picked_up_at'     => $d['picked_up_at'] ? date('d M, h:i A', strtotime($d['picked_up_at'])) : null,
            'delivered_at'     => $d['delivered_at'] ? date('d M, h:i A', strtotime($d['delivered_at'])) : null,
            'notes'            => $d['notes'] ?? null,
        ];
    }
}
