<?php

namespace App\Http\Controllers;

use App\Http\Requests\CreateTopupRequest;
use App\Mail\PaymentInvoiceMail;
use App\Mail\PaymentSuccessMail;
use App\Models\CoinTransaction;
use App\Models\Setting;
use App\Models\User;
use App\Services\ActivityLogService;
use App\Services\PaymentGatewayService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Str;
use Inertia\Inertia;
use Inertia\Response;

class TopupCoinController extends Controller
{
    protected const COIN_RATE = 1000; // 1 coin = Rp 1.000

    public function __construct(
        protected PaymentGatewayService $paymentGatewayService,
        protected ActivityLogService $activityLogService
    ) {}

    /**
     * Display the topup coin page.
     */
    public function index(): Response
    {
        $user = Auth::user();

        // Get payment channels and find QRIS
        $channelsResult = $this->paymentGatewayService->getChannels();
        $channels = $channelsResult['success'] ? $channelsResult['data'] : [];

        // Find QRIS channel
        $qrisChannel = collect($channels)->firstWhere('nama', 'QRIS')
            ?? collect($channels)->firstWhere('nama', 'QRISC');

        // Check pending transactions count
        $pendingCount = CoinTransaction::where('user_id', $user->id)
            ->whereIn('status', ['pending', 'processing'])
            ->where(function ($query) {
                $query->whereNull('expires_at')
                    ->orWhere('expires_at', '>', now());
            })
            ->count();

        $isBlocked = $pendingCount >= 3;
        $topupEnabled = Setting::isEnabled('topup_enabled', true);

        return Inertia::render('TopupCoin', [
            'coin_balance' => $user->coin_balance ?? 0,
            'coin_name' => User::getCoinName(),
            'coin_abbreviation' => User::getCoinAbbreviation(),
            'coin_rate' => self::COIN_RATE,
            'qris_channel' => $qrisChannel,
            'pending_count' => $pendingCount,
            'is_blocked' => $isBlocked,
            'topup_enabled' => $topupEnabled,
        ]);
    }

    /**
     * Create payment transaction and redirect to payment gateway.
     */
    public function store(CreateTopupRequest $request)
    {
        $user = Auth::user();

        // Check if topup is enabled
        if (! Setting::isEnabled('topup_enabled', true)) {
            return redirect()->back()->with('error', 'Fitur topup coin sedang dinonaktifkan sementara. Silakan coba lagi nanti.');
        }

        $validated = $request->validated();
        $amount = $validated['amount'];

        // Check if user has 3 or more pending transactions
        $pendingCount = CoinTransaction::where('user_id', $user->id)
            ->whereIn('status', ['pending', 'processing'])
            ->where(function ($query) {
                $query->whereNull('expires_at')
                    ->orWhere('expires_at', '>', now());
            })
            ->count();

        if ($pendingCount >= 3) {
            return redirect()->back()->withErrors([
                'amount' => 'Anda memiliki 3 pembayaran yang belum diselesaikan. Silakan selesaikan atau tunggu hingga expired sebelum melakukan topup baru.',
            ]);
        }

        // Auto-set QRIS as payment channel
        $paymentChannel = 'QRIS';

        // Calculate coins: 1 coin = Rp 1.000
        $coins = (int) ($amount / self::COIN_RATE);

        if ($coins <= 0) {
            return redirect()->back()->withErrors([
                'amount' => 'Jumlah topup terlalu kecil. Minimum adalah Rp 1.000.',
            ]);
        }

        // Calculate fee (optional, can be fetched from payment gateway)
        $feeResult = $this->paymentGatewayService->calculateFee($paymentChannel, $amount);
        $fee = $feeResult['success'] && isset($feeResult['data']['fee'])
            ? (int) $feeResult['data']['fee']
            : 0;

        try {
            DB::beginTransaction();

            // Generate unique reference code
            $referenceCode = 'TOPUP-'.strtoupper(Str::random(12)).'-'.time();

            // Create transaction record
            $transaction = CoinTransaction::create([
                'user_id' => $user->id,
                'reference_code' => $referenceCode,
                'payment_channel' => $paymentChannel,
                'amount' => $amount,
                'coins' => $coins,
                'fee' => $fee,
                'status' => 'pending',
                'expires_at' => now()->addHours(24), // Expires in 24 hours
            ]);

            // Prepare payment data for gateway
            $paymentData = [
                'channel_payment' => $paymentChannel,
                'ref_kode' => $referenceCode,
                'nominal' => $amount,
                'cus_nama' => $user->name,
                'cus_email' => $user->email,
                'cus_phone' => $user->phone ?? '0000000000',
                'produk' => "Topup {$coins} ".User::getCoinAbbreviation(),
                'url_redirect' => route('topup-coin.status', ['reference' => $referenceCode]),
                'url_callback' => route('payment.callback'),
            ];

            // Create payment with gateway
            $paymentResult = $this->paymentGatewayService->createPayment($paymentData);

            if (! $paymentResult['success']) {
                DB::rollBack();
                Log::error('Payment Gateway: Failed to create payment', [
                    'user_id' => $user->id,
                    'amount' => $amount,
                    'error' => $paymentResult['error'] ?? 'Unknown error',
                ]);

                return redirect()->back()->withErrors([
                    'payment' => $paymentResult['error'] ?? 'Gagal membuat pembayaran. Silakan coba lagi.',
                ]);
            }

            // Update transaction with payment gateway response
            $paymentData = $paymentResult['data'] ?? [];

            // Parse expired_time if available
            $expiresAt = null;
            if (isset($paymentData['expired_time'])) {
                try {
                    $expiresAt = \Carbon\Carbon::parse($paymentData['expired_time']);
                } catch (\Exception $e) {
                    $expiresAt = now()->addHours(24);
                }
            } else {
                $expiresAt = now()->addHours(24);
            }

            $transaction->update([
                'payment_reference' => $paymentData['id_reference'] ?? $paymentData['ref_id'] ?? $paymentData['reference'] ?? null,
                'payment_url' => $paymentData['checkout_url'] ?? $paymentData['payment_url'] ?? $paymentData['url'] ?? null,
                'qr_code_url' => $paymentData['target'] ?? null,
                'fee' => isset($paymentData['fee']) ? (int) $paymentData['fee'] : $fee,
                'status' => 'processing',
                'expires_at' => $expiresAt,
            ]);

            DB::commit();

            // Log topup coin activity
            $this->activityLogService->logTopupCoin(
                $transaction->fresh(),
                "User {$user->name} created topup coin transaction for {$coins} coins (Rp {$amount})",
                [
                    'amount' => $amount,
                    'coins' => $coins,
                    'fee' => $fee,
                    'payment_channel' => $paymentChannel,
                    'reference_code' => $referenceCode,
                ]
            );

            // Send invoice email
            try {
                Mail::to($user->email)->send(new PaymentInvoiceMail($transaction->fresh()));
            } catch (\Exception $e) {
                Log::error('Failed to send payment invoice email', [
                    'transaction_id' => $transaction->id,
                    'user_id' => $user->id,
                    'error' => $e->getMessage(),
                ]);
                // Don't fail the request if email fails
            }

            // For QRIS, redirect to status page to show QR code
            // For other payment methods, redirect to checkout URL
            if ($paymentChannel === 'QRIS' && isset($paymentData['target'])) {
                return redirect()->route('topup-coin.status', ['reference' => $referenceCode])
                    ->with('success', 'Silakan scan QR code untuk menyelesaikan pembayaran.');
            }

            // Redirect to payment URL for other payment methods
            if (isset($paymentData['checkout_url']) || isset($paymentData['payment_url']) || isset($paymentData['url'])) {
                return redirect($paymentData['checkout_url'] ?? $paymentData['payment_url'] ?? $paymentData['url']);
            }

            // Fallback: redirect to status page
            return redirect()->route('topup-coin.status', ['reference' => $referenceCode])
                ->with('info', 'Pembayaran sedang diproses. Silakan tunggu konfirmasi.');
        } catch (\Exception $e) {
            DB::rollBack();
            Log::error('Topup Coin Error', [
                'user_id' => $user->id,
                'amount' => $amount,
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
            ]);

            return redirect()->back()->withErrors([
                'payment' => 'Terjadi kesalahan saat memproses pembayaran. Silakan coba lagi.',
            ]);
        }
    }

    /**
     * Check payment status.
     */
    public function status(Request $request, string $reference)
    {
        $user = Auth::user();
        $transaction = CoinTransaction::where('reference_code', $reference)
            ->where('user_id', $user->id)
            ->firstOrFail();

        // If transaction is still pending/processing, check with payment gateway
        if ($transaction->isPending() || $transaction->isProcessing()) {
            $statusResult = $this->paymentGatewayService->getTransactionStatus(
                $reference,
                $transaction->payment_reference
            );

            if ($statusResult['success'] && isset($statusResult['data']['status'])) {
                $paymentStatus = $this->mapPaymentStatus($statusResult['data']['status']);

                if ($paymentStatus === 'success' && ! $transaction->isSuccess()) {
                    DB::transaction(function () use ($transaction) {
                        $transaction->markAsSuccess();
                        $transaction->user->addCoins($transaction->coins);
                    });

                    // Log payment success activity
                    $transaction->refresh();
                    $this->activityLogService->logPaymentSuccess(
                        $transaction,
                        "Payment successful for transaction #{$transaction->id}, {$transaction->coins} coins added to user balance",
                        [
                            'amount' => $transaction->amount,
                            'coins' => $transaction->coins,
                            'fee' => $transaction->fee,
                            'payment_channel' => $transaction->payment_channel,
                            'reference_code' => $transaction->reference_code,
                        ]
                    );

                    // Send success email
                    try {
                        Mail::to($transaction->user->email)->send(new PaymentSuccessMail($transaction));
                    } catch (\Exception $e) {
                        Log::error('Failed to send payment success email', [
                            'transaction_id' => $transaction->id,
                            'user_id' => $transaction->user_id,
                            'error' => $e->getMessage(),
                        ]);
                        // Don't fail the request if email fails
                    }
                } elseif ($paymentStatus === 'failed' && ! $transaction->isFailed()) {
                    $transaction->markAsFailed();
                } else {
                    $transaction->update(['status' => $paymentStatus]);
                }
            }

            // Refresh transaction
            $transaction->refresh();
        }

        return Inertia::render('TopupCoinStatus', [
            'transaction' => [
                'id' => $transaction->id,
                'reference_code' => $transaction->reference_code,
                'payment_channel' => $transaction->payment_channel,
                'amount' => $transaction->amount,
                'coins' => $transaction->coins,
                'fee' => $transaction->fee,
                'status' => $transaction->status,
                'payment_url' => $transaction->payment_url,
                'qr_code_url' => $transaction->qr_code_url,
                'paid_at' => $transaction->paid_at?->toISOString(),
                'expires_at' => $transaction->expires_at?->toISOString(),
                'created_at' => $transaction->created_at->toISOString(),
            ],
            'coin_name' => User::getCoinName(),
            'coin_abbreviation' => User::getCoinAbbreviation(),
        ]);
    }

    /**
     * Map payment gateway status to our transaction status.
     */
    protected function mapPaymentStatus(?string $status): string
    {
        return match (strtolower($status ?? '')) {
            'paid', 'success', 'completed', 'settled' => 'success',
            'pending', 'processing', 'waiting' => 'processing',
            'failed', 'error', 'canceled', 'cancelled' => 'failed',
            'expired' => 'cancelled',
            default => 'pending',
        };
    }
}
