<?php

namespace App\Http\Controllers\Coach;

use App\Http\Controllers\Controller;
use App\Models\Bank;
use App\Models\Invoice;
use App\Models\Payment;
use App\Models\Plan;
use App\Models\Setting;
use App\Models\Subscription;
use App\Models\SubscriptionAuditLog;
use App\Models\User;
use App\Notifications\AdminPaymentReceived;
use App\Notifications\InvoiceGenerated;
use App\Notifications\InvoicePaid;
use App\Services\PaymentService;
use App\Services\PdfService;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Inertia\Inertia;
use Inertia\Response;

class PaymentController extends Controller
{
    protected PaymentService $paymentService;
    protected PdfService $pdfService;

    public function __construct(PaymentService $paymentService, PdfService $pdfService)
    {
        $this->paymentService = $paymentService;
        $this->pdfService = $pdfService;
    }

    /**
     * Show checkout page for a plan.
     */
    public function checkout(Request $request, Plan $plan): Response|RedirectResponse
    {
        $user = $request->user();

        // Validate plan is active
        if (!$plan->is_active) {
            return redirect()->route('coach.subscription.index')
                ->with('error', 'El plan seleccionado no está disponible actualmente.');
        }

        // Ensure plan price is numeric
        $planData = $plan->toArray();
        $planData['price'] = (float) $plan->price;

        // Get wallet balance
        $wallet = $user->wallet;
        $walletBalance = $wallet ? (float) $wallet->balance : 0;

        // Clear any old plan purchase intent from session
        session()->forget('plan_purchase_intent');

        return Inertia::render('Coach/Subscription/Checkout', [
            'plan' => $planData,
            'currentPlan' => $user->currentPlan(),
            'paymentMethods' => $this->paymentService->getAvailableMethods(),
            'banks' => Bank::active()->ordered()->get(),
            'taxes' => [], // Sin impuestos
            'walletBalance' => $walletBalance,
            'settings' => [
                'currency' => Setting::get('currency', 'USD'),
                'tax_rate' => 0, // Sin impuestos
                'paypal_sandbox' => Setting::get('paypal_sandbox', true),
                'stripe_test_mode' => Setting::get('stripe_test_mode', true),
                'stripe_fee_enabled' => Setting::get('stripe_fee_enabled', false),
                'paypal_fee_enabled' => Setting::get('paypal_fee_enabled', false),
                'wallet_payment_enabled' => Setting::get('feature_wallet', true),
            ],
        ]);
    }

    /**
     * Process payment based on method.
     */
    public function process(Request $request, Plan $plan): RedirectResponse|\Illuminate\Http\Response
    {
        // Validate plan is active and available
        if (!$plan->is_active) {
            return back()->with('error', 'El plan seleccionado no está disponible actualmente.');
        }

        $validated = $request->validate([
            'payment_method' => 'required|in:stripe,paypal,bank_transfer,wallet',
            'selected_bank_id' => 'nullable|required_if:payment_method,bank_transfer|exists:banks,id',
            'receipt_file' => 'nullable|file|mimes:jpeg,jpg,png,webp,pdf|max:5120',
        ], [
            'payment_method.required' => 'Debes seleccionar un método de pago.',
            'payment_method.in' => 'El método de pago seleccionado no es válido.',
            'selected_bank_id.required_if' => 'Debes seleccionar el banco donde realizarás el pago.',
            'receipt_file.mimes' => 'El comprobante debe ser una imagen (JPG, PNG, WebP) o PDF.',
            'receipt_file.max' => 'El comprobante no debe superar 5MB.',
        ]);

        $user = $request->user();
        $method = $validated['payment_method'];

        // Validate payment method is available
        $availableMethods = $this->paymentService->getAvailableMethods();
        $methodExists = collect($availableMethods)->contains('id', $method);

        if ($method !== 'wallet' && !$methodExists) {
            return back()->with('error', 'El método de pago seleccionado no está disponible en este momento.');
        }

        // Handle wallet payment
        if ($method === 'wallet') {
            return $this->processWalletPayment($user, $plan);
        }

        try {
            // Create pending subscription
            $subscription = $this->createPendingSubscription($user, $plan);

            // Create invoice with fee calculation
            $invoice = $this->createInvoice($user, $subscription, $plan, $method);

            // Create payment record
            $payment = Payment::create([
                'user_id' => $user->id,
                'subscription_id' => $subscription->id,
                'invoice_id' => $invoice->id,
                'gateway' => $method,
                'amount' => $invoice->total,
                'currency' => Setting::get('currency', 'USD'),
                'status' => 'pending',
            ]);

            // Route to appropriate payment handler
            return match($method) {
                'stripe' => $this->processStripe($invoice, $payment),
                'paypal' => $this->processPayPal($invoice, $payment),
                'bank_transfer' => $this->processBankTransfer($request, $invoice, $payment, $user),
            };
        } catch (\Exception $e) {
            Log::error('Error processing payment', [
                'user_id' => $user->id,
                'plan_id' => $plan->id,
                'method' => $method,
                'error' => $e->getMessage(),
            ]);

            return back()->with('error', 'Hubo un error al procesar tu pago. Por favor, intenta nuevamente o contacta con soporte.');
        }
    }

    /**
     * Process payment using wallet balance.
     */
    protected function processWalletPayment($user, Plan $plan): RedirectResponse
    {
        $wallet = $user->wallet;
        $planPrice = (float) $plan->price;

        // Validate wallet exists and has sufficient balance
        if (!$wallet) {
            return back()->with('error', 'No tienes una billetera activa. Por favor, recarga tu billetera primero.');
        }

        if (!$wallet->hasSufficientBalance($planPrice)) {
            return back()->with('error', 'Saldo insuficiente en tu billetera. Tu saldo actual es $' . number_format($wallet->balance, 2) . ' y el plan cuesta $' . number_format($planPrice, 2));
        }

        try {
            // Create pending subscription
            $subscription = $this->createPendingSubscription($user, $plan);

            // Create invoice
            $invoice = Invoice::create([
                'user_id' => $user->id,
                'subscription_id' => $subscription->id,
                'invoice_number' => Invoice::generateNumber(),
                'subtotal' => $planPrice,
                'tax' => 0,
                'total' => $planPrice,
                'status' => 'paid',
                'payment_method' => 'wallet',
                'paid_at' => now(),
                'items' => json_encode([
                    [
                        'description' => "Plan {$plan->name} - {$plan->duration_days} días",
                        'quantity' => 1,
                        'unit_price' => $planPrice,
                        'total' => $planPrice,
                    ]
                ]),
            ]);

            // Process wallet payment
            $walletTransaction = $wallet->paySubscription($planPrice, $subscription->id, $plan->name);

            // Create payment record
            $payment = Payment::create([
                'user_id' => $user->id,
                'subscription_id' => $subscription->id,
                'invoice_id' => $invoice->id,
                'gateway' => 'wallet',
                'amount' => $planPrice,
                'currency' => Setting::get('currency', 'USD'),
                'status' => 'completed',
                'gateway_payment_id' => 'WALLET-' . $walletTransaction->id,
                'paid_at' => now(),
                'metadata' => [
                    'wallet_transaction_id' => $walletTransaction->id,
                    'wallet_balance_after' => $wallet->balance,
                ],
            ]);

            // Log the audit
            SubscriptionAuditLog::create([
                'subscription_id' => $subscription->id,
                'user_id' => $user->id,
                'action' => 'wallet_payment',
                'old_value' => null,
                'new_value' => json_encode([
                    'amount' => $planPrice,
                    'wallet_transaction_id' => $walletTransaction->id,
                ]),
                'notes' => "Pago con saldo de billetera por {$planPrice}",
                'ip_address' => request()->ip(),
            ]);

            // Generate PDF
            $this->pdfService->generateInvoice($invoice);

            // Activate subscription
            // Expire current active subscriptions
            Subscription::where('user_id', $subscription->user_id)
                ->where('id', '!=', $subscription->id)
                ->where('status', 'active')
                ->update(['status' => 'expired']);

            // Activate new subscription
            $subscription->update([
                'status' => 'active',
                'start_date' => now(),
                'end_date' => now()->addDays($plan->duration_days),
            ]);

            // Send notifications
            $user->notify(new InvoicePaid($invoice));

            // Notify admins
            $admins = User::where('role', 'admin')->get();
            foreach ($admins as $admin) {
                $admin->notify(new AdminPaymentReceived($invoice, 'subscription'));
            }

            return redirect()->route('coach.subscription.index')
                ->with('success', '¡Pago completado con éxito! Tu suscripción al plan ' . $plan->name . ' ha sido activada.');

        } catch (\Exception $e) {
            Log::error('Wallet payment error: ' . $e->getMessage(), [
                'user_id' => $user->id,
                'plan_id' => $plan->id,
                'trace' => $e->getTraceAsString(),
            ]);

            return back()->with('error', 'Error al procesar el pago: ' . $e->getMessage());
        }
    }

    /**
     * Create pending subscription.
     */
    protected function createPendingSubscription($user, Plan $plan): Subscription
    {
        // Check for existing pending subscriptions and cancel them
        Subscription::where('user_id', $user->id)
            ->where('status', 'pending')
            ->update(['status' => 'cancelled']);

        return Subscription::create([
            'user_id' => $user->id,
            'plan_id' => $plan->id,
            'start_date' => now(),
            'end_date' => now()->addDays($plan->duration_days),
            'status' => 'pending',
        ]);
    }

    /**
     * Calculate payment gateway fee.
     */
    protected function calculateGatewayFee(float $subtotal, string $method): array
    {
        $fee = 0;
        $feeLabel = null;

        if ($method === 'stripe' && Setting::get('stripe_fee_enabled', false)) {
            // Stripe: 2.9% + $0.30
            $percentFee = 0.029;
            $fixedFee = 0.30;
            $totalWithFee = ($subtotal + $fixedFee) / (1 - $percentFee);
            $fee = round($totalWithFee - $subtotal, 2);
            $feeLabel = 'Tarifa Stripe (2.9% + $0.30)';
        } elseif ($method === 'paypal' && Setting::get('paypal_fee_enabled', false)) {
            // PayPal: 3.49% + $0.49
            $percentFee = 0.0349;
            $fixedFee = 0.49;
            $totalWithFee = ($subtotal + $fixedFee) / (1 - $percentFee);
            $fee = round($totalWithFee - $subtotal, 2);
            $feeLabel = 'Tarifa PayPal (3.49% + $0.49)';
        }

        return ['fee' => $fee, 'label' => $feeLabel];
    }

    /**
     * Create invoice for subscription.
     */
    protected function createInvoice($user, Subscription $subscription, Plan $plan, string $paymentMethod): Invoice
    {
        $subtotal = (float) $plan->price;
        $feeData = $this->calculateGatewayFee($subtotal, $paymentMethod);
        $fee = $feeData['fee'];
        $total = $subtotal + $fee;

        $items = [
            [
                'description' => "Plan {$plan->name} - {$plan->duration_days} días",
                'quantity' => 1,
                'unit_price' => $subtotal,
                'total' => $subtotal,
            ]
        ];

        // Add fee as line item if applicable
        if ($fee > 0) {
            $items[] = [
                'description' => $feeData['label'],
                'quantity' => 1,
                'unit_price' => $fee,
                'total' => $fee,
            ];
        }

        return Invoice::create([
            'user_id' => $user->id,
            'subscription_id' => $subscription->id,
            'invoice_number' => Invoice::generateNumber(),
            'subtotal' => $subtotal,
            'tax' => $fee, // Using tax field for fee
            'total' => $total,
            'status' => 'pending',
            'items' => json_encode($items),
            'taxes_applied' => $fee > 0 ? [['name' => $feeData['label'], 'amount' => $fee]] : [],
        ]);
    }

    /**
     * Process Stripe payment.
     */
    protected function processStripe(Invoice $invoice, Payment $payment)
    {
        try {
            $session = $this->paymentService->createStripeSession(
                $invoice,
                route('coach.payment.stripe.success', ['payment' => $payment->id]),
                route('coach.payment.stripe.cancel', ['payment' => $payment->id])
            );

            // Store session ID
            $payment->update([
                'gateway_payment_id' => $session->id,
                'metadata' => ['stripe_session_id' => $session->id],
            ]);

            // Use Inertia::location for external redirect (required for Inertia.js)
            return Inertia::location($session->url);
        } catch (\Exception $e) {
            return back()->with('error', 'Error al procesar pago con Stripe: ' . $e->getMessage());
        }
    }

    /**
     * Process PayPal payment.
     */
    protected function processPayPal(Invoice $invoice, Payment $payment)
    {
        try {
            Log::info('PayPal: Starting payment process', [
                'invoice_id' => $invoice->id,
                'payment_id' => $payment->id,
                'amount' => $invoice->total,
            ]);

            $order = $this->paymentService->createPayPalOrder(
                $invoice,
                route('coach.payment.paypal.success', ['payment' => $payment->id]),
                route('coach.payment.paypal.cancel', ['payment' => $payment->id])
            );

            Log::info('PayPal: Order response received', [
                'has_id' => isset($order['id']),
                'order_id' => $order['id'] ?? 'N/A',
                'status' => $order['status'] ?? 'N/A',
            ]);

            if (isset($order['id'])) {
                $payment->update([
                    'gateway_payment_id' => $order['id'],
                    'metadata' => ['paypal_order_id' => $order['id']],
                ]);

                // Find approval URL
                $approvalUrl = collect($order['links'] ?? [])
                    ->firstWhere('rel', 'approve')['href'] ?? null;

                Log::info('PayPal: Approval URL', [
                    'has_url' => !empty($approvalUrl),
                    'url_prefix' => $approvalUrl ? substr($approvalUrl, 0, 50) . '...' : 'N/A',
                ]);

                if ($approvalUrl) {
                    // Use Inertia::location for external redirect (required for Inertia.js)
                    return Inertia::location($approvalUrl);
                }

                return back()->with('error', 'No se encontró la URL de aprobación de PayPal.');
            }

            // Log the error details
            Log::error('PayPal: Order creation failed', [
                'response' => $order,
                'invoice_id' => $invoice->id,
            ]);

            return back()->with('error', 'Error al crear orden de PayPal. Por favor, intente nuevamente.');
        } catch (\Exception $e) {
            Log::error('PayPal: Payment process error', [
                'message' => $e->getMessage(),
                'invoice_id' => $invoice->id,
                'trace' => $e->getTraceAsString(),
            ]);

            return back()->with('error', 'Error al procesar pago con PayPal: ' . $e->getMessage());
        }
    }

    /**
     * Process bank transfer.
     */
    protected function processBankTransfer(Request $request, Invoice $invoice, Payment $payment, $user): RedirectResponse
    {
        $updateData = [
            'payment_method' => 'bank_transfer',
            'notes' => 'Transferencia bancaria pendiente de confirmación.',
        ];

        // Save selected bank
        if ($request->filled('selected_bank_id')) {
            $updateData['selected_bank_id'] = $request->input('selected_bank_id');
        }

        // Handle receipt file upload
        if ($request->hasFile('receipt_file')) {
            $receiptPath = $request->file('receipt_file')->store(
                'subscription-receipts/' . $user->id,
                'public'
            );
            $updateData['receipt_path'] = $receiptPath;
        }

        $invoice->update($updateData);

        // Generate PDF invoice
        $this->pdfService->generateInvoice($invoice);

        // Notify user
        $user->notify(new InvoiceGenerated($invoice));

        return redirect()->route('coach.subscription.payment-pending', $invoice)
            ->with('success', 'Orden creada. Complete el pago para activar su suscripción.');
    }

    /**
     * Handle Stripe success callback.
     */
    public function stripeSuccess(Request $request, Payment $payment): RedirectResponse
    {
        $sessionId = $request->get('session_id');

        if (!$sessionId) {
            return redirect()->route('coach.subscription.index')
                ->with('error', 'Sesión de pago no válida.');
        }

        try {
            $result = $this->paymentService->verifyStripePayment($sessionId);

            if ($result['success']) {
                $this->completePayment($payment, 'stripe', $sessionId);

                return redirect()->route('coach.subscription.index')
                    ->with('success', '¡Pago completado! Tu suscripción ha sido activada.');
            }

            return redirect()->route('coach.subscription.index')
                ->with('error', 'El pago no pudo ser verificado.');
        } catch (\Exception $e) {
            return redirect()->route('coach.subscription.index')
                ->with('error', 'Error al verificar el pago: ' . $e->getMessage());
        }
    }

    /**
     * Handle Stripe cancel callback.
     */
    public function stripeCancel(Payment $payment): RedirectResponse
    {
        $payment->update(['status' => 'cancelled']);

        return redirect()->route('coach.subscription.index')
            ->with('warning', 'Pago cancelado. Puedes intentar de nuevo cuando lo desees.');
    }

    /**
     * Handle PayPal success callback.
     */
    public function paypalSuccess(Request $request, Payment $payment): RedirectResponse
    {
        $orderId = $payment->gateway_payment_id;

        if (!$orderId) {
            return redirect()->route('coach.subscription.index')
                ->with('error', 'Orden de PayPal no válida.');
        }

        try {
            $result = $this->paymentService->capturePayPalPayment($orderId);

            if (isset($result['status']) && $result['status'] === 'COMPLETED') {
                $this->completePayment($payment, 'paypal', $result['id'] ?? $orderId);

                return redirect()->route('coach.subscription.index')
                    ->with('success', '¡Pago completado! Tu suscripción ha sido activada.');
            }

            return redirect()->route('coach.subscription.index')
                ->with('error', 'El pago de PayPal no pudo ser completado.');
        } catch (\Exception $e) {
            return redirect()->route('coach.subscription.index')
                ->with('error', 'Error al procesar pago de PayPal: ' . $e->getMessage());
        }
    }

    /**
     * Handle PayPal cancel callback.
     */
    public function paypalCancel(Payment $payment): RedirectResponse
    {
        $payment->update(['status' => 'cancelled']);

        return redirect()->route('coach.subscription.index')
            ->with('warning', 'Pago cancelado. Puedes intentar de nuevo cuando lo desees.');
    }

    /**
     * Complete payment and activate subscription.
     */
    protected function completePayment(Payment $payment, string $method, string $transactionId): void
    {
        // Update payment
        $payment->update([
            'status' => 'completed',
            'gateway_status' => 'completed',
            'paid_at' => now(),
        ]);

        // Update invoice
        $payment->invoice->update([
            'status' => 'paid',
            'payment_method' => $method,
            'transaction_id' => $transactionId,
            'paid_at' => now(),
        ]);

        // Generate PDF
        $this->pdfService->generateInvoice($payment->invoice);

        // Activate subscription
        $subscription = $payment->subscription;

        // Expire current active subscriptions
        Subscription::where('user_id', $subscription->user_id)
            ->where('id', '!=', $subscription->id)
            ->where('status', 'active')
            ->update(['status' => 'expired']);

        // Activate new subscription
        $subscription->update([
            'status' => 'active',
            'start_date' => now(),
            'end_date' => now()->addDays($subscription->plan->duration_days),
        ]);

        // Send invoice paid notification with PDF
        $payment->user->notify(new InvoicePaid($payment->invoice));

        // Notify admin about the payment
        $admins = User::where('role', 'admin')->get();
        foreach ($admins as $admin) {
            $admin->notify(new AdminPaymentReceived($payment->invoice, 'subscription'));
        }
    }
}
