<?php

namespace App\Http\Controllers\Frontend\TopUp\Ipaymu;

use App\Http\Controllers\Frontend\TopUp\TopUpController;
use App\Http\Controllers\Frontend\TopUp\Traits\PaymentServiceTrait;
use App\Http\Controllers\Frontend\TopUp\Traits\RateLimitingTrait;
use App\Models\IpaymuSettings;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Inertia\Inertia;
use iPaymu\Exceptions\Unauthorized;
use iPaymu\iPaymu;

class IpaymuController extends TopUpController
{
    use PaymentServiceTrait, RateLimitingTrait;

    public function index()
    {
        $user = Auth::user();
        $settings = DB::table('ipaymu_settings')->first();

        // Check if game server is online
        $serverOnline = $this->api->serverOnline();

        // Check if service is active
        if (! $settings || ! $settings->is_active) {
            return redirect()->route('dashboard')->with('error', 'Ipaymu service is currently not available.');
        }

        $characters = $this->getUserCharactersWithFactionBonus();
        $goldRate = $settings->gold_rate ?? 1000;
        $packages = $this->generatePackages($goldRate);

        return Inertia::render('frontend/topup/ipaymu/index', [
            'characters' => $characters,
            'packages' => $packages,
            'settings' => [
                'gold_rate' => $settings->gold_rate,
                'min_amount' => $settings->min_amount,
                'max_amount' => $settings->max_amount,
                'is_active' => (bool) $settings->is_active,
            ],
            'userGold' => $user->gold ?? 0,
            'serverOnline' => $serverOnline,
        ]);
    }

    public function createPayment(Request $request)
    {
        $user = Auth::user();

        // Rate limiting using trait
        $rateLimit = $this->checkPaymentRateLimit($user->ID, 'ipaymu');
        if (! $rateLimit['allowed']) {
            return back()->with('error', $rateLimit['error']);
        }

        $request->validate([
            'character_id' => 'required|integer',
            'amount' => 'required|integer|min:1000',
            'promo_code' => 'nullable|string',
        ]);

        $settings = DB::table('ipaymu_settings')->first();

        // Validate payment request using trait
        $validation = $this->validatePaymentRequest($user, $settings, $request->amount);
        if (! $validation['valid']) {
            return back()->with('error', $validation['error']);
        }

        // Prepare payment data using trait
        $paymentData = $this->preparePaymentData($request, $user, $settings);
        if (! $paymentData['success']) {
            return back()->with('error', $paymentData['error']);
        }

        $goldAmount = $paymentData['goldAmount'];
        $promoResult = $paymentData['promoResult'];
        $autoPromoResult = $paymentData['autoPromoResult'];
        $streamerResult = $paymentData['streamerResult'];
        $factionData = $paymentData['factionData'];

        $referenceId = 'TOPUP-'.strtoupper(Str::random(12));

        // Log calculation using trait
        $this->logPaymentCalculation(
            $request->character_id,
            $factionData,
            $request->amount,
            $settings->gold_rate,
            $promoResult,
            $streamerResult,
            $goldAmount,
            $autoPromoResult
        );

        try {
            \Log::info('Creating iPaymu instance', [
                'va' => $settings->va_number,
                'api_key_length' => strlen($settings->api_key),
                'production_mode' => (bool) $settings->production_mode,
            ]);

            $iPaymu = new iPaymu($settings->api_key, $settings->va_number, (bool) $settings->production_mode);

            // Set callback URLs dynamically from current app URL
            $baseUrl = rtrim(config('app.url'), '/');
            $iPaymu->setURL([
                'ureturn' => $baseUrl.'/topup/ipaymu/return',
                'unotify' => $baseUrl.'/topup/ipaymu/notify',
                'ucancel' => $baseUrl.'/topup/ipaymu/cancel',
            ]);

            // Set buyer info
            $buyerData = [
                'name' => $user->name ?: 'Guest',
                'phone' => ! empty($user->mobilenumber) ? $user->mobilenumber : '08123456789',
                'email' => $user->email ?: 'guest@example.com',
            ];
            \Log::info('Buyer data', $buyerData);
            $iPaymu->setBuyer($buyerData);

            // Add cart item - use trait method for product name
            $productName = $this->buildProductName($goldAmount, $promoResult);

            $cart = [
                'product' => [$productName],
                'price' => [$promoResult['final_amount']],
                'quantity' => [1],
                'description' => ['Gold for character ID: '.$request->character_id],
                'weight' => [0],
                'length' => [0],
                'width' => [0],
                'height' => [0],
            ];
            $iPaymu->addCart($cart);

            // Create redirect payment
            \Log::info('Calling redirectPayment', [
                'original_amount' => $request->amount,
                'discount' => $promoResult['discount'],
                'final_amount' => $promoResult['final_amount'],
                'gold_amount' => $goldAmount,
                'promo_code' => $promoResult['promo']?->code,
            ]);
            $payment = $iPaymu->redirectPayment([
                'referenceId' => $referenceId,
            ]);
            \Log::info('Payment response', ['response' => $payment]);

            // Check for API error response
            if (isset($payment['Status']) && (int) $payment['Status'] !== 200) {
                $errorMsg = $payment['Message'] ?? 'Unknown API error';

                return back()->with('error', 'Payment API error: '.$errorMsg);
            }

            if (isset($payment['Data']['Url'])) {
                // Save transaction to database
                DB::table('ipaymu_transactions')->insert([
                    'user_id' => $user->ID,
                    'character_id' => $request->character_id,
                    'transaction_id' => $payment['Data']['TransactionId'] ?? null,
                    'reference_id' => $referenceId,
                    'amount' => $promoResult['final_amount'],
                    'gold_amount' => $goldAmount,
                    'streamer_code' => $streamerResult['streamer'] ? $streamerResult['streamer']->code : null,
                    'status' => 'pending',
                    'payment_url' => $payment['Data']['Url'],
                    'response_data' => json_encode($payment),
                    'expired_at' => now()->addHours(24),
                    'created_at' => now(),
                    'updated_at' => now(),
                ]);

                // Record promo usage using trait
                $this->recordPromoUsage($promoResult, $user->ID);
                $this->recordAutoPromoUsage($autoPromoResult, $user->ID);

                return Inertia::location($payment['Data']['Url']);
            }

            \Log::error('Ipaymu payment failed', ['response' => $payment]);

            return back()->with('error', 'Failed to create payment: '.json_encode($payment));
        } catch (Unauthorized $e) {
            \Log::error('Ipaymu unauthorized', ['error' => 'API credentials invalid or unauthorized']);

            return back()->with('error', 'Payment error: Invalid API credentials. Please contact support.');
        } catch (\Exception $e) {
            $errorResult = $this->handlePaymentException($e, 'Ipaymu');

            return back()->with('error', $errorResult['error']);
        }
    }

    public function handleReturn(Request $request)
    {
        $status = $request->input('status');
        $trxId = $request->input('trx_id');

        \Log::info('iPaymu return handler accessed', [
            'status' => $status,
            'trx_id' => $trxId,
            'full_query' => $request->all(),
        ]);

        if ($status === 'berhasil' || $status === 'success') {
            return redirect()->route('topup.history')->with('success', 'Payment successful! Your gold has been added.');
        }

        if ($status === 'gagal' || $status === 'failed') {
            return redirect()->route('topup.history')->with('error', 'Payment failed. Please try again.');
        }

        return redirect()->route('topup.history')->with('info', 'Payment processed. Please wait for confirmation.');
    }

    public function handleNotify(Request $request)
    {
        $trxId = $request->input('trx_id');
        $status = $request->input('status');
        $refId = $request->input('reference_id');
        $callbackSignature = $request->input('signature');
        $sid = $request->input('sid'); // Session ID from iPay

        \Log::info('Ipaymu callback received', $request->all());

        if (! $trxId || ! $status) {
            return response()->json(['status' => 'error', 'message' => 'Invalid callback'], 400);
        }

        // Verify callback signature
        $settings = IpaymuSettings::first();
        if (! $settings) {
            \Log::error('Ipaymu callback: Settings not found');

            return response()->json(['status' => 'error', 'message' => 'Settings not found'], 400);
        }

        // Verify HMAC-SHA256 signature per iPaymu API v2 spec
        if ($callbackSignature && ! $this->verifyCallbackSignature($request->all(), $settings)) {
            \Log::error('Ipaymu callback signature mismatch', [
                'received' => $callbackSignature,
                'trx_id' => $trxId,
                'reference_id' => $refId,
            ]);

            return response()->json(['status' => 'error', 'message' => 'Invalid signature'], 400);
        }

        $transaction = DB::table('ipaymu_transactions')
            ->where('reference_id', $refId)
            ->first();

        if (! $transaction) {
            return response()->json(['status' => 'error', 'message' => 'Transaction not found'], 404);
        }

        $newStatus = $this->normalizeCallbackStatus($status);
        $oldStatus = $transaction->status;

        // Update transaction
        DB::table('ipaymu_transactions')
            ->where('id', $transaction->id)
            ->update([
                'transaction_id' => $trxId,
                'status' => $newStatus,
                'response_data' => json_encode($request->all()),
                'updated_at' => now(),
                'paid_at' => $newStatus === 'success' ? now() : $transaction->paid_at,
            ]);

        // If payment successful, add gold to user using trait
        if ($newStatus === 'success' && $oldStatus !== 'success') {
            $user = $this->handlePaymentSuccess($transaction, $settings?->gold_rate);

            // Send broadcast notification if enabled
            if ($user && $settings && ($settings->broadcast_enabled ?? true)) {
                try {
                    $message = $settings->getBroadcastMessage($user, $transaction);
                    $channel = $settings->broadcast_channel ?? 9;
                    $this->api->WorldChat(0, $message, $channel);
                    \Log::info('iPaymu donation broadcast sent', [
                        'user' => $user->name,
                        'amount' => $transaction->amount,
                        'gold' => $transaction->gold_amount,
                        'channel' => $channel,
                    ]);
                } catch (\Exception $e) {
                    \Log::error('Failed to send iPaymu donation broadcast', [
                        'error' => $e->getMessage(),
                    ]);
                }
            }

            // Send Discord notification if enabled
            if ($user && $settings && ($settings->discord_enabled ?? false)) {
                try {
                    $settings->sendDiscordNotification($user, $transaction);
                } catch (\Exception $e) {
                    \Log::error('Failed to send iPaymu Discord notification', [
                        'error' => $e->getMessage(),
                    ]);
                }
            }
        }

        return response()->json(['status' => 'ok']);
    }

    /**
     * Verify iPaymu callback signature using HMAC-SHA256 per API v2 spec.
     */
    protected function verifyCallbackSignature(array $payload, object $settings): bool
    {
        $callbackSignature = $payload['signature'] ?? '';
        if (empty($callbackSignature)) {
            return false;
        }

        // iPaymu API v2 signature: HMAC-SHA256 of body hash
        $body = json_encode($payload, JSON_UNESCAPED_SLASHES);
        $bodyHash = strtolower(hash('sha256', $body));
        $stringToSign = 'POST:' . $settings->va_number . ':' . $bodyHash . ':' . $settings->api_key;
        $expectedSignature = hash_hmac('sha256', $stringToSign, $settings->api_key);

        if (hash_equals($expectedSignature, $callbackSignature)) {
            return true;
        }

        // Fallback: legacy simple SHA256 concatenation (some iPaymu implementations)
        $trxId = $payload['trx_id'] ?? '';
        $refId = $payload['reference_id'] ?? '';
        $legacySignature = hash('sha256', $settings->va_number . $trxId . $refId . $settings->api_key);

        return hash_equals($legacySignature, $callbackSignature);
    }

    /**
     * Normalize iPaymu callback status to internal status.
     */
    protected function normalizeCallbackStatus(string $status): string
    {
        $status = strtolower($status);

        return match ($status) {
            'berhasil', 'sukses', 'success', 'settled', 'paid' => 'success',
            'gagal', 'failed', 'fail', 'expired', 'cancelled', 'canceled' => 'failed',
            'pending', 'wait', 'waiting' => 'pending',
            default => $status,
        };
    }

    public function handleCancel(Request $request)
    {
        return redirect()->route('topup.history')->with('error', 'Payment was cancelled.');
    }
}
