<?php

namespace App\Http\Controllers\Payments;

use App\Http\Controllers\Controller;
use App\Models\Transaction;
use App\Services\TicketPurchaseService;
use App\Services\TilopayClient;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Illuminate\Validation\Rule;
use InvalidArgumentException;
use Throwable;

class TilopayPaymentController extends Controller
{
    public function __construct(
        private readonly TilopayClient $tilopay,
        private readonly TicketPurchaseService $purchases,
    ) {}

    public function checkout(Request $request): JsonResponse
    {
        $data = $request->validate([
            'transaction_id' => ['required', 'integer', Rule::exists('transactions', 'id')],
            'billing' => ['nullable', 'array'],
        ]);

        $user = $request->user();

        if (! $user) {
            return response()->json(['message' => 'No autenticado.'], 401);
        }

        try {
            $transaction = $this->purchases->prepareForTilopay(
                Transaction::findOrFail($data['transaction_id']),
                $user,
            );
        } catch (InvalidArgumentException $e) {
            return response()->json(['message' => $e->getMessage()], 422);
        }

        try {
            $payment = $this->tilopay->createPayment($transaction, $user, $data['billing'] ?? []);
        } catch (Throwable $e) {
            Log::error('Tilopay checkout failed', [
                'transaction_id' => $transaction->id,
                'error' => $e->getMessage(),
            ]);

            return response()->json(['message' => 'No se pudo iniciar el pago con Tilopay.'], 502);
        }

        return response()->json([
            'transaction_id' => $transaction->id,
            'order_number' => $transaction->provider_order_number,
            'amount' => $transaction->amount,
            'payment_url' => $payment['url'],
        ], 201);
    }

    public function walletRecharge(Request $request): JsonResponse
    {
        $data = $request->validate([
            'amount' => ['required', 'numeric', 'min:500'],
            'billing' => ['nullable', 'array'],
        ]);

        $user = $request->user();

        if (! $user) {
            return response()->json(['message' => 'No autenticado.'], 401);
        }

        $transaction = Transaction::create([
            'user_id' => $user->id,
            'amount' => $data['amount'],
            'type' => 'deposit',
            'payment_method' => 'card',
            'provider' => 'tilopay',
            'provider_order_number' => $this->orderNumber('WALLET'),
            'status' => 'pending',
        ]);

        try {
            $payment = $this->tilopay->createPayment($transaction, $user, $data['billing'] ?? []);
        } catch (Throwable $e) {
            Log::error('Tilopay wallet recharge failed', [
                'transaction_id' => $transaction->id,
                'error' => $e->getMessage(),
            ]);

            $transaction->update([
                'status' => 'rejected',
                'provider_payload' => ['reason' => 'gateway_error'],
                'rejected_at' => now(),
            ]);

            return response()->json(['message' => 'No se pudo iniciar la recarga con Tilopay.'], 502);
        }

        return response()->json([
            'transaction_id' => $transaction->id,
            'order_number' => $transaction->provider_order_number,
            'amount' => $transaction->amount,
            'payment_url' => $payment['url'],
        ], 201);
    }

    public function callback(Request $request)
    {
        $payload = $request->all();
        $orderNumber = $request->query('order');

        $transaction = Transaction::where('provider_order_number', $orderNumber)
            ->where('provider', 'tilopay')
            ->first();

        if (! $transaction) {
            Log::warning('Tilopay callback for unknown order', ['order' => $orderNumber]);

            return $this->respond($request, false, 'Orden no encontrada.', null);
        }

        if (! $this->returnDataIsValid($request, $transaction)) {
            Log::warning('Tilopay callback with invalid returnData', ['order' => $orderNumber]);

            return $this->respond($request, false, 'Datos de retorno inválidos.', $transaction);
        }

        $approved = (string) $request->query('code') === '1';

        try {
            $transaction = $approved
                ? $this->purchases->approve($transaction, $payload)
                : $this->purchases->reject($transaction, $payload);
        } catch (Throwable $e) {
            Log::error('Tilopay callback processing failed', [
                'order' => $orderNumber,
                'error' => $e->getMessage(),
            ]);

            return $this->respond($request, false, 'No se pudo procesar la confirmación.', $transaction);
        }

        return $this->respond(
            $request,
            $approved,
            $approved ? 'Pago aprobado.' : 'Pago rechazado.',
            $transaction,
        );
    }

    private function respond(Request $request, bool $approved, string $message, ?Transaction $transaction)
    {
        if ($request->expectsJson()) {
            return response()->json([
                'approved' => $approved,
                'message' => $message,
                'transaction_id' => $transaction?->id,
                'status' => $transaction?->status,
            ], $approved ? 200 : 422);
        }

        $returnUrl = config('services.tilopay.return_url');

        if ($returnUrl) {
            $separator = str_contains($returnUrl, '?') ? '&' : '?';

            return redirect()->away($returnUrl.$separator.http_build_query([
                'approved' => $approved ? 1 : 0,
                'order' => $transaction?->provider_order_number,
                'status' => $transaction?->status,
            ]));
        }

        return response()->json([
            'approved' => $approved,
            'message' => $message,
            'status' => $transaction?->status,
        ], $approved ? 200 : 422);
    }

    private function returnDataIsValid(Request $request, Transaction $transaction): bool
    {
        $returnData = $request->query('returnData');

        if (! $returnData) {
            return ! config('services.tilopay.require_return_data', true);
        }

        $decoded = json_decode((string) base64_decode((string) $returnData, true), true);

        if (! is_array($decoded)) {
            return false;
        }

        return (int) ($decoded['transaction_id'] ?? 0) === $transaction->id
            && (int) ($decoded['user_id'] ?? 0) === $transaction->user_id
            && (string) ($decoded['order_number'] ?? '') === (string) $transaction->provider_order_number;
    }

    private function orderNumber(string $prefix = 'WINCAR'): string
    {
        return $prefix.'-'.now()->format('YmdHis').'-'.Str::upper(Str::random(8));
    }

    /**
     * Simulador Sandbox de Pago Seguro de Tilopay
     */
    public function mockCheckout(Request $request)
    {
        $amount = $request->query('amount');
        $order = $request->query('order');
        $returnData = $request->query('returnData');

        $html = <<<HTML
<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Wincar - Simulador de Pago Seguro (TiloPay)</title>
    <style>
        body {
            background-color: #121212;
            color: #ffffff;
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            margin: 0;
        }
        .card {
            background-color: #1e1e1e;
            border-radius: 20px;
            padding: 30px;
            width: 90%;
            max-width: 400px;
            box-shadow: 0 8px 24px rgba(0,0,0,0.5);
            text-align: center;
            border: 1px solid #2e2e2e;
        }
        h2 {
            color: #FFA738;
            margin-top: 0;
            font-size: 24px;
        }
        .info {
            background-color: #2a2a2a;
            padding: 15px;
            border-radius: 12px;
            margin: 20px 0;
            text-align: left;
            font-size: 14px;
        }
        .info div {
            margin-bottom: 8px;
        }
        .info div:last-child {
            margin-bottom: 0;
        }
        .btn {
            display: block;
            width: 100%;
            padding: 14px;
            border: none;
            border-radius: 25px;
            font-size: 16px;
            font-weight: bold;
            cursor: pointer;
            margin-bottom: 12px;
            transition: opacity 0.2s;
            text-decoration: none;
            box-sizing: border-box;
        }
        .btn:hover {
            opacity: 0.9;
        }
        .btn-success {
            background-image: linear-gradient(135deg, #FFA738, #FE6B3E);
            color: #000000;
        }
        .btn-danger {
            background-color: #e53935;
            color: #ffffff;
        }
        .footer {
            font-size: 11px;
            color: #888888;
            margin-top: 20px;
        }
    </style>
</head>
<body>
    <div class="card">
        <h2>TiloPay Sandbox 💳</h2>
        <p style="font-size: 14px; color: #aaaaaa;">Estás en el modo de simulación de pagos de Wincar.</p>
        
        <div class="info">
            <div><strong>Orden:</strong> {$order}</div>
            <div><strong>Monto:</strong> ₡{$amount}</div>
        </div>

        <a href="/api/payments/tilopay/callback?code=1&order={$order}&returnData={$returnData}" class="btn btn-success">APROBAR PAGO</a>
        <a href="/api/payments/tilopay/callback?code=2&order={$order}&returnData={$returnData}" class="btn btn-danger">RECHAZAR PAGO</a>
        
        <div class="footer">
            Wincar Sorteos CR &copy; 2026 - Transacción Segura
        </div>
    </div>
</body>
</html>
HTML;

        return response($html);
    }
}
