<?php

namespace App\Services;

use App\Mail\OrderConfirmation;
use App\Models\Order;
use App\Models\Product;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

/**
 * Finalise une commande après paiement Stripe (webhook ou synchro au retour client).
 * Idempotent : ne décrémente pas le stock deux fois ni n’envoie plusieurs e-mails client.
 */
class FinalizeOrderPaymentService
{
    public function __construct(
        protected StripeService $stripeService,
        protected MailService $mailService
    ) {}

    /**
     * Appelé depuis le webhook payment_intent.succeeded.
     */
    public function finalizeFromWebhookPaymentIntent(object $intent): void
    {
        if (($intent->status ?? null) !== 'succeeded') {
            return;
        }

        $order = $this->resolveOrderForIntent($intent);
        if (! $order) {
            Log::info('Stripe webhook: aucune commande pour ce PaymentIntent', ['payment_intent' => $intent->id ?? null]);

            return;
        }

        $expectedCents = (int) round((float) $order->total * 100);
        if ((int) ($intent->amount ?? 0) !== $expectedCents) {
            Log::warning('Stripe webhook: montant PaymentIntent ≠ total commande', [
                'order_id' => $order->id,
                'expected_cents' => $expectedCents,
                'intent_amount' => $intent->amount ?? null,
            ]);

            return;
        }

        $this->markOrderPaidDecrementStockNotifyCustomer($order);
    }

    /**
     * Au retour sur la page confirmation après paiement : interroge l’API Stripe si encore en attente.
     * Utile si le webhook n’a pas atteint le serveur (local, pare-feu, mauvaise URL).
     */
    public function syncFromStripeIfPending(Order $order): bool
    {
        $order->refresh();
        if ($order->status === 'paid') {
            return true;
        }
        if ($order->status !== 'pending' || ! $order->stripe_payment_intent_id) {
            return false;
        }
        if (! $this->stripeService->isConfigured()) {
            return false;
        }

        $intent = $this->stripeService->retrievePaymentIntent($order->stripe_payment_intent_id);
        if (! $intent || $intent->status !== 'succeeded') {
            return false;
        }

        $expectedCents = (int) round((float) $order->total * 100);
        if ((int) $intent->amount !== $expectedCents) {
            Log::warning('Stripe sync: montant PaymentIntent ≠ total commande', [
                'order_id' => $order->id,
                'expected_cents' => $expectedCents,
                'intent_amount' => $intent->amount,
            ]);

            return false;
        }

        $this->markOrderPaidDecrementStockNotifyCustomer($order);

        return true;
    }

    protected function resolveOrderForIntent(object $intent): ?Order
    {
        $order = Order::where('stripe_payment_intent_id', $intent->id)->first();

        if (! $order && ! empty($intent->metadata['order_id'])) {
            $order = Order::find((int) $intent->metadata['order_id']);
            if ($order && $order->stripe_payment_intent_id !== $intent->id) {
                $order->update([
                    'stripe_payment_intent_id' => $intent->id,
                    'stripe_payment_status' => $intent->status ?? null,
                ]);
                $order->refresh();
            }
        }

        return $order;
    }

    protected function markOrderPaidDecrementStockNotifyCustomer(Order $order): void
    {
        DB::transaction(function () use ($order) {
            $order = Order::query()->lockForUpdate()->find($order->id);
            if (! $order || $order->status === 'paid') {
                return;
            }

            $order->update([
                'status' => 'paid',
                'stripe_payment_status' => 'succeeded',
            ]);

            foreach ($order->items ?? [] as $item) {
                $product = Product::find($item['product_id'] ?? null);
                if ($product && $product->stock !== null) {
                    $product->decrement('stock', (int) ($item['qty'] ?? 0));
                }
            }

            if ($this->mailService->isConfigured()) {
                $this->mailService->send(new OrderConfirmation($order->fresh()));
            }
        });
    }
}
