<?php

namespace App\Controllers;

use App\Models\OrderModel;
use App\Models\UserModel;
use App\Models\NotificationModel;
use App\Models\OrderStatusHistoryModel;
use App\Models\DeliveryPersonModel;

class Delivery extends BaseController
{
    protected $orderModel;
    protected $userModel;
    protected $notificationModel;
    protected $statusHistoryModel;
    protected $deliveryPersonModel;

    public function __construct()
    {
        $this->orderModel = new OrderModel();
        $this->userModel = new UserModel();
        $this->notificationModel = new NotificationModel();
        $this->statusHistoryModel = new OrderStatusHistoryModel();
        $this->deliveryPersonModel = new DeliveryPersonModel();
    }

    private function checkDeliveryAccess()
    {
        $role = session()->get('role') ?: session()->get('user_type');
        if (!session()->get('logged_in') || $role !== 'delivery') {
            return redirect()->to('/login');
        }

        return null;
    }

    // D1 - Profile with mandatory details
    public function profile()
    {
        $check = $this->checkDeliveryAccess();
        if ($check) return $check;

        $userId = session()->get('user_id');
        $user = $this->userModel->find($userId);
        $deliveryPerson = $this->deliveryPersonModel->where('user_id', $userId)->first();

        $data = [
            'user' => $user,
            'deliveryPerson' => $deliveryPerson,
            'pageTitle' => 'Profile & KYC',
            'pageSubtitle' => 'Manage your profile and verification details',
        ];

        return view('delivery/profile', $data);
    }

    public function updateProfile()
    {
        $check = $this->checkDeliveryAccess();
        if ($check) return $check;

        $userId = session()->get('user_id');
        
        $userData = [
            'name' => $this->request->getPost('name'),
            'mobile' => $this->request->getPost('mobile'),
            'email' => $this->request->getPost('email'),
            'address' => $this->request->getPost('address'),
            'pin_code' => $this->request->getPost('pin_code'),
        ];

        $this->userModel->update($userId, $userData);

        return $this->response->setJSON(['success' => true, 'message' => 'Profile updated successfully']);
    }

    // D2 - KYC Details (PAN, Aadhar)
    public function updateKYC()
    {
        $check = $this->checkDeliveryAccess();
        if ($check) return $check;

        $userId = session()->get('user_id');
        $deliveryPerson = $this->deliveryPersonModel->where('user_id', $userId)->first();

        $kycData = [
            'pan_card' => $this->request->getPost('pan_card'),
            'aadhar_card' => $this->request->getPost('aadhar_card'),
            'kyc_verified' => 0, // Will be verified by admin
        ];

        if ($deliveryPerson) {
            $this->deliveryPersonModel->update($deliveryPerson['id'], $kycData);
        } else {
            $kycData['user_id'] = $userId;
            $this->deliveryPersonModel->insert($kycData);
        }

        return $this->response->setJSON(['success' => true, 'message' => 'KYC details submitted for verification']);
    }

    // D3, D4 - Dashboard with BGV status check
    public function dashboard()
    {
        $check = $this->checkDeliveryAccess();
        if ($check) return $check;

        $userId = session()->get('user_id');
        $user = $this->userModel->find($userId);
        $deliveryPerson = $this->deliveryPersonModel->where('user_id', $userId)->first();

        // Check KYC and BGV status
        $canSeeRequests = ($deliveryPerson && $deliveryPerson['kyc_verified'] == 1 && $user['bgv_cleared'] == 1);

        if (!$canSeeRequests) {
            return view('delivery/dashboard_restricted', [
                'user' => $user,
                'deliveryPerson' => $deliveryPerson,
                'kycStatus' => $deliveryPerson ? $deliveryPerson['kyc_verified'] : 0,
                'bgvStatus' => $user['bgv_cleared'] ?? 0,
            ]);
        }

        // Get badge count
        $badgeCount = $deliveryPerson['badges'] ?? 0;

        // Get available delivery requests filtered by badge requirements (D19, D20, D21)
        $availableRequests = $this->getFilteredDeliveryRequests($badgeCount);

        // Get assigned deliveries
        $assignedDeliveries = $this->orderModel
            ->where('delivery_person_id', $userId)
            ->whereNotIn('status', ['completed', 'cancelled'])
            ->orderBy('created_at', 'DESC')
            ->findAll();

        // Calculate distance and delivery details for each request
        foreach ($availableRequests as &$request) {
            $request['pickup_distance'] = $this->calculateDistance(
                $user['pin_code'],
                $request['seller_pin_code']
            );
            $request['drop_distance'] = $this->calculateDistance(
                $request['seller_pin_code'],
                $request['buyer_pin_code']
            );
        }

        $data = [
            'user' => $user,
            'deliveryPerson' => $deliveryPerson,
            'availableRequests' => $availableRequests,
            'assignedDeliveries' => $assignedDeliveries,
        ];

        return view('delivery/dashboard', $data);
    }

    // D19, D20, D21 - Filter delivery requests by badge count
    private function getFilteredDeliveryRequests($badgeCount)
    {
        $builder = $this->orderModel->builder();
        $builder->select('orders.*, products.title, products.price_category')
            ->join('products', 'products.id = orders.product_id')
            ->where('orders.delivery_person_id', null)
            ->where('orders.status', 'confirmed');

        // Filter by badge requirements
        if ($badgeCount < 20) {
            $builder->where('products.price_category !=', 'high_end')
                   ->where('products.price_category !=', 'ultra_luxury');
        } elseif ($badgeCount < 50) {
            $builder->where('products.price_category !=', 'ultra_luxury');
        } elseif ($badgeCount < 100) {
            // Can see all except specific ultra luxury over 100 badges
            $builder->where('products.required_badges <=', $badgeCount);
        }

        return $builder->get()->getResultArray();
    }

    // D5 - Calculate distance between pin codes
    private function calculateDistance($pinCode1, $pinCode2)
    {
        // Simplified distance calculation - in production use geolocation API
        return abs(intval($pinCode1) - intval($pinCode2)) * 0.5; // Rough estimate in km
    }

    // D6, D7, D8, D27, D28, D31 - Accept delivery request
    public function acceptDeliveryRequest()
    {
        $check = $this->checkDeliveryAccess();
        if ($check) return $check;

        $userId = session()->get('user_id');
        $orderId = $this->request->getPost('order_id');
        $order = $this->orderModel->find($orderId);

        if (!$order || $order['delivery_person_id'] !== null) {
            return $this->response->setJSON(['success' => false, 'message' => 'Delivery request not available']);
        }

        // D28 - Get pickup and drop time ranges
        $pickupTimeStart = $this->request->getPost('pickup_time_start');
        $pickupTimeEnd = $this->request->getPost('pickup_time_end');
        $dropTimeStart = $this->request->getPost('drop_time_start');
        $dropTimeEnd = $this->request->getPost('drop_time_end');

        // D7, D8 - Validate time constraints for Rent
        if ($order['order_type'] === 'rent') {
            $rentalStartTime = strtotime($order['rental_start_date']);
            $pickupTime = strtotime($pickupTimeEnd);
            
            // Must pickup at least 4-5 hours before rental start
            if (($rentalStartTime - $pickupTime) < (4 * 3600)) {
                return $this->response->setJSON(['success' => false, 'message' => 'Pickup time must be at least 4-5 hours before rental start']);
            }

            // Must drop at least 4-5 hours before rental start
            $dropTime = strtotime($dropTimeEnd);
            if (($rentalStartTime - $dropTime) < (4 * 3600)) {
                return $this->response->setJSON(['success' => false, 'message' => 'Drop time must be at least 4-5 hours before rental start']);
            }
        }

        // D10 - Validate time constraints for Sell
        if ($order['order_type'] === 'sell') {
            $maxDeliveryDate = strtotime($order['max_delivery_date'] ?? '+3 days');
            $dropTime = strtotime($dropTimeEnd);
            
            // Must deliver at least 1 day before max delivery date
            if (($maxDeliveryDate - $dropTime) < (24 * 3600)) {
                return $this->response->setJSON(['success' => false, 'message' => 'Drop time must be at least 1 day before max delivery date']);
            }
        }

        // D31 - Transfer deposit for Rent orders
        if ($order['order_type'] === 'rent') {
            $depositAmount = $order['deposit_amount'] ?? 0;
            // Logic to transfer deposit from delivery person to system
            // This would integrate with payment gateway
        }

        // Assign delivery person
        $this->orderModel->update($orderId, [
            'delivery_person_id' => $userId,
            'status' => 'assigned',
            'pickup_time_start' => $pickupTimeStart,
            'pickup_time_end' => $pickupTimeEnd,
            'drop_time_start' => $dropTimeStart,
            'drop_time_end' => $dropTimeEnd,
            'delivery_accepted_at' => date('Y-m-d H:i:s'),
        ]);

        // Notify seller and buyer
        $this->notificationModel->insert([
            'user_id' => $order['seller_id'],
            'title' => 'Delivery Person Assigned',
            'message' => 'A delivery person has been assigned to your order',
            'type' => 'delivery_assigned',
            'related_id' => $orderId,
        ]);

        return $this->response->setJSON(['success' => true, 'message' => 'Delivery request accepted successfully']);
    }

    // D11 - Mark Dispatched as-is
    public function markDispatchedAsIs($orderId)
    {
        return $this->markDeliveryStatus($orderId, 'dispatched_as_is', 'Product dispatched as-is from seller');
    }

    // D12 - Mark Returned as-is
    public function markReturnedAsIs($orderId)
    {
        return $this->markDeliveryStatus($orderId, 'returned_as_is', 'Product returned as-is to seller');
    }

    // D13 - Mark Dispatched with Defects
    public function markDispatchedWithDefects($orderId)
    {
        $defectNotes = $this->request->getPost('defect_notes');
        return $this->markDeliveryStatus($orderId, 'dispatched_with_defects', "Product dispatched with defects: {$defectNotes}");
    }

    // D14 - Mark Returned with Defects
    public function markReturnedWithDefects($orderId)
    {
        $defectNotes = $this->request->getPost('defect_notes');
        return $this->markDeliveryStatus($orderId, 'returned_with_defects', "Product returned with defects: {$defectNotes}");
    }

    // D15 - Mark Not Returned By Buyer
    public function markNotReturnedByBuyer($orderId)
    {
        return $this->markDeliveryStatus($orderId, 'not_returned_by_buyer', 'Product not returned by buyer');
    }

    // D16 - Mark Not Dispatched By Seller
    public function markNotDispatchedBySeller($orderId)
    {
        return $this->markDeliveryStatus($orderId, 'not_dispatched_by_seller', 'Product not dispatched by seller');
    }

    // Helper function to mark delivery status
    private function markDeliveryStatus($orderId, $status, $notes)
    {
        $check = $this->checkDeliveryAccess();
        if ($check) return $check;

        $userId = session()->get('user_id');
        $order = $this->orderModel->find($orderId);

        if (!$order || $order['delivery_person_id'] != $userId) {
            return $this->response->setJSON(['success' => false, 'message' => 'Order not found']);
        }

        $this->orderModel->update($orderId, [
            'status' => $status,
            'status_updated_at' => date('Y-m-d H:i:s'),
        ]);

        $this->statusHistoryModel->insert([
            'order_id' => $orderId,
            'status' => $status,
            'notes' => $notes,
            'updated_by' => $userId,
        ]);

        // D17, D18 - Update reliability scores
        if (in_array($status, ['dispatched_as_is', 'returned_as_is'])) {
            $deliveryPerson = $this->deliveryPersonModel->where('user_id', $userId)->first();
            if ($deliveryPerson) {
                $scoreIncrease = ($order['order_type'] === 'rent') ? 2 : 1; // D17: +2 for rent, D18: +1 for sell
                
                $this->deliveryPersonModel->update($deliveryPerson['id'], [
                    'rental_reliability_score' => ($deliveryPerson['rental_reliability_score'] ?? 0) + ($order['order_type'] === 'rent' ? $scoreIncrease : 0),
                    'sale_reliability_score' => ($deliveryPerson['sale_reliability_score'] ?? 0) + ($order['order_type'] === 'sell' ? $scoreIncrease : 0),
                ]);
            }
        }

        // Notify buyer and seller
        $this->notificationModel->insert([
            'user_id' => $order['buyer_id'],
            'title' => 'Delivery Status Updated',
            'message' => $notes,
            'type' => 'delivery_status_update',
            'related_id' => $orderId,
        ]);

        return $this->response->setJSON(['success' => true, 'message' => 'Status updated successfully']);
    }

    // D22, D23, D24, D25, D26 - Cancel delivery request
    public function cancelDeliveryRequest($orderId)
    {
        $check = $this->checkDeliveryAccess();
        if ($check) return $check;

        $userId = session()->get('user_id');
        $order = $this->orderModel->find($orderId);

        if (!$order || $order['delivery_person_id'] != $userId) {
            return $this->response->setJSON(['success' => false, 'message' => 'Order not found']);
        }

        $currentTime = time();
        $acceptedTime = strtotime($order['delivery_accepted_at']);
        
        // D22 - Check if still within cancellation window (some duration)
        $cancellationWindow = 2 * 3600; // 2 hours window
        if (($currentTime - $acceptedTime) > $cancellationWindow) {
            // D24, D25 - Additional checks for near-deadline cancellations
            if ($order['order_type'] === 'rent') {
                $rentalStartTime = strtotime($order['rental_start_date']);
                // D24 - Can cancel only 3 days before rental start
                if (($rentalStartTime - $currentTime) < (3 * 24 * 3600)) {
                    return $this->response->setJSON(['success' => false, 'message' => 'Cannot cancel within 3 days of rental start']);
                }
            } else {
                $maxDeliveryTime = strtotime($order['max_delivery_date'] ?? '+3 days');
                // D25 - Can cancel only 3 days before max delivery date
                if (($maxDeliveryTime - $currentTime) < (3 * 24 * 3600)) {
                    return $this->response->setJSON(['success' => false, 'message' => 'Cannot cancel within 3 days of max delivery date']);
                }
            }
        }

        // D26 - Release delivery request back to pool
        $this->orderModel->update($orderId, [
            'delivery_person_id' => null,
            'status' => 'confirmed',
            'pickup_time_start' => null,
            'pickup_time_end' => null,
            'drop_time_start' => null,
            'drop_time_end' => null,
            'delivery_accepted_at' => null,
        ]);

        // Notify admin
        $this->notificationModel->insert([
            'user_id' => 1, // Admin user ID
            'title' => 'Delivery Request Cancelled',
            'message' => "Delivery person cancelled order #{$orderId}. Request returned to pool.",
            'type' => 'delivery_cancelled',
            'related_id' => $orderId,
        ]);

        return $this->response->setJSON(['success' => true, 'message' => 'Delivery request cancelled. It has been returned to the pool.']);
    }

    // D29 - View Delivery History and Earnings
    public function history()
    {
        $check = $this->checkDeliveryAccess();
        if ($check) return $check;

        $userId = session()->get('user_id');
        $user = $this->userModel->find($userId);
        $deliveryPerson = $this->deliveryPersonModel->where('user_id', $userId)->first();

        $deliveries = $this->orderModel
            ->where('delivery_person_id', $userId)
            ->orderBy('updated_at', 'DESC')
            ->findAll();

        // Calculate total earnings
        $totalEarnings = 0;
        foreach ($deliveries as $delivery) {
            $totalEarnings += $delivery['delivery_charge'] ?? 50;
        }

        $data = [
            'user' => $user,
            'deliveryPerson' => $deliveryPerson,
            'deliveries' => $deliveries,
            'totalEarnings' => $totalEarnings,
        ];

        return view('delivery/history', $data);
    }

    public function earnings()
    {
        $check = $this->checkDeliveryAccess();
        if ($check) return $check;

        $userId = session()->get('user_id');
        $user = $this->userModel->find($userId);
        $deliveryPerson = $this->deliveryPersonModel->where('user_id', $userId)->first();

        $completedDeliveries = $this->orderModel
            ->where('delivery_person_id', $userId)
            ->whereIn('status', ['dispatched_as_is', 'returned_as_is', 'delivered'])
            ->findAll();

        $totalEarnings = 0;
        $totalDeliveries = count($completedDeliveries);
        
        foreach ($completedDeliveries as $delivery) {
            $totalEarnings += $delivery['delivery_charge'] ?? 50;
        }

        // Calculate today's and week's earnings
        $todayEarnings = 0;
        $weekEarnings = 0;
        $today = date('Y-m-d');
        $weekStart = date('Y-m-d', strtotime('-7 days'));

        foreach ($completedDeliveries as $delivery) {
            $deliveryDate = date('Y-m-d', strtotime($delivery['created_at']));
            $charge = $delivery['delivery_charge'] ?? 50;
            
            if ($deliveryDate == $today) {
                $todayEarnings += $charge;
            }
            if ($deliveryDate >= $weekStart) {
                $weekEarnings += $charge;
            }
        }

        $data = [
            'user' => $user,
            'deliveryPerson' => $deliveryPerson,
            'completedDeliveries' => $completedDeliveries,
            'totalEarnings' => $totalEarnings,
            'totalDeliveries' => $totalDeliveries,
            'todayEarnings' => $todayEarnings,
            'weekEarnings' => $weekEarnings,
            'pageTitle' => 'Earnings',
            'pageSubtitle' => 'Track your delivery earnings',
        ];

        return view('delivery/earnings', $data);
    }

    // D2 - View Order Details
    public function orderDetails($orderId)
    {
        $check = $this->checkDeliveryAccess();
        if ($check) return $check;

        $userId = session()->get('user_id');
        $order = $this->orderModel->find($orderId);

        if (!$order || $order['delivery_person_id'] != $userId) {
            return redirect()->to('/delivery/dashboard')->with('error', 'Order not found');
        }

        $history = $this->statusHistoryModel->getOrderHistory($orderId);
        $buyer = $this->userModel->find($order['buyer_id']);
        $seller = $this->userModel->find($order['seller_id']);

        $data = [
            'user' => $this->userModel->find($userId),
            'order' => $order,
            'buyer' => $buyer,
            'seller' => $seller,
            'history' => $history,
        ];

        return view('delivery/order_details', $data);
    }

    // D30 - Reminder Notifications (called via cron job)
    public function sendPickupDropReminders()
    {
        // This would be called via a scheduled task/cron job
        $orders = $this->orderModel
            ->where('status', 'assigned')
            ->where('delivery_person_id IS NOT NULL')
            ->findAll();

        $currentTime = time();

        foreach ($orders as $order) {
            $pickupTime = strtotime($order['pickup_time_start']);
            $dropTime = strtotime($order['drop_time_start']);

            // Send reminder 2 hours before pickup
            if (($pickupTime - $currentTime) <= (2 * 3600) && ($pickupTime - $currentTime) > (1.5 * 3600)) {
                $this->notificationModel->insert([
                    'user_id' => $order['delivery_person_id'],
                    'title' => 'Pickup Reminder',
                    'message' => "Reminder: Pickup for order #{$order['id']} is in 2 hours",
                    'type' => 'pickup_reminder',
                    'related_id' => $order['id'],
                ]);
            }

            // Send reminder 2 hours before drop
            if (($dropTime - $currentTime) <= (2 * 3600) && ($dropTime - $currentTime) > (1.5 * 3600)) {
                $this->notificationModel->insert([
                    'user_id' => $order['delivery_person_id'],
                    'title' => 'Drop Reminder',
                    'message' => "Reminder: Drop for order #{$order['id']} is in 2 hours",
                    'type' => 'drop_reminder',
                    'related_id' => $order['id'],
                ]);
            }
        }

        return $this->response->setJSON(['success' => true, 'reminders_sent' => count($orders)]);
    }
}
