<?php

namespace App\Controllers\Api;

use App\Libraries\JwtAuth;
use App\Models\OrderModel;
use App\Models\OrderItemModel;
use App\Models\NotificationModel;
use App\Models\SettingModel;

class OrdersController extends BaseApiController
{
    /**
     * GET api/orders - list orders for current user (or driver). Optional ?limit=5 for last N.
     */
    public function index()
    {
        $user = JwtAuth::user();
        if (! $user) {
            return $this->error('Unauthorized', 401);
        }
        $db   = \Config\Database::connect();
        $role = $db->table('users')->where('id', $user->id)->get()->getRow()->role ?? 'user';

        $model = model(OrderModel::class);
        if ($role === 'driver') {
            $model->where('driver_id', $user->id);
        } else {
            $model->where('user_id', $user->id);
        }
        $limit = (int) ($this->request->getGet('limit') ?? 0);
        if ($limit > 0) {
            $model->limit($limit);
        }
        $orders = $model->orderBy('created_at', 'DESC')->findAll();
        $data   = $role === 'driver' ? $this->formatOrdersForDriver($orders) : $this->formatOrders($orders);
        return $this->success($data);
    }

    /**
     * GET api/orders/active - single active order for user (dashboard card)
     */
    public function active()
    {
        $user = JwtAuth::user();
        if (! $user) {
            return $this->error('Unauthorized', 401);
        }
        $model = model(OrderModel::class);
        $order = $model->where('user_id', $user->id)
            ->whereIn('status', ['paid', 'dispatched'])
            ->orderBy('created_at', 'DESC')
            ->first();
        if (! $order) {
            return $this->success(null);
        }
        $data = $this->formatOrderWithDriver($order);
        return $this->success($data);
    }

    /**
     * GET api/orders/:id - single order detail for current user (address, status, OTP when paid/dispatched).
     */
    public function show(int $id)
    {
        $user = JwtAuth::user();
        if (! $user) {
            return $this->error('Unauthorized', 401);
        }
        $db    = \Config\Database::connect();
        $role  = $db->table('users')->where('id', $user->id)->get()->getRow()->role ?? 'user';
        $model = model(OrderModel::class);
        if ($role === 'driver') {
            $model->where('driver_id', $user->id);
        } else {
            $model->where('user_id', $user->id);
        }
        $order = $model->find($id);
        if (! $order) {
            return $this->error('Order not found', 404);
        }
        $data = $role === 'driver' ? $this->formatOrderForDriver($order) : $this->formatOrderWithDriver($order);
        return $this->success($data);
    }

    /**
     * POST api/orders - create order (after payment); generates OTP; sends Discord webhook.
     * Body: location_id, order_type (gas|fuel|shop|rescue), service_id (optional), rescue_service_id (optional),
     *       order_meta (gas: gas_size_id, refill_or_kit; fuel: inventory_id, liters; etc), total_amount,
     *       items (optional for shop: [{ inventory_id, quantity, unit_price }]
     */
    public function create()
    {
        $user = JwtAuth::user();
        if (! $user) {
            return $this->error('Unauthorized', 401);
        }
        $db   = \Config\Database::connect();
        $role = $db->table('users')->where('id', $user->id)->get()->getRow()->role ?? 'user';
        if ($role !== 'user') {
            return $this->error('Only users can create orders', 403);
        }

        $json = $this->request->getJSON(true) ?: [];
        $orderType   = $json['order_type'] ?? 'gas';
        $totalAmount = (float) ($json['total_amount'] ?? 0);
        $pointsUsed  = (int) ($json['points_used'] ?? 0);
        $locationId = isset($json['location_id']) ? (int) $json['location_id'] : null;
        $serviceId  = isset($json['service_id']) ? (int) $json['service_id'] : null;
        $rescueServiceId = isset($json['rescue_service_id']) ? (int) $json['rescue_service_id'] : null;
        $orderMeta  = $json['order_meta'] ?? null;
        $items      = $json['items'] ?? [];

        if ($totalAmount <= 0) {
            return $this->error('total_amount required and must be positive', 400);
        }
        if (! in_array($orderType, ['gas', 'fuel', 'shop', 'rescue'], true)) {
            return $this->error('Invalid order_type', 400);
        }

        $userRow = $db->table('users')->where('id', $user->id)->get()->getRow();
        $pointsBalance = isset($userRow->points_balance) ? (int) $userRow->points_balance : 0;

        if ($pointsUsed < 0) {
            return $this->error('points_used must be non-negative', 400);
        }
        if ($pointsUsed > 0) {
            if ($pointsUsed < 5000) {
                return $this->error('Minimum redeemable points is 5,000', 400);
            }
            if ($pointsUsed > $pointsBalance) {
                return $this->error('Insufficient points balance', 400);
            }
            $totalInt = (int) round($totalAmount);
            if ($pointsUsed > $totalInt) {
                return $this->error('Points used cannot exceed order total', 400);
            }
        }

        $amountAfterPoints = $totalAmount - $pointsUsed;
        $pointsToAward     = (int) floor($amountAfterPoints / 1000);

        $orderModel = model(OrderModel::class);
        $orderModel->insert([
            'user_id'           => $user->id,
            'service_id'        => $serviceId,
            'location_id'       => $locationId,
            'order_type'        => $orderType,
            'order_meta'        => $orderMeta !== null ? json_encode($orderMeta) : null,
            'rescue_service_id' => $rescueServiceId ?: null,
            'total_amount'      => $totalAmount,
            'points_used'       => $pointsUsed,
            'otp_code'          => sprintf('%04d', random_int(0, 9999)),
            'status'            => 'paid',
        ]);
        $id = $orderModel->getInsertID();

        $db->table('users')->where('id', $user->id)->update([
            'points_balance' => $pointsBalance - $pointsUsed + $pointsToAward,
            'updated_at'     => date('Y-m-d H:i:s'),
        ]);

        $orderItemModel = model(OrderItemModel::class);
        foreach ($items as $item) {
            $invId = (int) ($item['inventory_id'] ?? 0);
            $qty   = (int) ($item['quantity'] ?? 1);
            $price = (float) ($item['unit_price'] ?? 0);
            if ($invId > 0 && $qty > 0) {
                $orderItemModel->insert([
                    'order_id'     => $id,
                    'inventory_id' => $invId,
                    'quantity'     => $qty,
                    'unit_price'   => $price,
                ]);
            }
        }

        $order = $orderModel->find($id);
        $address = '';
        if ($locationId) {
            $loc = $db->table('locations')->where('id', $locationId)->get()->getRow();
            $address = $loc ? ($loc->address_name ?? $loc->latitude . ',' . $loc->longitude) : '';
        }
        $userRow = $db->table('users')->where('id', $user->id)->get()->getRow();
        helper('discord');
        send_order_to_discord([
            'id'            => $id,
            'order_type'    => $orderType,
            'user_phone'    => $userRow->phone ?? '',
            'address'       => $address,
            'total_amount'  => $totalAmount,
            'order_summary' => $this->buildOrderSummary($order),
        ]);

        NotificationModel::logOrderStatus((int) $user->id, $id, 'paid');

        return $this->success($this->formatOrder($order), 201);
    }

    /**
     * POST api/orders/:id/complete - driver completes delivery with OTP.
     * Body: { "otp_code": "1234" }
     */
    public function complete(int $id)
    {
        $user = JwtAuth::user();
        if (! $user) {
            return $this->error('Unauthorized', 401);
        }
        $db   = \Config\Database::connect();
        $role = $db->table('users')->where('id', $user->id)->get()->getRow()->role ?? 'user';
        if ($role !== 'driver') {
            return $this->error('Only drivers can complete delivery', 403);
        }

        $orderModel = model(OrderModel::class);
        $order      = $orderModel->find($id);
        if (! $order || (int) $order->driver_id !== (int) $user->id) {
            return $this->error('Order not found', 404);
        }
        $json    = $this->request->getJSON(true) ?: [];
        $otpCode = $json['otp_code'] ?? '';
        if ($otpCode !== $order->otp_code) {
            return $this->error('Invalid OTP', 400);
        }
        $orderModel->update($id, ['status' => 'delivered']);
        NotificationModel::logOrderStatus((int) $order->user_id, $id, 'delivered');
        return $this->success($this->formatOrder($orderModel->find($id)));
    }

    private function formatOrders(array $orders): array
    {
        return array_map([$this, 'formatOrder'], $orders);
    }

    /** For driver: include location and user phone for Call/Maps */
    private function formatOrdersForDriver(array $orders): array
    {
        return array_map([$this, 'formatOrderForDriver'], $orders);
    }

    private function formatOrderForDriver(object $order): array
    {
        $data = $this->formatOrder($order);
        $db   = \Config\Database::connect();
        if (! empty($order->location_id)) {
            $loc = $db->table('locations')->where('id', $order->location_id)->get()->getRow();
            $data['location'] = $loc ? [
                'latitude'     => (float) $loc->latitude,
                'longitude'    => (float) $loc->longitude,
                'address_name' => $loc->address_name ?? null,
                'plus_code'    => $loc->plus_code ?? null,
            ] : null;
        } else {
            $data['location'] = null;
        }
        $userRow = $db->table('users')->where('id', $order->user_id)->get()->getRow();
        $data['user_phone'] = $userRow ? $userRow->phone : null;
        $data['order_summary'] = $this->buildOrderSummary($order);
        return $data;
    }

    private function formatOrder(object $order): array
    {
        $pointsUsed = (int) ($order->points_used ?? 0);
        $data = [
            'id'           => (int) $order->id,
            'user_id'      => (int) $order->user_id,
            'driver_id'    => $order->driver_id ? (int) $order->driver_id : null,
            'service_id'   => $order->service_id ? (int) $order->service_id : null,
            'location_id'  => $order->location_id ?? null,
            'order_type'   => $order->order_type ?? null,
            'order_meta'   => isset($order->order_meta) ? (is_string($order->order_meta) ? json_decode($order->order_meta, true) : $order->order_meta) : null,
            'total_amount' => (float) $order->total_amount,
            'points_used'  => $pointsUsed,
            'status'       => $order->status,
            'created_at'   => $order->created_at ?? null,
        ];
        if (! empty($order->otp_code) && in_array($order->status, ['paid', 'dispatched'], true)) {
            $data['otp_code'] = $order->otp_code;
        }
        return $data;
    }

    private function formatOrderWithDriver(object $order): array
    {
        $data = $this->formatOrder($order);
        $db   = \Config\Database::connect();
        if (! empty($order->driver_id)) {
            $driver = $db->table('users')->where('id', $order->driver_id)->get()->getRow();
            $data['driver'] = $driver ? [
                'id'    => (int) $driver->id,
                'phone' => $driver->phone,
                'name'  => ! empty($driver->display_name) ? $driver->display_name : ($driver->username ?? 'Driver'),
            ] : null;
        } else {
            $data['driver'] = null;
        }
        if (! empty($order->location_id)) {
            $loc = $db->table('locations')->where('id', $order->location_id)->get()->getRow();
            $data['location'] = $loc ? [
                'latitude'     => (float) $loc->latitude,
                'longitude'    => (float) $loc->longitude,
                'address_name' => $loc->address_name ?? null,
                'plus_code'    => $loc->plus_code ?? null,
            ] : null;
        } else {
            $data['location'] = null;
        }
        $data['order_summary'] = $this->buildOrderSummary($order);
        return $data;
    }

    /**
     * Human-readable summary: gas (type, brand, size), fuel (brand, liters), rescue (service name), shop (item count).
     */
    private function buildOrderSummary(object $order): ?array
    {
        $db       = \Config\Database::connect();
        $orderType = $order->order_type ?? 'gas';
        $meta     = isset($order->order_meta) ? (is_string($order->order_meta) ? json_decode($order->order_meta, true) : $order->order_meta) : [];

        if ($orderType === 'gas' && ! empty($meta['gas_size_id'])) {
            $inv = $db->table('inventory')->where('id', (int) $meta['gas_size_id'])->get()->getRow();
            if (! $inv) {
                return ['type' => $meta['refill_or_kit'] ?? 'Refill', 'brand' => '—', 'size' => '—'];
            }
            $provider = $db->table('providers')->where('id', $inv->provider_id)->get()->getRow();
            $refillOrKit = isset($meta['refill_or_kit']) && $meta['refill_or_kit'] === 'new_kit' ? 'New kit' : 'Refill';
            $out = [
                'type'  => $refillOrKit,
                'brand' => $provider ? $provider->name : '—',
                'size'  => $inv->item_name ?? '—',
            ];
            if ($refillOrKit === 'New kit' && ! empty($meta['kit_addons']) && is_array($meta['kit_addons'])) {
                $out['kit_addons'] = $meta['kit_addons'];
            }
            return $out;
        }

        if ($orderType === 'fuel' && ! empty($meta['inventory_id'])) {
            $inv = $db->table('inventory')->where('id', (int) $meta['inventory_id'])->get()->getRow();
            if (! $inv) {
                return ['brand' => '—', 'liters' => (int) ($meta['liters'] ?? 0)];
            }
            $provider = $db->table('providers')->where('id', $inv->provider_id)->get()->getRow();
            $pricePerLiter = isset($inv->price) ? (float) $inv->price : null;

            $out = [
                'brand'           => $provider ? $provider->name : '—',
                'fuel_type'       => $inv->item_name ?? '—',
                'liters'          => (int) ($meta['liters'] ?? 0),
                'price_per_liter' => $pricePerLiter,
            ];
            if (! empty($meta['car_plate'])) {
                $out['car_plate'] = $meta['car_plate'];
            }
            return $out;
        }

        if ($orderType === 'rescue' && ! empty($order->rescue_service_id)) {
            $svc = $db->table('rescue_services')->where('id', $order->rescue_service_id)->get()->getRow();

            return ['service' => $svc ? $svc->name : '—'];
        }

        if ($orderType === 'shop') {
            $count = $db->table('order_items')->where('order_id', $order->id)->countAllResults();

            return ['items_count' => $count];
        }

        return null;
    }
}
