<?php

namespace App\Http\Controllers\API\Manager;

use App\Http\Controllers\Controller;
use App\Models\{Order, DeliveryBoy, DeliveryAssignment};
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Carbon\Carbon;

class DashboardController extends Controller
{
    public function index(Request $request)
    {
        $restaurant = $this->getRestaurant($request);
        
        return response()->json([
            'stats' => $this->getStats($restaurant->id),
            'revenue' => $this->getRevenue($restaurant->id),
            'orders' => $this->getOrders($request, $restaurant->id),
            'alerts' => $this->getAlerts($restaurant->id),
        ]);
    }

    public function getStats($restaurantId)
    {
        $today = Carbon::today();
        
        return [
            'new' => Order::where('restaurant_id', $restaurantId)->where('status', 'pending')->count(),
            'preparing' => Order::where('restaurant_id', $restaurantId)->where('status', 'preparing')->count(),
            'ready' => Order::where('restaurant_id', $restaurantId)->where('status', 'ready')->count(),
            'on_delivery' => Order::where('restaurant_id', $restaurantId)->whereIn('status', ['picked_up', 'on_the_way'])->count(),
            'completed' => Order::where('restaurant_id', $restaurantId)->where('status', 'delivered')->whereDate('created_at', $today)->count(),
            'cancelled' => Order::where('restaurant_id', $restaurantId)->where('status', 'cancelled')->whereDate('created_at', $today)->count(),
        ];
    }

    public function getRevenue($restaurantId)
    {
        $today = Carbon::today();
        
        $data = Order::where('restaurant_id', $restaurantId)
            ->whereDate('created_at', $today)
            ->whereNotIn('status', ['cancelled'])
            ->selectRaw('
                SUM(total) as total_sales,
                SUM(delivery_fee) as delivery_fees,
                SUM(service_charge) as service_charges,
                SUM(COALESCE(refund_amount, 0)) as refunds,
                COUNT(*) as order_count
            ')
            ->first();
        
        return [
            'total_sales' => round($data->total_sales ?? 0, 2),
            'delivery_fees' => round($data->delivery_fees ?? 0, 2),
            'service_charges' => round($data->service_charges ?? 0, 2),
            'refunds' => round($data->refunds ?? 0, 2),
            'net_revenue' => round(($data->total_sales ?? 0) - ($data->refunds ?? 0), 2),
            'order_count' => $data->order_count ?? 0,
        ];
    }

    public function getOrders(Request $request, $restaurantId)
    {
        $restaurant = \App\Models\Restaurant::find($restaurantId);
        
        $query = Order::with([
            'user:id,name,phone',
            'items:id,order_id,product_name,quantity,unit_price,total_price',
            'delivery.deliveryBoy:id,full_name,phone,rating,status'
        ])
        ->where('restaurant_id', $restaurantId);

        if ($request->status) {
            $query->where('status', $request->status);
        }
        
        if ($request->payment_status) {
            $query->where('payment_status', $request->payment_status);
        }
        
        if ($request->search) {
            $query->where(function($q) use ($request) {
                $q->where('order_number', 'like', "%{$request->search}%")
                  ->orWhere('delivery_phone', 'like', "%{$request->search}%");
            });
        }

        $orders = $query->latest()->paginate(20);
        
        $orders->getCollection()->transform(function($order) use ($restaurant) {
            if ($order->delivery_latitude && $order->delivery_longitude && $restaurant->latitude && $restaurant->longitude) {
                // Use saved distance if available, otherwise calculate
                if (!$order->distance_km) {
                    $mapService = new \App\Services\MapService();
                    $directions = $mapService->getDirections(
                        $restaurant->latitude,
                        $restaurant->longitude,
                        $order->delivery_latitude,
                        $order->delivery_longitude
                    );
                    $order->distance_km = $directions['distance_km'];
                }
                $order->restaurant_latitude = $restaurant->latitude;
                $order->restaurant_longitude = $restaurant->longitude;
            }
            return $order;
        });
        
        return $orders;
    }
    
    private function calculateDistance($lat1, $lon1, $lat2, $lon2)
    {
        $earthRadius = 6371;
        $dLat = deg2rad($lat2 - $lat1);
        $dLon = deg2rad($lon2 - $lon1);
        $a = sin($dLat/2) * sin($dLat/2) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * sin($dLon/2) * sin($dLon/2);
        $c = 2 * atan2(sqrt($a), sqrt(1-$a));
        return round($earthRadius * $c, 2);
    }

    public function getAlerts($restaurantId)
    {
        $alerts = [];
        
        $delayed = Order::where('restaurant_id', $restaurantId)
            ->where('status', 'ready')
            ->whereNull('assigned_delivery_boy_id')
            ->where('ready_at', '<', now()->subMinutes(15))
            ->count();
        
        if ($delayed > 0) {
            $alerts[] = [
                'type' => 'warning',
                'message' => "{$delayed} orders ready but no delivery boy assigned",
                'action' => 'assign_delivery',
            ];
        }
        
        $rejections = DB::table('delivery_rejections')
            ->join('orders', 'delivery_rejections.order_id', '=', 'orders.id')
            ->where('orders.restaurant_id', $restaurantId)
            ->whereNull('orders.assigned_delivery_boy_id')
            ->select('order_id', DB::raw('COUNT(*) as rejection_count'))
            ->groupBy('order_id')
            ->having('rejection_count', '>=', 3)
            ->count();
        
        if ($rejections > 0) {
            $alerts[] = [
                'type' => 'danger',
                'message' => "{$rejections} orders rejected by multiple delivery boys",
                'action' => 'review_orders',
            ];
        }
        
        return $alerts;
    }

    public function getAvailableDeliveryBoys(Request $request)
    {
        $restaurant = $this->getRestaurant($request);
        
        return DeliveryBoy::select('delivery_boys.*')
            ->selectRaw('
                (6371 * acos(
                    cos(radians(?)) * cos(radians(delivery_boy_areas.latitude)) *
                    cos(radians(delivery_boy_areas.longitude) - radians(?)) +
                    sin(radians(?)) * sin(radians(delivery_boy_areas.latitude))
                )) AS distance_km',
                [$restaurant->latitude, $restaurant->longitude, $restaurant->latitude]
            )
            ->join('delivery_boy_areas', 'delivery_boys.id', '=', 'delivery_boy_areas.delivery_boy_id')
            ->with('vehicles:id,delivery_boy_id,vehicle_type')
            ->where('delivery_boys.status', 'online')
            ->where('delivery_boys.is_available', true)
            ->where('delivery_boys.verification_status', 'verified')
            ->where('delivery_boy_areas.is_active', true)
            ->havingRaw('distance_km <= 10')
            ->orderBy('distance_km')
            ->get()
            ->map(function($boy) {
                return [
                    'id' => $boy->id,
                    'name' => $boy->full_name,
                    'phone' => $boy->phone,
                    'distance' => round($boy->distance_km, 1) . ' km',
                    'rating' => $boy->rating,
                    'total_deliveries' => $boy->total_deliveries,
                    'vehicle' => $boy->vehicles->first()->vehicle_type ?? 'N/A',
                    'status' => $boy->status,
                ];
            });
    }

    public function getMapDeliveries(Request $request)
    {
        $restaurant = $this->getRestaurant($request);
        
        $query = Order::with(['user:id,name', 'delivery.deliveryBoy:id,full_name'])
            ->where('restaurant_id', $restaurant->id);
        
        // Date filter
        if ($request->date) {
            switch ($request->date) {
                case 'today':
                    $query->whereDate('created_at', Carbon::today());
                    break;
                case 'yesterday':
                    $query->whereDate('created_at', Carbon::yesterday());
                    break;
                case 'week':
                    $query->whereBetween('created_at', [Carbon::now()->startOfWeek(), Carbon::now()->endOfWeek()]);
                    break;
                case 'month':
                    $query->whereMonth('created_at', Carbon::now()->month)
                          ->whereYear('created_at', Carbon::now()->year);
                    break;
                case 'all':
                    // No date filter
                    break;
            }
        } else {
            // Default to today
            $query->whereDate('created_at', Carbon::today());
        }
        
        // Status filter
        if ($request->status) {
            $query->where('status', $request->status);
        } else {
            // Default to active statuses
            $query->whereIn('status', ['pending', 'accepted', 'preparing', 'ready', 'picked_up', 'on_the_way']);
        }
        
        $orders = $query->get()
            ->map(function($order) use ($restaurant) {
                return [
                    'id' => $order->id,
                    'order_number' => $order->order_number,
                    'customer' => $order->user->name,
                    'delivery_boy' => $order->delivery->deliveryBoy->full_name ?? 'N/A',
                    'status' => $order->status,
                    'restaurant_lat' => $restaurant->latitude,
                    'restaurant_lng' => $restaurant->longitude,
                    'customer_lat' => $order->delivery_latitude,
                    'customer_lng' => $order->delivery_longitude,
                    'distance_km' => $this->calculateDistance(
                        $restaurant->latitude,
                        $restaurant->longitude,
                        $order->delivery_latitude,
                        $order->delivery_longitude
                    ) . ' km'
                ];
            });
        
        return response()->json($orders);
    }

    public function assignDeliveryBoy(Request $request, Order $order)
    {
        $request->validate(['delivery_boy_id' => 'required|exists:delivery_boys,id']);
        
        $restaurant = $this->getRestaurant($request);
        
        if ($order->restaurant_id !== $restaurant->id) {
            return response()->json(['message' => 'Unauthorized'], 403);
        }
        
        DB::transaction(function() use ($order, $request) {
            $deliveryBoy = DeliveryBoy::lockForUpdate()->find($request->delivery_boy_id);
            
            if (!$deliveryBoy->is_available) {
                throw new \Exception('Delivery boy not available');
            }
            
            $order->update([
                'assigned_delivery_boy_id' => $deliveryBoy->id,
                'status' => 'assigned',
            ]);
            
            $deliveryBoy->update([
                'status' => 'on_delivery',
                'is_available' => false,
            ]);
        });
        
        return response()->json(['message' => 'Delivery boy assigned successfully']);
    }

    public function getDashboardStats(Request $request)
    {
        $restaurant = $this->getRestaurant($request);
        $today = Carbon::today();
        
        $stats = [
            'today_orders' => Order::where('restaurant_id', $restaurant->id)->whereDate('created_at', $today)->count(),
            'today_revenue' => Order::where('restaurant_id', $restaurant->id)->whereDate('created_at', $today)->whereNotIn('status', ['cancelled'])->sum('total'),
            'active_orders' => Order::where('restaurant_id', $restaurant->id)->whereIn('status', ['pending', 'accepted', 'preparing', 'ready', 'picked_up'])->count(),
            'avg_rating' => round($restaurant->rating ?? 0, 1),
            'pending' => Order::where('restaurant_id', $restaurant->id)->where('status', 'pending')->count(),
            'preparing' => Order::where('restaurant_id', $restaurant->id)->where('status', 'preparing')->count(),
            'ready' => Order::where('restaurant_id', $restaurant->id)->where('status', 'ready')->count(),
            'on_delivery' => Order::where('restaurant_id', $restaurant->id)->whereIn('status', ['picked_up', 'on_the_way'])->count(),
        ];
        
        $recentOrders = Order::with('user')
            ->where('restaurant_id', $restaurant->id)
            ->latest()
            ->take(5)
            ->get()
            ->map(function($order) {
                return [
                    'id' => $order->id,
                    'order_number' => $order->order_number,
                    'customer_name' => $order->user->name ?? 'Guest',
                    'items_count' => $order->items()->count(),
                    'total' => $order->total,
                    'payment_method' => $order->payment_method,
                    'status' => $order->status,
                    'created_at' => $order->created_at,
                ];
            });
        
        return response()->json([
            'stats' => $stats,
            'recent_orders' => $recentOrders,
            'restaurant_name' => $restaurant->name,
        ]);
    }
    
    public function getRevenueChart(Request $request)
    {
        $restaurant = $this->getRestaurant($request);
        $period = $request->query('period', 'week');
        $days = $period === 'week' ? 7 : 30;
        
        $data = [];
        for ($i = $days - 1; $i >= 0; $i--) {
            $date = Carbon::today()->subDays($i);
            $revenue = Order::where('restaurant_id', $restaurant->id)
                ->whereDate('created_at', $date)
                ->whereNotIn('status', ['cancelled'])
                ->sum('total');
            
            $data[] = [
                'label' => $period === 'week' ? $date->format('D') : $date->format('d'),
                'revenue' => round($revenue, 2),
            ];
        }
        
        return response()->json($data);
    }

    private function getRestaurant(Request $request)
    {
        $user = $request->user();
        
        if (!$user->restaurant_id) {
            abort(404, 'No restaurant found');
        }
        
        return \App\Models\Restaurant::find($user->restaurant_id);
    }
}
