<?php

namespace App\Http\Controllers\User\Financial;

use App\Helpers\DropdownListHelper;
use App\Http\Controllers\Controller;
use App\Http\Requests\User\AddBankCardRequest;
use App\Http\Requests\User\ChargeWalletRequest;
use App\Http\Requests\User\WithdrawalWalletRequest;
use App\Models\BankCard;
use App\Models\Setting;
use App\Models\Transaction;
use App\Models\Withdrawal;
use App\Notifications\WalletCharge;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Shetabit\Payment\Facade\Payment;
use Inertia\Inertia;
use Shetabit\Multipay\Exceptions\InvalidPaymentException;
use Shetabit\Multipay\Exceptions\PurchaseFailedException;
use Shetabit\Multipay\Invoice;

class WalletController extends Controller
{
    use DropdownListHelper;

    /**
     * wallet page
     */
    public function index()
    {
        /** @var \App\Models\User $user */
        $user = auth()->user();

        // لیست آیتم‌هایی که می‌خوایم حذف کنیم
        $excludeIds = ['digipay', 'snapppay', 'azki'];

        // گرفتن payment gateways
        $paymentGateways = Setting::where('key', 'payment_gateway')->first() != null
            ? unserialize(Setting::where('key', 'payment_gateway')->first()->value)
            : [];

        // map و filter
        $paymentGateways = array_filter(array_map(function ($pg) {
            return [
                'id' => $pg['id'],
                'label' => $pg['label'],
                'status' => $pg['status'],
            ];
        }, $paymentGateways), function ($pg) use ($excludeIds) {
            // فقط آیتم‌هایی که فعال هستند و جزو لیست حذف نباشند
            return $pg['status'] && !in_array($pg['id'], $excludeIds);
        });

        // user withdrawals
        $withdrawals = $user->withdrawals()->orderByRaw("FIELD(status , 'awaiting', 'deposited', 'deleted') ASC")->orderByDesc('created_at')->paginate(10);

        // get user bank card
        $BankCard = $user->bankCards()->where('status', 'active')->get();

        return Inertia::render('User/Financial/Wallet/Show', [
            'walletRelatedAmounts' => $this->walletRelatedAmounts(),
            'paymentGateways' => array_values($paymentGateways),
            'withdrawals' => $withdrawals,
            'bankCard' => $BankCard,
        ]);
    }

    /**
     * payment charge wallet
     */
    public function charge(ChargeWalletRequest $request)
    {
        /** @var \App\Models\User $user */
        $user = auth()->user();

        // payment gateways
        $paymentGateways = Setting::where('key', 'payment_gateway')->first() != null ? unserialize(Setting::where('key', 'payment_gateway')->first()->value) : [];

        // validate existing payment gateways
        if (count($paymentGateways) == 0) {
            return redirect()->back()->withErrors([__('messages.no_any_payment_gateways')]);
        }

        // validate selected payment gateway
        $paymentGatewaysIDStatus = [];
        foreach ($paymentGateways as $pg) {
            $paymentGatewaysIDStatus[$pg['id']] = $pg['status'];
        }
        if (!$request->exists('payment_gateway') || $request->payment_gateway == null || $request->payment_gateway == '')
            return redirect()->back()->withErrors([__('messages.no_any_selected_payment_gateway')]);
        if (!array_key_exists($request->payment_gateway, $paymentGatewaysIDStatus) || !$paymentGatewaysIDStatus[$request->payment_gateway])
            return redirect()->back()->withErrors([__('messages.selected_payment_gateway_not_active')]);

        // set payment gateway driver configs
        foreach ($paymentGateways as $pg) {
            foreach ($pg['fields'] as $key => $field) {
                Config::set('payment.drivers.' . $pg['id'] . '.' . $key, $field['value']);
            }
        }

        // user amount for charge
        $amount = (int)str_replace(',', '', $request->amount);

        // check amount limit
        $limitAmount = Setting::where('key', 'wallet_charge_limit')->first() != null ? (int)str_replace(',', '', Setting::where('key', 'wallet_charge_limit')->first()->value) : null;
        if ($limitAmount != null && $amount > $limitAmount) {
            return redirect()->back()->withErrors([__('messages.wallet_charge_limit_', ['amount' => number_format($limitAmount)])]);
        }

        // create invoice and send to payment gateway
        $invoice = new Invoice;
        $invoice->amount($amount);

        // add transaction
        $transaction = $user->transactions()->create([
            'amount' => $amount,
            'transaction_id' => rand(100000000, 999999999),
            'payment_gateway' => $request->payment_gateway,
            'payment_details' => serialize([
                'type' => 'wallet_charge'
            ]),
            'description' => __('messages.transaction_user_charge'),
            'type' => 'user_charge',
            'status' => 'waiting_payment'
        ]);

        // handle toman
        if ($request->payment_gateway === 'toman') {
            Config::set('payment.drivers.toman.data', [
                'res_number' => $transaction->uuid,
                'return_to' => route('cart.payment.callback_get'),
                'items' => [
                    [
                        'name' => 'شارژ کیف پول',
                        'price' => $amount * 10,
                        'quantity' => 1
                    ]
                ]
            ]);
        }

        // You can specify callbackUrl
        $pay = null;
        try {
            $pay = Payment::via($request->payment_gateway)->callbackUrl(route('cart.payment.callback_get'))->purchase(
                $invoice,
                function ($driver, $transactionId) use ($transaction) {
                    $transaction->update([
                        'gateway_transaction_id' => $transactionId,
                    ]);
                }
            );
        } catch (PurchaseFailedException $e) {
            return redirect()->back()->withErrors([$e->getMessage()]);
        }

        if ($pay != null) {
            $redirectionForm = $pay->pay();
            $data = [
                'action' => $redirectionForm->getAction(),
                'method' => $redirectionForm->getMethod(),
                'inputs' => $redirectionForm->getInputs(),
            ];

            return Inertia::render('Main/Cart/PaymentRedirect', $data);
        }

        return redirect()->back()->withErrors([__('messages.error_in_payment_gateway')]);
    }

    /**
     * withdrawal wallet amount
     */
    public function add_withdrawal(WithdrawalWalletRequest $request)
    {
        /** @var \App\Models\User $user */
        $user = auth()->user();

        // user amount for charge
        $amount = (int)str_replace(',', '', $request->amount);

        // withdrawal limit
        $withdrawalLimit = Setting::where('key', 'withdrawal_limit')->first()?->value ?? 10000;
        $withdrawalLimit = (int)str_replace(',', '', $withdrawalLimit);

        // get bank card
        $BankCard = $user->bankCards()->find($request->bank_card);
        if (!$BankCard) {
            return redirect()->back()->withErrors([__('messages.bank_account_not_found')]);
        }

        try {
            DB::transaction(function () use ($user, $amount, $withdrawalLimit, $BankCard) {
                // گرفتن جدیدترین مقدار wallet با lock
                $wallet = $user->wallet()->lockForUpdate()->first();

                // بررسی موجودی و حداقل برداشت
                if ($amount > $wallet->amount) {
                    throw new \Exception(__('messages.withdrawal_amount_is_bigger_than_wallet_amount'));
                }

                if ($amount < $withdrawalLimit) {
                    throw new \Exception(__('messages.withdrawal_amount_is_smaller_than_withdrawal_limit'));
                }

                // ایجاد تراکنش مالی
                $transaction = $user->transactions()->create([
                    'amount' => $amount * (-1),
                    'transaction_id' => rand(100000000, 999999999),
                    'description' => __('messages.transaction_bank_withdrawal'),
                    'type' => 'bank_withdrawal',
                    'status' => 'waiting_admin'
                ]);

                // کسر از کیف پول
                $wallet->update([
                    'amount' => $wallet->amount - $amount
                ]);

                // ثبت درخواست برداشت
                $user->withdrawals()->create([
                    'amount' => $amount,
                    'bank_account' => serialize($BankCard->toArray()),
                    'transaction_id' => $transaction->transaction_id,
                    'status' => 'awaiting',
                ]);
            });

            return redirect()->back()->with('message', [__('messages.withdrawal_request_submited')]);
        } catch (\Exception $e) {
            return redirect()->back()->withErrors([$e->getMessage()]);
        }
    }

    /**
     * delete withdrawal
     */
    public function delete_withdrawal(Withdrawal $withdrawal)
    {
        /** @var \App\Models\User $user */
        $user = auth()->user();
        $wallet = $user->wallet;

        if ($withdrawal->user_id != $user->id) {
            return redirect()->back()->withErrors([__('messages.unauthorized')]);
        }

        // delete from transaction list
        $transaction = Transaction::where('transaction_id', $withdrawal->transaction_id)->first();
        if ($transaction != null) {
            $transaction->delete();
        }

        // increase the amount in the wallet
        $user->wallet->update([
            'amount' => $wallet->amount + $withdrawal->amount,
        ]);

        $withdrawal->delete();

        return redirect()->back()->with('message', [__('messages.withdrawal_request_deleted')]);
    }

    /**
     * add bank card
     */
    public function add_bank_card(AddBankCardRequest $request)
    {
        /** @var \App\Models\User $user */
        $user = auth()->user();

        // check for duplicated
        if (strlen($request->card_number) < 16 || $user->bankCards()->where('card_number', $request->card_number)->where('sheba_number', $request->sheba_number)->count() > 0) {
            return redirect()->back()->withErrors([__('messages.bank_card_is_duplicated')]);
        }

        // add card number
        $user->bankCards()->create([
            'name' => $request->name,
            'card_number' => $request->card_number,
            'sheba_number' => $request->sheba_number,
            'status' => 'active',
        ]);

        return redirect()->back()->with('message', [__('messages.bank_card_added')]);
    }

    /**
     * delete bank card
     */
    public function delete_bank_card(BankCard $bankCard)
    {
        /** @var \App\Models\User $user */
        $user = auth()->user();

        if ($bankCard->user_id != $user->id) {
            return redirect()->back()->withErrors([__('messages.unauthorized')]);
        }

        $bankCard->delete();

        return redirect()->back()->with('message', [__('messages.bank_card_deleted')]);
    }
}
