<?php

namespace App\Http\Controllers\Api\V1;

use App\Http\Controllers\Controller;
use App\Http\Resources\Api\OrderResource;
use App\Models\Order;
use App\Models\User;
use App\Services\ActivityLogService;
use App\Services\NotificationService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use Illuminate\Validation\Rule;

class DeliveryController extends Controller
{
    public function __construct(private readonly NotificationService $notifications)
    {
    }

    public function index(Request $request): JsonResponse
    {
        $this->authorizeAdmin($request);

        $query = Order::query()
            ->with(['user', 'address', 'livreur'])
            ->whereNotNull('livreur_id');

        if ($request->filled('status')) {
            $query->where('delivery_status', $request->status);
        }

        if ($request->filled('livreur_id')) {
            $query->where('livreur_id', $request->livreur_id);
        }

        $perPage = min((int) $request->get('per_page', 15), 50);
        $orders = $query->orderByDesc('created_at')->paginate($perPage);

        return response()->json([
            'data' => OrderResource::collection($orders->items()),
            'meta' => [
                'current_page' => $orders->currentPage(),
                'last_page' => $orders->lastPage(),
                'per_page' => $orders->perPage(),
                'total' => $orders->total(),
            ],
        ]);
    }

    public function assign(Request $request, Order $order): JsonResponse
    {
        $this->authorizeAdmin($request);

        $validated = $request->validate([
            'livreur_id' => ['required', 'exists:users,id'],
        ]);

        /** @var User $livreur */
        $livreur = User::where('id', $validated['livreur_id'])
            ->where('role', User::ROLE_LIVREUR)
            ->firstOrFail();

        $order->livreur_id = $livreur->id;
        $order->delivery_status = Order::DELIVERY_ASSIGNED;
        $order->delivery_assigned_at = now();
        $order->save();

        ActivityLogService::log(
            'delivery.assigned',
            $order,
            ['order_id' => $order->id, 'livreur_id' => $livreur->id, 'livreur_name' => $livreur->name],
            "Livreur assigné à la commande #{$order->id} : {$livreur->name}",
            $request->user()?->id,
            $request
        );

        $order->load('user');
        if ($order->user) {
            $this->notifications->notifyDeliveryStatus($order->user, $order->id, $order->number, 'Livreur assigné');
        }

        return response()->json([
            'data' => new OrderResource($order->fresh()->load(['user', 'address', 'livreur'])),
            'message' => __('Livreur assigné.'),
        ]);
    }

    public function my(Request $request): JsonResponse
    {
        $user = $request->user();
        if (! $user || $user->role !== User::ROLE_LIVREUR) {
            abort(403);
        }

        $orders = Order::with(['address'])
            ->where('livreur_id', $user->id)
            ->orderByDesc('created_at')
            ->get();

        return response()->json([
            'data' => OrderResource::collection($orders),
        ]);
    }

    public function livreurs(Request $request): JsonResponse
    {
        $this->authorizeAdmin($request);

        $livreurs = User::query()
            ->where('role', User::ROLE_LIVREUR)
            ->where('is_active', true)
            ->orderBy('name')
            ->get(['id', 'name', 'email', 'phone']);

        return response()->json([
            'data' => $livreurs,
        ]);
    }

    public function updateStatus(Request $request, Order $order): JsonResponse
    {
        $user = $request->user();
        if (! $user || $user->role !== User::ROLE_LIVREUR || $order->livreur_id !== $user->id) {
            abort(403);
        }

        $data = $request->validate([
            'status' => [
                'required',
                'string',
                Rule::in([
                    Order::DELIVERY_ACCEPTED,
                    Order::DELIVERY_PICKED_UP,
                    Order::DELIVERY_IN_TRANSIT,
                    Order::DELIVERY_DELIVERED,
                    Order::DELIVERY_FAILED,
                ]),
            ],
            'proof' => ['nullable', 'image', 'max:4096'],
        ]);

        $newStatus = $data['status'];

        // Simple state machine
        $allowedFrom = [
            Order::DELIVERY_ACCEPTED => [Order::DELIVERY_ASSIGNED, Order::DELIVERY_PENDING],
            Order::DELIVERY_PICKED_UP => [Order::DELIVERY_ACCEPTED],
            Order::DELIVERY_IN_TRANSIT => [Order::DELIVERY_PICKED_UP],
            Order::DELIVERY_DELIVERED => [Order::DELIVERY_IN_TRANSIT, Order::DELIVERY_PICKED_UP],
            Order::DELIVERY_FAILED => [
                Order::DELIVERY_ASSIGNED,
                Order::DELIVERY_ACCEPTED,
                Order::DELIVERY_PICKED_UP,
                Order::DELIVERY_IN_TRANSIT,
            ],
        ];

        $current = $order->delivery_status;
        if (! isset($allowedFrom[$newStatus]) || ! in_array($current, $allowedFrom[$newStatus], true)) {
            return response()->json([
                'message' => __('Transition de statut invalide.'),
            ], 422);
        }

        $order->delivery_status = $newStatus;

        if ($newStatus === Order::DELIVERY_DELIVERED) {
            $order->delivered_at = now();
            if ($request->hasFile('proof')) {
                if ($order->delivery_proof_path) {
                    Storage::disk('public')->delete($order->delivery_proof_path);
                }
                $order->delivery_proof_path = $request->file('proof')->store('deliveries', 'public');
            }
        }

        if ($newStatus === Order::DELIVERY_FAILED) {
            $order->delivered_at = null;
        }

        $order->save();

        ActivityLogService::log(
            'delivery.status_changed',
            $order,
            ['order_id' => $order->id, 'from' => $current, 'to' => $newStatus],
            "Statut de livraison changé pour la commande #{$order->id} : {$current} → {$newStatus}",
            $request->user()?->id,
            $request
        );

        $statusLabels = [
            Order::DELIVERY_ACCEPTED => 'Acceptée par le livreur',
            Order::DELIVERY_PICKED_UP => 'Commande récupérée',
            Order::DELIVERY_IN_TRANSIT => 'En cours de livraison',
            Order::DELIVERY_DELIVERED => 'Livrée',
            Order::DELIVERY_FAILED => 'Livraison échouée',
        ];
        $order->load('user');
        if ($order->user) {
            $this->notifications->notifyDeliveryStatus(
                $order->user,
                $order->id,
                $order->number,
                $statusLabels[$newStatus] ?? $newStatus
            );
        }

        return response()->json([
            'data' => new OrderResource($order->fresh()->load(['address', 'livreur'])),
            'message' => __('Statut de livraison mis à jour.'),
        ]);
    }

    protected function authorizeAdmin(Request $request): void
    {
        $user = $request->user();
        if (! $user || ! $user->isAdmin()) {
            abort(403);
        }
    }
}

