<?php

namespace App\Http\Controllers\Admin;

use App\Models\User;
use App\Models\Balance;
use App\Models\Setting;
use App\Models\Discount;
use Illuminate\Support\Str;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use App\Models\VpsSubscription;
use Illuminate\Http\JsonResponse;
use App\Http\Controllers\Controller;
use App\Models\Invoice;
use App\Models\VpsDetail;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Http;

class TripayController extends Controller
{
    public $merchantUrl;
    public $merchantUrlCallback;
    public $merchantCode;
    public $merchantApiKey;
    public $merchantPrivateKey;

    public function __construct()
    {
        $this->merchantUrl = env('TRIPAY_MERCHANT_URL');
        $this->merchantUrlCallback = env('TRIPAY_MERCHANT_URL_CALLBACK');
        $this->merchantCode = env('TRIPAY_MERCHANT_CODE');
        $this->merchantApiKey = env('TRIPAY_MERCHANT_API_KEY');
        $this->merchantPrivateKey = env('TRIPAY_MERCHANT_PRIVATE_KEY');
    }

    public function signature($merchantRef, $amount)
    {
        return hash_hmac('sha256', $this->merchantCode . $merchantRef . $amount, $this->merchantPrivateKey);
    }

    public function paymentChannel(): JsonResponse
    {
        $url = $this->merchantUrl . '/merchant/payment-channel';
        try {
            // Make the HTTP request
            $response = Http::withHeaders([
                'Authorization' => 'Bearer ' . $this->merchantApiKey,
                'Content-Type' => 'application/json',
            ])
                ->timeout(10)
                ->withoutVerifying()
                ->get($url);
            $responseBody = (object) $response->json();
            return response()->json([
                'response' => $responseBody->data,
                'metadata' => [
                    'code' => 200,
                    'message' => 'OK',
                ],
            ], 200);
        } catch (\Exception $e) {
            return response()->json([
                'response' => null,
                'metadata' => [
                    'code' => 500,
                    'message' => 'Connection error: ' . $e->getMessage(),
                ],
            ], 500);
        }
    }

    public function create(Request $request): JsonResponse
    {
        $setting = Setting::find('1');
        $url = $this->merchantUrl . '/transaction/create';
        $merchantRef = 'INV-' . Carbon::now('Asia/Jakarta')->format('YmdHis');
        $method = $request->payment_channel;
        $amount = intval(str_replace([',', '.'], '', $request->amount));
        $discount_code = $request->discount_code;
        $expires_at = Carbon::now('Asia/Jakarta');
        $user = auth()->user();
        $balance = Balance::where('user_id', $user->id)
            ->where('is_closed_payment', 0)
            ->exists();
        if ($balance) {
            return response()->json([
                'response' => null,
                'metadata' => [
                    'code' => 400,
                    'message' => 'Failed, existing open payment',
                ],
            ], 400);
        }
        $discount_id = null;
        $discount_amount = 0;
        $amount_discount = $amount;
        if (!empty($discount_code)) {
            $discount = Discount::getDiscount($discount_code, $expires_at);
            if ($discount) {
                if ($discount->amount_min > $amount) {
                    return response()->json([
                        'response' => null,
                        'metadata' => [
                            'code' => 400,
                            'message' => 'Failed, minimum amount IDR ' . number_format($discount->amount_min, 0, ',', '.'),
                        ],
                    ], 400);
                }
                $discount_id = $discount->id;
                $discount_amount = $discount->amount ?? 0;
                $amount_discount = intval($discount_amount) < intval($amount) ?  intval(intval($amount) - intval($discount_amount)) : intval($amount);
            } else {
                return response()->json([
                    'response' => null,
                    'metadata' => [
                        'code' => 400,
                        'message' => 'Maaf, kode diskon yang Anda masukkan sudah tidak berlaku, tidak ditemukan, atau telah mencapai batas penggunaan.',
                    ],
                ], 400);
            }
        }
        $data = [
            'method'         => $method,
            'merchant_ref'   => $merchantRef,
            'amount'         => $amount_discount,
            'customer_name'  => $user->name,
            'customer_email' => $user->email,
            'customer_phone' => $user->phone,
            'order_items'    => [
                [
                    'sku'         => $merchantRef,
                    'name'        => 'TOPUP ' . $merchantRef,
                    'price'       => $amount_discount,
                    'quantity'    => 1,
                    'product_url' => '',
                    'image_url'   => '',
                ]
            ],
            'return_url'   => $this->merchantUrlCallback,
            'expired_time' => Carbon::now('Asia/Jakarta')->addMinutes($setting->payment_expired)->timestamp,
            'signature'    => $this->signature($merchantRef, $amount_discount),
        ];
        try {
            // Make the HTTP request
            $response = Http::withHeaders([
                'Authorization' => 'Bearer ' . $this->merchantApiKey,
                'Content-Type' => 'application/json',
            ])
                ->timeout(10)
                ->withoutVerifying()
                ->post($url, $data);
            $responseBody = (object) $response->json();
            if ($response->successful()) {
                $data = (object) $responseBody->data;
                $reference = $data->reference;
                $payment_method = $data->payment_method;
                $payment_name = $data->payment_name;
                $amount_topup = $amount;
                $total_amount = $data->amount;
                $fee_merchant = $data->fee_merchant;
                $fee_customer = $data->fee_customer;
                $total_fee = $data->total_fee;
                $amount_received = $data->amount_received;
                $pay_code = $data->pay_code;
                $pay_url = $data->pay_url;
                $checkout_url = $data->checkout_url;
                $status = $data->status;
                Balance::create(
                    [
                        'user_id' => $user->id,
                        'discount_id' => $discount_id,
                        'discount_amount' => $discount_amount,
                        'merchant_ref'   => $merchantRef,
                        'reference'   => $reference,
                        'amount_topup'   => $amount_topup,
                        'total_amount' => $total_amount,
                        'fee_merchant'   => $fee_merchant,
                        'fee_customer'   => $fee_customer,
                        'total_fee'   => $total_fee,
                        'amount_received'   => $amount_received,
                        'payment_method'   => $payment_method,
                        'payment_name'   => $payment_name,
                        'pay_code'   => $pay_code,
                        'pay_url'   => $pay_url,
                        'checkout_url'   => $checkout_url,
                        'status'   => $status,
                    ]
                );
                return response()->json([
                    'response' => $pay_url ?? $checkout_url,
                    'metadata' => [
                        'code' => 200,
                        'message' => 'OK',
                    ],
                ], 200);
            }
            return response()->json([
                'response' => null,
                'metadata' => [
                    'code' => 500,
                    'message' => 'Gagal topup, silahkan hubungi admin',
                ],
            ], 500);
        } catch (\Exception $e) {
            return response()->json([
                'response' => null,
                'metadata' => [
                    'code' => 500,
                    'message' => 'Connection error: ' . $e->getMessage(),
                ],
            ], 500);
        }
    }

    public function callback(Request $request): JsonResponse
    {
        $signature = $request->header('X-Callback-Signature');
        $payload = $request->getContent();
        $computedSign = hash_hmac('sha256', $payload, $this->merchantPrivateKey);
        if (!hash_equals($computedSign, $signature)) {
            return response()->json([
                'response' => null,
                'metadata' => [
                    'code' => 403,
                    'message' => 'invalid signature',
                ],
            ], 403);
        }
        $event = $request->header('X-Callback-Event');
        if ($event !== 'payment_status') {
            return response()->json([
                'response' => null,
                'metadata' => [
                    'code'    => 403,
                    'message' => 'Unrecognized callback event',
                ],
            ], 403);
        }
        $reference = $request->reference;
        $merchant_ref = $request->merchant_ref;
        $payment_method = $request->payment_method_code;
        $payment_name = $request->payment_method;
        $total_amount = $request->total_amount;
        $fee_merchant = $request->fee_merchant;
        $fee_customer = $request->fee_customer;
        $total_fee = $request->total_fee;
        $amount_received = $request->amount_received;
        $is_closed_payment = $request->is_closed_payment;
        $status = $request->status;
        $paid_at = $request->paid_at;
        $note = $request->note;
        if ((int)$is_closed_payment === 1) {
            $balance = Balance::where('reference', $reference)
                ->where('merchant_ref', $merchant_ref)
                ->where('status', 'UNPAID')
                ->first();
            if (!$balance) {
                return response()->json([
                    'response' => null,
                    'metadata' => [
                        'code'    => 404,
                        'message' => 'Top-up record not found or already processed',
                    ],
                ], 404);
            }
            $user_id = $balance->user_id;
            $amount_topup = $balance->amount_topup;
            $balance->payment_method = $payment_method;
            $balance->payment_name = $payment_name;
            $balance->total_amount = $total_amount;
            $balance->fee_merchant = $fee_merchant;
            $balance->fee_customer = $fee_customer;
            $balance->total_fee = $total_fee;
            $balance->amount_received = $amount_received;
            $balance->is_closed_payment = $is_closed_payment;
            $balance->status = $status;
            $balance->paid_at = $paid_at;
            $balance->note = $note;
            $balance->save();
            if (Str::upper($status) === 'PAID') {
                $user = User::find($user_id);
                if ($user) {
                    if ($user->amount != str_replace(',', '', $amount_topup)) {
                        $new_balance = $user->amount + str_replace(',', '', $amount_topup);
                        Invoice::create([
                            'user_id' => $request->id,
                            'uuid' => (string) Str::uuid(),
                            'price' => str_replace(',', '', $amount_topup),
                            'initial_balance' => str_replace(',', '', $user->amount),
                            'new_balance' => str_replace(',', '', $new_balance),
                        ]);
                    }
                    $user->increment('amount', $amount_topup);
                    $vps_subscription = VpsSubscription::where('user_id', $user->id)
                        ->where('suspend', 1)
                        ->get();
                    foreach ($vps_subscription as $item) {
                        $vps_detail = VpsDetail::find($item->vps_details_id);
                        if (!$vps_detail) {
                            continue;
                        }
                        $requestMarzban = new Request([
                            'id' => $vps_detail->vps_id,
                            'username' => $item->username,
                            'status' => 'active',
                        ]);
                        $marzbanController = new MarzbanController();
                        $marzbanController->usersStatus($requestMarzban);
                        $item->suspend = 0;
                        $item->pay_at = Carbon::now('Asia/Jakarta');
                        $item->save();
                    }
                }
            }
            return response()->json([
                'response' => null,
                'metadata' => [
                    'code' => 200,
                    'message' => 'OK',
                ],
            ], 200);
        }
        return response()->json([
            'response' => null,
            'metadata' => [
                'code' => 403,
                'message' => 'unrecognized payment status',
            ],
        ], 403);
    }
}
