<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Models\UserPaymentMethod;
use App\Services\Payments\PaymentGatewayManager;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use RuntimeException;

class PayPalVaultController extends Controller
{
    public function createSetupOrder(
        Request $request,
        PaymentGatewayManager $gatewayManager,
    ): JsonResponse {
        $user = $request->user();
        abort_unless($user && $user->role === 'client', 403);

        $data = $request->validate([
            'return_url' => ['nullable', 'url'],
            'cancel_url' => ['nullable', 'url'],
        ]);

        $returnUrl = (string) ($data['return_url'] ?? 'https://lineupfrance.com/paypal/return');
        $cancelUrl = (string) ($data['cancel_url'] ?? 'https://lineupfrance.com/paypal/cancel');

        try {
            $setup = $gatewayManager->paypalGateway()->createVaultSetupOrder(
                context: [
                    'return_url' => $returnUrl,
                    'cancel_url' => $cancelUrl,
                    'custom_id' => 'user_' . $user->id,
                ],
            );
        } catch (RuntimeException $exception) {
            return response()->json([
                'message' => $exception->getMessage(),
            ], 422);
        }

        return response()->json([
            'data' => [
                'setup_token_id' => $setup['setup_token_id'] ?? $setup['order_id'] ?? null,
                'order_id' => $setup['order_id'] ?? $setup['setup_token_id'] ?? null,
                'approve_url' => $setup['approve_url'] ?? null,
                'status' => $setup['status'] ?? null,
                'payload' => $setup['payload'] ?? [],
            ],
        ], 201);
    }

    public function captureSetupOrder(
        Request $request,
        PaymentGatewayManager $gatewayManager,
    ): JsonResponse {
        $user = $request->user();
        abort_unless($user && $user->role === 'client', 403);

        $data = $request->validate([
            'setup_token_id' => ['nullable', 'string', 'max:255'],
            'order_id' => ['nullable', 'string', 'max:255'],
            'label' => ['nullable', 'string', 'max:150'],
            'email' => ['nullable', 'email', 'max:255'],
            'is_default' => ['nullable', 'boolean'],
        ]);

        $setupTokenId = (string) ($data['setup_token_id'] ?? $data['order_id'] ?? '');
        if ($setupTokenId === '') {
            return response()->json([
                'message' => 'setup_token_id ou order_id est requis.',
            ], 422);
        }

        try {
            $captured = $gatewayManager->paypalGateway()->captureVaultSetupOrder($setupTokenId);
        } catch (RuntimeException $exception) {
            return response()->json([
                'message' => $exception->getMessage(),
            ], 422);
        }

        $isDefault = (bool) ($data['is_default'] ?? true);
        $vaultId = $captured['vault_id'] ?? null;
        $resolvedSetupTokenId = (string) ($captured['setup_token_id'] ?? $captured['order_id'] ?? $setupTokenId);

        $method = DB::transaction(function () use ($user, $captured, $data, $vaultId, $isDefault, $resolvedSetupTokenId): UserPaymentMethod {
            if ($isDefault) {
                UserPaymentMethod::query()
                    ->where('user_id', $user->id)
                    ->where('type', UserPaymentMethod::TYPE_PAY_IN)
                    ->update(['is_default' => false]);
            }

            $existing = UserPaymentMethod::query()
                ->where('user_id', $user->id)
                ->where('type', UserPaymentMethod::TYPE_PAY_IN)
                ->where('provider', 'paypal')
                ->get()
                ->first(function (UserPaymentMethod $method) use ($vaultId, $resolvedSetupTokenId): bool {
                    $details = is_array($method->details) ? $method->details : [];

                    if (is_string($vaultId) && $vaultId !== '' && ($details['vault_id'] ?? null) === $vaultId) {
                        return true;
                    }

                    return ($details['setup_token_id'] ?? $details['setup_order_id'] ?? null) === $resolvedSetupTokenId;
                });

            $email = $captured['payer_email'] ?? $data['email'] ?? $user->email;
            $isVerified = is_string($vaultId) && $vaultId !== '';

            $details = [
                'email' => is_string($email) ? $email : $user->email,
                'vault_id' => $isVerified ? $vaultId : null,
                'vault_token' => $isVerified ? $vaultId : null,
                'vault_token_type' => $isVerified ? 'PAYPAL_VAULT_ID' : 'SETUP_TOKEN',
                'vault_status' => $captured['vault_status'] ?? ($isVerified ? 'APPROVED' : 'PAYER_ACTION_REQUIRED'),
                'payer_id' => $captured['payer_id'] ?? null,
                'setup_token_id' => $resolvedSetupTokenId,
                'setup_order_id' => $resolvedSetupTokenId,
                'provider_reference' => $captured['capture_id'] ?? $resolvedSetupTokenId,
            ];

            $attributes = [
                'label' => $data['label'] ?? ($existing?->label ?: 'PayPal'),
                'account_holder' => ($existing?->account_holder) ?: ($user->name ?? 'Client'),
                'details' => $details,
                'is_default' => $isDefault,
                'is_active' => true,
                'verified_at' => $isVerified ? now() : null,
            ];

            if ($existing) {
                $existing->update($attributes);
                return $existing->fresh();
            }

            return UserPaymentMethod::create([
                'user_id' => $user->id,
                'type' => UserPaymentMethod::TYPE_PAY_IN,
                'provider' => 'paypal',
                ...$attributes,
            ]);
        });

        $statusCode = $method->verified_at !== null ? 201 : 202;
        $message = $method->verified_at !== null
            ? 'Moyen de paiement PayPal ajoute.'
            : 'Setup PayPal enregistre. Finalisation en attente du webhook PayPal.';

        return response()->json([
            'message' => $message,
            'data' => [
                'payment_method' => $method,
                'capture' => $captured,
            ],
        ], $statusCode);
    }
}
