<?php

namespace App\Http\Controllers\Api\V1;

use App\Http\Controllers\Controller;
use App\Http\Requests\Api\StoreEmpletteRequest;
use App\Http\Requests\Api\UpdateEmpletteAdminRequest;
use App\Http\Resources\Api\EmpletteResource;
use App\Models\Emplette;
use App\Models\EmpletteItem;
use App\Models\EmpletteLog;
use App\Models\Order;
use App\Models\OrderItem;
use App\Services\AdminAlertMailService;
use App\Services\FedapayService;
use App\Services\NotificationService;
use App\Services\WhatsappEmpletteService;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\DB;

class EmpletteController extends Controller
{
    public function __construct(
        private readonly WhatsappEmpletteService $whatsapp,
        private readonly NotificationService $notifications,
        private readonly FedapayService $fedapay,
        private readonly AdminAlertMailService $adminMails
    ) {
    }

    public function index(Request $request)
    {
        $user = $request->user();

        $query = Emplette::query()
            ->with(['items', 'logs.user'])
            ->where('user_id', $user->id)
            ->latest();

        return EmpletteResource::collection($query->paginate(20));
    }

    public function store(StoreEmpletteRequest $request)
    {
        $user = $request->user();

        $data = $request->validated();

        $emplette = DB::transaction(function () use ($user, $data) {
            $emplette = Emplette::create([
                'user_id' => $user->id,
                'status' => Emplette::STATUS_SUBMITTED,
                'estimated_total' => collect($data['items'])->sum(function (array $item): float {
                    $quantity = (int) ($item['quantity'] ?? 1);
                    $price = (float) $item['client_price'];

                    return $quantity * $price;
                }),
                'final_total' => 0,
                'currency' => 'XOF',
                    // Séparation note client / note admin
                    'client_notes' => $data['client_notes'] ?? ($data['notes'] ?? null),
                    'admin_notes' => null,
            ]);

            foreach ($data['items'] as $item) {
                EmpletteItem::create([
                    'emplette_id' => $emplette->id,
                    'name' => $item['name'],
                    'quantity' => $item['quantity'] ?? 1,
                    'client_price' => $item['client_price'],
                    'admin_price' => 0,
                    'status' => EmpletteItem::STATUS_PENDING,
                ]);
            }

            EmpletteLog::create([
                'emplette_id' => $emplette->id,
                'user_id' => $user->id,
                'actor_type' => 'client',
                'action' => 'created',
                'payload' => $data,
                'message' => 'Nouvelle demande d\'emplette créée par le client.',
            ]);

            return $emplette;
        });

        $this->whatsapp->sendNewEmpletteToAdmin($emplette);
        $this->adminMails->sendNewEmpletteRequest($emplette);

        return new EmpletteResource(
            $emplette->load(['items', 'logs.user'])
        );
    }

    public function show(Request $request, Emplette $emplette)
    {
        $user = $request->user();

        if ($user->id !== $emplette->user_id && !$user->isAdmin()) {
            abort(Response::HTTP_FORBIDDEN);
        }

        return new EmpletteResource(
            $emplette->load(['user', 'items', 'logs.user', 'order'])
        );
    }

    public function adminIndex(Request $request)
    {
        $this->authorizeAdmin($request);

        $status = $request->query('status');

        $query = Emplette::query()
            ->with(['user', 'items'])
            ->latest();

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

        return EmpletteResource::collection($query->paginate(20));
    }

    public function adminUpdate(UpdateEmpletteAdminRequest $request, Emplette $emplette)
    {
        $this->authorizeAdmin($request);

        if ($emplette->quote_sent_at !== null) {
            return response()->json([
                'message' => 'Le devis a déjà été enregistré et le client a déjà été notifié (action unique).',
            ], Response::HTTP_UNPROCESSABLE_ENTITY);
        }

        $data = $request->validated();

        $admin = $request->user();

        $emplette = DB::transaction(function () use ($emplette, $data, $admin) {
            $itemsData = $data['items'];

            // on remplace la liste des items par celle envoyée (plus simple pour le front)
            $emplette->items()->delete();

            $finalTotal = 0;
            $estimatedTotal = 0;

            foreach ($itemsData as $item) {
                $quantity = (int) ($item['quantity'] ?? 1);
                $clientPrice = (float) ($item['client_price'] ?? 0);
                // Si l'admin ne modifie pas le montant (admin_price envoyé à 0),
                // on prend le montant du client par défaut pour éviter un final_total à 0.
                $adminPrice = (float) ($item['admin_price'] ?? 0);
                if ($adminPrice <= 0 && $clientPrice > 0) {
                    $adminPrice = $clientPrice;
                }

                $created = EmpletteItem::create([
                    'emplette_id' => $emplette->id,
                    'name' => $item['name'],
                    'quantity' => $quantity,
                    'client_price' => $clientPrice,
                    'admin_price' => $adminPrice,
                    'status' => EmpletteItem::STATUS_UPDATED,
                ]);

                $finalTotal += (float) $created->admin_price * $quantity;
                $estimatedTotal += (float) $created->client_price * $quantity;
            }

            $emplette->update([
                'status' => $data['status'] ?? Emplette::STATUS_QUOTED,
                'final_total' => $finalTotal,
                'estimated_total' => $estimatedTotal,
                'admin_notes' => $data['admin_notes'] ?? ($data['notes'] ?? $emplette->admin_notes),
                'quote_sent_at' => now(),
            ]);

            EmpletteLog::create([
                'emplette_id' => $emplette->id,
                'user_id' => $admin->id,
                'actor_type' => 'admin',
                'action' => 'quote_prepared',
                'payload' => $data,
                'message' => 'Devis préparé par l\'administrateur.',
            ]);

            return $emplette;
        });

        $this->whatsapp->sendQuoteToClient($emplette);

        $emplette->load('user');
        if ($emplette->user) {
            $this->notifications->notifyEmpletteQuote(
                $emplette->user,
                $emplette->id,
                'Votre demande d\'emplette a été traitée. Consultez le devis dans l\'application.'
            );
        }

        return new EmpletteResource(
            $emplette->fresh()->load(['user', 'items', 'logs.user', 'order'])
        );
    }

    public function clientDecision(Request $request, Emplette $emplette)
    {
        $user = $request->user();

        if ($user->id !== $emplette->user_id) {
            abort(Response::HTTP_FORBIDDEN);
        }

        $validated = $request->validate([
            'decision' => ['required', 'string', 'in:accept,reject'],
        ]);

        $decision = $validated['decision'];

        DB::transaction(function () use ($emplette, $user, $decision) {
            if ($decision === 'accept') {
                $emplette->update([
                    'status' => Emplette::STATUS_ACCEPTED,
                ]);

                EmpletteLog::create([
                    'emplette_id' => $emplette->id,
                    'user_id' => $user->id,
                    'actor_type' => 'client',
                    'action' => 'accepted',
                    'payload' => null,
                    'message' => 'Le client a accepté le devis.',
                ]);
            } else {
                // Si une commande a été créée, on la marque comme annulée.
                if ($emplette->order_id) {
                    $emplette->order()->update([
                        'status' => Order::STATUS_CANCELLED,
                        'payment_status' => Order::PAYMENT_FAILED,
                    ]);
                }

                $emplette->update([
                    'status' => Emplette::STATUS_REJECTED,
                ]);

                EmpletteLog::create([
                    'emplette_id' => $emplette->id,
                    'user_id' => $user->id,
                    'actor_type' => 'client',
                    'action' => 'rejected',
                    'payload' => null,
                    'message' => 'Le client a refusé le devis.',
                ]);
            }
        });

        if ($decision === 'accept') {
            $this->adminMails->sendEmpletteAccepted($emplette->fresh());
        }

        return new EmpletteResource(
            $emplette->fresh()->load(['user', 'items', 'logs.user'])
        );
    }

    public function initPayment(Request $request, Emplette $emplette)
    {
        $user = $request->user();
        if ($user->id !== $emplette->user_id) {
            abort(Response::HTTP_FORBIDDEN);
        }

        if (! in_array($emplette->status, [Emplette::STATUS_ACCEPTED, Emplette::STATUS_CLIENT_REVIEW], true)) {
            return response()->json([
                'message' => 'La demande doit être acceptée avant le paiement.',
            ], Response::HTTP_UNPROCESSABLE_ENTITY);
        }

        $emplette->loadMissing(['user', 'items', 'order']);

        $order = DB::transaction(function () use ($emplette, $user) {
            if ($emplette->order && $emplette->order->payment_status === Order::PAYMENT_PENDING) {
                return $emplette->order;
            }

            if ($emplette->order && $emplette->order->payment_status === Order::PAYMENT_PAID) {
                return $emplette->order;
            }

            $order = Order::create([
                'number' => Order::generateNumber(),
                'user_id' => $user->id,
                'address_id' => null,
                'subtotal' => $emplette->final_total,
                'delivery_fee' => 0,
                'total' => $emplette->final_total,
                'status' => Order::STATUS_PENDING,
                'payment_status' => Order::PAYMENT_PENDING,
            ]);

            foreach ($emplette->items as $item) {
                OrderItem::create([
                    'order_id' => $order->id,
                    'product_id' => null,
                    'product_name' => $item->name,
                    'quantity' => $item->quantity,
                    'unit_price' => $item->admin_price,
                    'total' => $item->admin_price * $item->quantity,
                ]);
            }

            $emplette->update(['order_id' => $order->id]);
            $this->adminMails->sendNewOrder($order);

            return $order;
        });

        if ($order->payment_status === Order::PAYMENT_PAID) {
            return response()->json([
                'data' => [
                    'order_id' => $order->id,
                    'redirect_url' => null,
                ],
                'message' => 'Commande déjà payée.',
            ]);
        }

        if (! $this->fedapay->isEnabled()) {
            $redirectUrl = url('/api/v1/payment/simulate?order_id=' . $order->id . '&token=' . $order->id);

            return response()->json([
                'data' => [
                    'order_id' => $order->id,
                    'redirect_url' => $redirectUrl,
                ],
                'message' => 'Redirection vers paiement (simulation).',
            ]);
        }

        try {
            $payment = $this->fedapay->createTransaction($order, $user);
        } catch (\RuntimeException $e) {
            return response()->json(['message' => $e->getMessage()], 422);
        }

        $order->update([
            'payment_status' => Order::PAYMENT_PENDING,
            'payment_reference' => 'fedapay_tx_' . $payment['transaction_id'],
        ]);

        EmpletteLog::create([
            'emplette_id' => $emplette->id,
            'user_id' => $user->id,
            'actor_type' => 'client',
            'action' => 'payment_initiated',
            'payload' => ['order_id' => $order->id],
            'message' => 'Paiement du devis initié par le client.',
        ]);

        return response()->json([
            'data' => [
                'order_id' => $order->id,
                'redirect_url' => $payment['redirect_url'],
            ],
            'message' => 'Redirection vers paiement.',
        ]);
    }

    public function convertToOrder(Request $request, Emplette $emplette)
    {
        $this->authorizeAdmin($request);

        $validated = $request->validate([
            'mark_order_paid' => ['sometimes', 'boolean'],
        ]);
        $markOrderPaid = (bool) ($validated['mark_order_paid'] ?? false);

        if ($emplette->order_id) {
            return response()->json([
                'message' => 'Une commande existe déjà pour cette demande.',
                'order_id' => $emplette->order_id,
            ]);
        }

        if (! in_array($emplette->status, [Emplette::STATUS_ACCEPTED, Emplette::STATUS_QUOTED], true)) {
            return response()->json([
                'message' => 'La demande doit être acceptée (ou devis préparé) avant de créer une commande.',
            ], Response::HTTP_UNPROCESSABLE_ENTITY);
        }

        $admin = $request->user();

        $order = DB::transaction(function () use ($emplette, $markOrderPaid, $admin) {
            $user = $emplette->user;

            $order = Order::create([
                'number' => Order::generateNumber(),
                'user_id' => $user->id,
                'address_id' => null,
                'subtotal' => $emplette->final_total,
                'delivery_fee' => 0,
                'total' => $emplette->final_total,
                'status' => Order::STATUS_PENDING,
                'payment_status' => Order::PAYMENT_PENDING,
            ]);

            foreach ($emplette->items as $item) {
                OrderItem::create([
                    'order_id' => $order->id,
                    'product_id' => null,
                    'product_name' => $item->name,
                    'quantity' => $item->quantity,
                    'unit_price' => $item->admin_price,
                    'total' => $item->admin_price * $item->quantity,
                ]);
            }

            if ($markOrderPaid) {
                $order->update([
                    'payment_status' => Order::PAYMENT_PAID,
                    'status' => Order::STATUS_PAID,
                    'paid_at' => now(),
                    'payment_reference' => 'manual_admin_emplette_' . $order->id,
                ]);
            }
            $this->adminMails->sendNewOrder($order);

            $emplette->update([
                'status' => Emplette::STATUS_CONVERTED,
                'order_id' => $order->id,
            ]);

            EmpletteLog::create([
                'emplette_id' => $emplette->id,
                'user_id' => $admin->id,
                'actor_type' => 'admin',
                'action' => 'converted_to_order',
                'payload' => [
                    'order_id' => $order->id,
                    'mark_order_paid' => $markOrderPaid,
                ],
                'message' => $markOrderPaid
                    ? 'Conversion en commande par l’administrateur (commande marquée comme payée).'
                    : 'La demande emplette a été convertie en commande.',
            ]);

            return $order->fresh(['user']);
        });

        if ($markOrderPaid && $order->user) {
            $this->notifications->notifyOrderStatus($order->user, $order->id, $order->number, 'Payée');
            $this->adminMails->sendEmplettePayment($emplette->fresh(), $order);
        }

        return response()->json([
            'message' => $markOrderPaid
                ? 'Commande créée et marquée comme payée.'
                : 'Commande créée avec succès depuis la demande emplette.',
            'order_id' => $order->id,
            'payment_status' => $order->payment_status,
        ]);
    }

    private function authorizeAdmin(Request $request): void
    {
        $user = $request->user();

        if (!$user || !$user->isAdmin()) {
            abort(Response::HTTP_FORBIDDEN);
        }
    }
}

