<?php

namespace App\Http\Controllers;

use Helper;
use Module;
use App\Models\Package;
use App\Models\Transaction;
use App\Models\User;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Http;

class TransactionController extends Controller
{
  public function list()
  {
    if (!Helper::isEx()) {
      return redirect()->back();
    }
    if (empty(Helper::setting('currencyCode'))) {
      $currencyCode = 'USD';
    } else {
      $currencyCode = Helper::setting('currencyCode');
    }
    $user = auth()->user();
    $walletBalance = $user->transactions()->sum('amount');
    $transactions = $user
      ->transactions()
      ->orderBy('id', 'desc')
      ->paginate(50);
    return view('/user-transaction', compact('walletBalance', 'transactions', 'currencyCode'));
  }

  public static function store($code, $from_id, $to_id, $type, $amount, $data, $memo = null)
  {
    // $from_id transaction (minus)
    $transaction = new Transaction();
    $transaction->code = $code;
    $transaction->user_id = $from_id;
    $transaction->user2_id = $to_id;
    $transaction->type = $type;
    $transaction->amount = $amount * -1;
    $transaction->memo = $memo;
    $transaction->data = $data;
    $transaction->save();

    // $to_id transaction (plus)
    $transaction = new Transaction();
    $transaction->code = $code;
    $transaction->user_id = $to_id;
    $transaction->user2_id = $from_id;
    $transaction->type = $type;
    $transaction->amount = $amount;
    $transaction->memo = $memo;
    $transaction->data = $data;
    $transaction->save();

    File::ensureDirectoryExists(public_path("users/{$from_id}/transactions"), 0755, true);
    file_put_contents(public_path("users/{$from_id}/transactions/{$type}_{$code}.json"), $data);
    File::ensureDirectoryExists(public_path("users/{$to_id}/transactions"), 0755, true);
    file_put_contents(public_path("users/{$to_id}/transactions/{$type}_{$code}.json"), $data);
  }

  public static function autoRenew()
  {
    echo 'OK';
    self::renew();
    echo 'SUCCESS';
  }

  // public function autoRenew(Request $request)
  // {
  //   echo 'OK';
  //   if ($request->input('awg_orderId') !== Helper::setting('awg_orderId')) {
  //     return;
  //   }
  //   self::renew();
  //   echo 'SUCCESS';
  // }

  public static function renew()
  {
    if (!Helper::isEx()) {
      return;
    }
    $users = User::all();
    foreach ($users as $user) {
      self::renewPerUser($user->id);
    }
  }

  public static function renewPerUser($user_id)
  {
    if (!Helper::isEx()) {
      return;
    }
    $user = User::where('id', '=', $user_id)->first();
    $expired = $user->role !== 'admin' && $user->billing_end < Carbon::now() ? true : false;
    if ($expired === true && $user->package->rate_monthly > 0) {
      $daysTotal =
        Carbon::now()
          ->startOfMonth()
          ->diffInseconds(Carbon::now()->endOfMonth(), false) / 86400;
      $daysRemaining = Carbon::now()->diffInseconds(Carbon::now()->endOfMonth(), false) / 86400;
      $prorated = ($daysRemaining / $daysTotal) * $user->package->rate_monthly;
      $walletBalance = $user->transactions()->sum('amount');
      if ($prorated > $walletBalance) {
        return;
      }
      $admin_id = 1;
      $transactionCode = Carbon::now()->timestamp . rand(100, 999);
      $transactionData = [
        'transactionCode' => $transactionCode,
        'description' => 'renew ' . $user->package->name . ' @ ' . $prorated,
      ];
      self::store($transactionCode, $user->id, $admin_id, 'renew', $prorated, json_encode($transactionData));

      // user table update
      $user->billing_start = Carbon::now()->startOfMonth();
      $user->billing_end = Carbon::now()->endOfMonth();
      $user->save();
    }
  }

  public function topup(Request $request)
  {
    if (!Helper::isEx()) {
      return;
    }
    if ($request->input('gateway') === 'OfflinePayment') {
      $_MsgOfflinePayment = str_ireplace(
        ['{name}', '{currencyCode}', '{topupValue}', '{gateway}'],
        [
          $request->input('user_name'),
          $request->input('currencyCode'),
          number_format($request->input('topupValue'), Helper::setting('nfDecimals'), Helper::setting('nfDecimalpoint'), Helper::setting('nfSeparator')),
          $request->input('gateway'),
        ],
        __('_MsgOfflinePayment')
      );
      return redirect()
        ->route('user.show', ['user_id' => $request->input('user_id')])
        ->with(['success_alert' => $_MsgOfflinePayment]);
    } else {
      $modules = Module::getByStatus(1);
      foreach ($modules as $module) {
        if ($module->getName() === $request->input('gateway')) {
          return redirect()->route($module->getName(), [
            'gateway' => $request->input('gateway'),
            'user_id' => $request->input('user_id'),
            'user_name' => $request->input('user_name'),
            'currencyCode' => $request->input('currencyCode'),
            'topupValue' => $request->input('topupValue'),
            'userGopayId' => $request->input('userGopayId'),
          ]);
        }
      }
      // if(Module::isEnabled('PayGate')) {
      //   // $upId = $request->input('upId');
      //   $user_id = $request->input('user_id');
      //   $package_id = $request->input('package_id');
      //   $gateway = $request->input('gateway');
      //   return redirect()->route("paygate.$gateway", compact('user_id', 'package_id', 'gateway'));
      // }
    }
  }

  public function topupSuccess(Request $request)
  {
    if (!Helper::isEx()) {
      return;
    }
    // $verified = $this->verifyPayment($request->gateway, $request->pg_tr_id);
    // if (empty($verified)) return response()->json(['success' => false, 'message' => 'Payment cannot be verified!']);
    $bank_id = 2;
    self::store($request->pg_tr_id, $bank_id, $request->user_id, 'topup', $request->topupValue, $request->pg_response);
    self::renewPerUser($request->user_id);
  }

  public function mpSuccess(Request $request)
  {
    if (!Helper::isEx()) {
      return;
    }
    // $verified = $this->verifyPayment('Mercadopago', $request->payment_id);
    // if (empty($verified)) return response()->json(['success' => false, 'message' => 'Payment cannot be verified!']);
    $pg_response = [
      'payment_gateway' => 'Mercadopago',
      'mercadopago_payment_id' => $request->payment_id,
      'mercadopago_payment_status' => $request->status,
      'mercadopago_external_reference' => $request->external_reference,
      'mercadopago_merchant_order_id' => $request->merchant_order_id,
    ];
    $ext_ref = json_decode($request->external_reference, true);
    $bank_id = 2;
    self::store($request->payment_id, $bank_id, $ext_ref['user_id'], 'topup', $ext_ref['topup_value'], json_encode($pg_response));
    self::renewPerUser($ext_ref['user_id']);
    return redirect()
      ->route('transaction.list', $ext_ref['user_id'])
      ->with(['success_alert' => __('Top up successful!')]);
  }

  public function stripeSuccess(Request $request)
  {
    if (!Helper::isEx()) {
      return;
    }
    // $verified = $this->verifyPayment('stripe', $request->pg_tr_id);
    // if (empty($verified)) return response()->json(['success' => false, 'message' => 'Payment cannot be verified!']);
    $pg_response = [
      'payment_gateway' => 'Stripe',
      'stripe_session_id' => $request->pg_tr_id,
      'stripe_payment_amount' => $request->topupValue,
    ];
    $bank_id = 2;
    self::store($request->pg_tr_id, $bank_id, $request->user_id, 'topup', $request->topupValue, json_encode($pg_response));
    self::renewPerUser($request->user_id);
    return redirect()
      ->route('transaction.list', $request->user_id)
      ->with(['success_alert' => __('Top up successful!')]);
  }

  public static function gopaySuccess($data)
  {
    if (!Helper::isEx()) {
      return;
    }
    $bank_id = 2;
    self::store($data['pg_tr_id'], $bank_id, $data['user_id'], 'topup', $data['topupValue'], $data['pg_response']);
    self::renewPerUser($data['user_id']);
  }

  public function upgrade(Request $request)
  {
    if (!Helper::isEx()) {
      return redirect()->back();
    }
    $admin_id = 1;
    $user = auth()->user();
    $daysTotal =
      Carbon::now()
        ->startOfMonth()
        ->diffInseconds(Carbon::now()->endOfMonth(), false) / 86400;
    $daysRemaining = Carbon::now()->diffInseconds(Carbon::now()->endOfMonth(), false) / 86400;
    $billing_interval = $request->input('billing_interval');
    $package = Package::where('id', '=', $request->input('package_id'))->first();
    if ($user->package->name === 'trial' || $user->package->id === 2) {
      $prorated = $user->package->rate_monthly > $package->rate_monthly ? 0 : ($daysRemaining / $daysTotal) * $package->rate_monthly;
    } else {
      $prorated = $user->package->rate_monthly > $package->rate_monthly ? 0 : $package->rate_monthly - $user->package->rate_monthly;
    }
    if ($prorated > $request->input('walletBalance')) {
      return redirect()
        ->route('user.show', ['user_id' => $user->id])
        ->with(['danger_alert' => __('Your wallet balance is not enough. Please top up first!')]);
    }

    $transactionCode = Carbon::now()->timestamp . rand(100, 999);
    $transactionData = [
      'transactionCode' => $transactionCode,
      'description' => 'from ' . $user->package->name . ' to ' . $package->name,
    ];
    self::store($transactionCode, $user->id, $admin_id, 'upgrade', $prorated, json_encode($transactionData));

    // user table update
    $user->package_id = $package->id;
    $user->billing_interval = $billing_interval;
    $user->billing_start = Carbon::now()->startOfMonth();
    $user->billing_end = Carbon::now()->endOfMonth();
    $user->save();

    return redirect()
      ->route('transaction.list', $user->id)
      ->with(['success_alert' => __('Upgrade successful!')]);
  }

  public function transfer(Request $request)
  {
    if (!Helper::isEx()) {
      return redirect()->back();
    }
    $from = User::where('name', '=', $request->input('from_name'))->first();
    $to = User::where('name', '=', $request->input('to_name'))->first();
    if (empty($to->id)) {
      return redirect()->back()->with(['danger_alert' => __('Cannot find Username') . ': ' . $request->input('to_name')]);
    }
    if (filter_var(Helper::setting('waVerification'), FILTER_VALIDATE_BOOLEAN) && $from->role !== 'admin' && $from->otp !== $request->input('otp') && $request->input('adminSender')) {
      return redirect()
        ->back()
        ->with(['danger_alert' => __('OTP code is invalid.')]);
    }
    $from->otp = null;
    $from->save();
    $fromBalance = $from->transactions()->sum('amount');
    if ($from->role !== 'admin' && $request->input('amount') > $fromBalance) {
      return redirect()
        ->back()
        ->with(['danger_alert' => __('Balance is not enough.')]);
    }
    $transactionCode = Carbon::now()->timestamp . rand(100, 999);
    $transactionData = [
      'transactionCode' => $transactionCode,
      'description' => 'from ' . $request->input('from_name') . ' to ' . $request->input('to_name'),
    ];
    self::store($transactionCode, $from->id, $to->id, 'transfer', $request->input('amount'), json_encode($transactionData), $request->input('memo'));
    self::renewPerUser($to->id);
    return redirect()
      ->route('transaction.list', $from->id)
      ->with(['success_alert' => __('Transfer successful!')]);
  }

  public function paymentResponse(Request $request)
  {
    $filename = public_path("users/1/payment/" . date('Y-m-d-H-i-s') . ".json");
    $data = json_encode($request->all(), JSON_PRETTY_PRINT);
    file_put_contents($filename, $data);
    return response('Data received successfully.', 200)->header('Content-Type', 'text/plain');
  }

  private function verifyPayment($gateway, $transactionId) {
    if (strtolower($gateway) === 'mercadopago') {
      $mpAccessToken = Helper::setting('mpAccessToken');
      require_once Module::getModulePath('Mercadopago') . 'vendor/autoload.php';
      \MercadoPago\MercadoPagoConfig::setAccessToken($mpAccessToken);
      \MercadoPago\MercadoPagoConfig::setRuntimeEnviroment(\MercadoPago\MercadoPagoConfig::LOCAL);
      $client = new \MercadoPago\Client\Payment\PaymentClient();
      $response = $client->get($transactionId);
      // file_put_contents(public_path('response.json'), json_encode($response));
      if (empty($response->status)) return false;
      if (strtolower($response->status) === 'approved') return true;
    } else if (strtolower($gateway) === 'midtrans') {
      $midtransServerKey = Helper::setting('midtransServerKey');
      require_once Module::getModulePath('Midtrans') . 'vendor/autoload.php';
      \Midtrans\Config::$serverKey = $midtransServerKey;
      \Midtrans\Config::$isProduction = str_starts_with($midtransServerKey, 'SB-') ? false : true;
      $response = \Midtrans\Transaction::status($transactionId);
      // file_put_contents(public_path('response.json'), json_encode($response));
      if (str_starts_with(strtolower($response?->status_message), 'success')) return true;
      else return false;
    } else if (strtolower($gateway) === 'paypal') {
      $paypalSandbox = config('app.PAYPAL_SANDBOX') ?? false;
      $paypalClientId = Helper::setting('paypalClientId');
      $paypalSecretKey = Helper::setting('paypalSecretKey');
      $response = Http::withoutVerifying()
      ->withOptions(["verify"=>false])
      ->withBasicAuth($paypalClientId, $paypalSecretKey)
      ->asForm()
      ->post($paypalSandbox ? 'https://api-m.sandbox.paypal.com/v1/oauth2/token' : 'https://api-m.paypal.com/v1/oauth2/token', ['grant_type' => 'client_credentials']);
      $accessToken = json_decode($response)?->access_token;
      if (empty($accessToken)) return false;
      $response = Http::withoutVerifying()
      ->withOptions(["verify"=>false])
      ->withToken($accessToken)
      ->get($paypalSandbox ? "https://api-m.sandbox.paypal.com/v1/payments/sale/{$transactionId}" : "https://api-m.paypal.com/v1/payments/sale/{$transactionId}");
      // file_put_contents(public_path('response.json'), $response);
      $res = json_decode($response, true);
      if (empty($res['state'])) return false;
      if (strtolower($res['state']) === 'completed') return true;
    } else if (strtolower($gateway) === 'pix') {
      return true;
    } else if (strtolower($gateway) === 'razorpay') {
      $razorpayKeyId = Helper::setting('razorpayKeyId');
      $razorpayKeySecret = Helper::setting('razorpayKeySecret');
      require_once Module::getModulePath('Razorpay') . 'vendor/autoload.php';
      $api = new \Razorpay\Api\Api($razorpayKeyId, $razorpayKeySecret);
      $response = $api->payment->fetch($transactionId);
      // file_put_contents(public_path('response.json'), json_encode($response));
      if (empty($response->status)) return false;
      if (strtolower($response->status) == 'captured') return true;
    } else if (strtolower($gateway) === 'stripe') {
      $stripeSecret = Helper::setting('stripeSecret');
      require_once Module::getModulePath('Stripe') . 'vendor/autoload.php';
      $stripe = new \Stripe\StripeClient($stripeSecret);
      $response = $stripe->checkout->sessions->retrieve($transactionId);
      // file_put_contents(public_path('response.json'), json_encode($response));
      if (empty($response->payment_status)) return false;
      if (strtolower($response->status) == 'paid') return true;
    }
    return false;
  }
}
