<?php

namespace App\Http\Controllers\Api;

use App\Constants\Status;
use App\Http\Controllers\Controller;
use App\Lib\Api\UserActionProcess;
use App\Models\Transaction;
use App\Models\TransactionCharge;
use App\Models\User;
use App\Models\UserAction;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;

class SendMoneyController extends Controller
{
    public function checkUser(Request $request)
    {
        $findUser = User::where('username', $request->user)->orWhereRaw("CONCAT(dial_code, mobile) = ?", [$request->user])->first();
        if (!$findUser) {
            $notify[] = 'User not found';
            return responseError('validation_error', $notify);
        }

        $user = auth()->user();
        if (@$findUser && $user->username == @$findUser->username || $user->email == @$findUser->email) {
            $notify[] = 'Can\'t send money or request to your own';
            return responseError('validation_error', $notify);
        }

        $notify[] = 'Check User';
        return responseSuccess('check_user', $notify, [
            'user' => $findUser,
        ]);
    }

    public function sendMoney()
    {
        $notify[]        = "Send Money";
        $user            = auth()->user();
        $sendMoneyCharge = TransactionCharge::where('slug', 'send_money')->first();

        return responseSuccess('money_out', $notify, [
            'otp_type'                  => otpType(),
            'current_balance'           => $user->balance,
            'send_money_charge'         => $sendMoneyCharge,
            'latest_send_money_history' => Transaction::where('user_id', $user->id)
                ->where('remark', 'send_money')
                ->groupBy('receiver_id')
                ->with('receiverUser')
                ->orderBy('id', 'DESC')
                ->limit(10)
                ->get(),
        ]);
    }

    public function sendMoneyConfirm(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'amount'   => 'required|gt:0',
            'user'     => 'required',
            'otp_type' => otpType(validation: true),
            'pin'      => 'required',
        ]);

        if ($validator->fails()) {
            return responseError('validation_error', $validator->errors());
        }

        $user = auth()->user();
        if (!Hash::check($request->pin, $user->password)) {
            $notify[] = 'Provided PIN does not correct';
            return responseError('validation_error', $notify);
        }

        $receiver = User::where('username', $request->user)->orWhereRaw("CONCAT(dial_code, mobile) = ?", [$request->user])->first();
        if (!$receiver) {
            $notify[] = 'Sorry! Receiver not found';
            return responseError('validation_error', $notify);
        }

        $sendMoneyCharge = TransactionCharge::where('slug', 'send_money')->first();
        if (!$sendMoneyCharge) {
            $notify[] = 'Sorry, Transaction charge not found';
            return responseError('validation_error', $notify);
        }

        if ($request->amount < $sendMoneyCharge->min_limit || $request->amount > $sendMoneyCharge->max_limit) {
            $notify[] = 'Please follow the send money limit';
            return responseError('validation_error', $notify);
        }

        $fixedCharge = $sendMoneyCharge->fixed_charge;
        $totalCharge = ($request->amount * $sendMoneyCharge->percent_charge / 100) + $fixedCharge;
        $cap         = $sendMoneyCharge->cap;

        if ($sendMoneyCharge->cap != -1 && $totalCharge > $cap) {
            $totalCharge = $cap;
        }

        $totalAmount = getAmount($request->amount + $totalCharge);

        if ($sendMoneyCharge->daily_limit != -1 && $user->trxLimit('send_money')['daily'] + $totalAmount >= $sendMoneyCharge->daily_limit) {
            $notify[] = 'Daily send money limit has been exceeded';
            return responseError('validation_error', $notify);
        }

        if ($sendMoneyCharge->monthly_limit != 1 && ($user->trxLimit('send_money')['monthly'] + $totalAmount) > $sendMoneyCharge->monthly_limit) {
            $notify[] = 'Your monthly send money limit exceeded';
            return responseError('validation_error', $notify);
        }

        if ($totalAmount > $user->balance) {
            $notify[] = 'Sorry! Insufficient balance';
            return responseError('validation_error', $notify);
        }

        $userAction          = new UserActionProcess();
        $userAction->user_id = $user->id;
        $userAction->act     = 'send_money';

        $userAction->details = [
            'amount'       => $request->amount,
            'total_amount' => $totalAmount,
            'total_charge' => $totalCharge,
            'receiver_id'  => $receiver->id,
            'done_route'   => 'api.send.money.done',
        ];

        if (count(otpType())) {
            $userAction->type = $request->otp_type;
        }
        $userAction->submit();
        $actionId = $userAction->action_id;

        if ($userAction->verify_api_otp) {
            $notify[] = 'Verify otp';
            return responseSuccess('verify_otp', $notify, [
                'action_id' => $actionId,
            ]);
        }

        return callApiMethod($userAction->next_route, $actionId);
    }

    public function sendMoneyDone($actionId)
    {
        $user = auth()->user();

        $userAction = UserAction::where('id', $actionId)
            ->where('user_id', $user->id)
            ->where('user_type', 'USER')
            ->where('is_api', Status::YES)
            ->where('is_used', Status::NO)
            ->first();

        if (!$userAction) {
            $notify[] = 'Sorry! Unable to process';
            return responseError('validation_error', $notify);
        }

        $details = $userAction->details;

        $receiver = User::where('id', $details->receiver_id)->first();
        if (!$receiver) {
            $notify[] = 'Sorry! Receiver not found';
            return responseError('validation_error', $notify);
        }

        if (@$userAction->details->total_amount > $user->balance) {
            $notify[] = 'Sorry! Insufficient balance';
            return responseError('validation_error', $notify);
        }

        $userAction->is_used = Status::YES;
        $userAction->save();

        $user->balance -= $details->total_amount;
        $user->save();

        $senderTrx                = new Transaction();
        $senderTrx->user_id       = $user->id;
        $senderTrx->user_type     = 'USER';
        $senderTrx->before_charge = $details->amount;
        $senderTrx->amount        = $details->total_amount;
        $senderTrx->post_balance  = $user->balance;
        $senderTrx->charge        = $details->total_charge;
        $senderTrx->charge_type   = '+';
        $senderTrx->trx_type      = '-';
        $senderTrx->remark        = 'send_money';
        $senderTrx->details       = 'Send Money to';
        $senderTrx->receiver_id   = $receiver->id;
        $senderTrx->receiver_type = "USER";
        $senderTrx->trx           = getTrx();
        $senderTrx->save();

        generatePoints($senderTrx, $user);

        checkUserReward($user, $senderTrx);

        $receiver->balance += $details->amount;
        $receiver->save();

        $receiverTrx                = new Transaction();
        $receiverTrx->user_id       = $receiver->id;
        $receiverTrx->user_type     = 'USER';
        $receiverTrx->before_charge = $details->amount;
        $receiverTrx->amount        = $details->amount;
        $receiverTrx->post_balance  = $receiver->balance;
        $receiverTrx->charge        = 0;
        $receiverTrx->charge_type   = '+';
        $receiverTrx->trx_type      = '+';
        $receiverTrx->remark        = 'receive_money';
        $receiverTrx->details       = 'Received Money From';
        $receiverTrx->receiver_id   = $receiver->id;
        $receiverTrx->receiver_type = "USER";
        $receiverTrx->trx           = $senderTrx->trx;
        $receiverTrx->save();

        referralCommission($user, $details->amount, $senderTrx->trx, 'send_money');

        notify($user, 'SEND_MONEY', [
            'amount'  => showAmount($details->total_amount, currencyFormat: false),
            'charge'  => showAmount($details->total_charge, currencyFormat: false),
            'to_user' => $receiver->fullname . ' ( ' . $receiver->username . ' )',
            'trx'     => $senderTrx->trx,
            'time'    => showDateTime($senderTrx->created_at, 'd/M/Y @h:i a'),
            'balance' => showAmount($user->balance, currencyFormat: false),
        ]);

        notify($receiver, 'RECEIVED_MONEY', [
            'amount'    => showAmount($details->amount, currencyFormat: false),
            'from_user' => $user->fullname . ' ( ' . $user->username . ' )',
            'trx'       => $senderTrx->trx,
            'time'      => showDateTime($senderTrx->created_at, 'd/M/Y @h:i a'),
            'balance'   => showAmount($receiver->balance, currencyFormat: false),
        ]);

        $notify[] = 'Successfully complete the send money process';
        return responseSuccess('send_money_done', $notify, [
            'send_money' => $senderTrx->load('receiverUser'),
            'amount'     => $details->amount,
        ]);
    }

    public function sendMoneyHistory()
    {
        $notify[] = "Send Money History";
        return responseSuccess('send_money_history', $notify, [
            'history' => Transaction::where('user_id', auth()->id())->where(function ($query) {
                $query->where('remark', 'send_money')->orWhere('remark', 'receive_money');
            })->with('receiverUser', 'relatedTransaction.user')->apiQuery(),
        ]);
    }
}
