<?php

namespace App\Http\Controllers\Api;

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

class RequestMoneyController extends Controller
{
    public function allRequests()
    {
        $notify[] = "Money Requests To Me";
        $requests = RequestMoney::where('receiver_id', auth()->id())->where('status', Status::PENDING)->with('sender')->whereHas('sender')->apiQuery();
        return responseSuccess('money_request_to_me', $notify, [
            'otp_type' => otpType(),
            'requests' => $requests,
        ]);
    }

    public function requestedHistory()
    {
        $notify[] = "My Requested History";
        $requests = RequestMoney::where('sender_id', auth()->id())->with('receiver')->orderBy('id', 'DESC')->apiQuery();
        $notify[] = 'My Requested History';
        return responseSuccess('my_requested_history', $notify, [
            'requests' => $requests,
        ]);
    }

    public function requestMoney()
    {
        $notify[]       = "Request Money";
        $transferCharge = TransactionCharge::where('slug', 'send_money')->first();

        return responseSuccess('request_money', $notify, [
            'otp_type'        => otpType(),
            'current_balance' => auth()->user()->balance,
            'transfer_charge' => $transferCharge,
        ]);
    }

    public function confirmRequest(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'amount' => 'required|gt:0',
            'user'   => 'required',
            '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);
        }

        if ($user->username == $request->user || $user->email == $request->user) {
            $notify[] = 'Can\'t make request to your own';
            return responseError('validation_error', $notify);
        }

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

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

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

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

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

        $requestDetail                 = new RequestMoney();
        $requestDetail->charge         = $totalCharge;
        $requestDetail->request_amount = $request->amount;
        $requestDetail->sender_id      = auth()->id();
        $requestDetail->receiver_id    = $receiver->id;
        $requestDetail->note           = $request->note;
        $requestDetail->save();

        notify($receiver, 'REQUEST_MONEY', [
            'amount'        => $request->amount,
            'currency_code' => gs('cur_text'),
            'requestor'     => auth()->user()->username,
            'time'          => showDateTime($requestDetail->created_at, 'd/M/Y @h:i a'),
            'note'          => $request->note,
        ]);

        $notify[] = 'Request money successfully';
        return responseSuccess('money_request_done', $notify, [
            'request_money'      => $requestDetail,
            'user'               => auth()->user(),
            'receiver_user'      => $receiver,
            'transaction_charge' => $transferCharge,
            'charge'             => $totalCharge,
        ]);
    }

    public function requestAccept(Request $request)
    {
        $validator = Validator::make(
            $request->all(),
            [
                'request_id' => 'required|integer',
                'otp_type'   => otpType(validation: true),
                'pin'      => 'required',
            ],
            [
                'request_id.required' => 'Transfer details is 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);
        }

        $requestDetail = RequestMoney::where('receiver_id', $user->id)->find($request->request_id);
        if (!$requestDetail) {
            $notify[] = 'Invalid request';
            return responseError('validation_error', $notify);
        }

        $requestor = User::find($requestDetail->sender_id);
        if (!$requestor) {
            $notify[] = 'Requestor user not found';
            return responseError('validation_error', $notify);
        }

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

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

        if ($transferCharge->daily_request_accept_limit != -1 && (auth()->user()->trxLimit('request_money')['daily'] + $requestDetail->request_amount > $transferCharge->daily_request_accept_limit)) {
            $notify[] = 'Daily request accept limit has been exceeded';
            return responseError('validation_error', $notify);
        }

        if ($transferCharge->monthly_request_accept_limit != -1 && (auth()->user()->trxLimit('request_money')['monthly'] + $requestDetail->request_amount > $transferCharge->monthly_request_accept_limit)) {
            $notify[] = 'Monthly request accept limit has been exceeded';
            return responseError('validation_error', $notify);
        }

        $userAction            = new UserActionProcess();
        $userAction->user_id   = auth()->user()->id;
        $userAction->user_type = 'USER';
        $userAction->act       = 'request_money_accept';

        $userAction->details = [
            'amount'       => $requestDetail->request_amount,
            'charge'       => $requestDetail->charge,
            'request_id'   => $requestDetail->id,
            'requestor_id' => $requestor->id,
            'done_route'   => 'api.request.accept.done',
        ];

        if (count(otpType())) {

            $userAction->type = $request->otp_type;
        }
        $userAction->submit();

        $actionId = $userAction->action_id;

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

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

    public function requestAcceptDone($actionId)
    {
        $userAction = UserAction::where('user_id', auth()->user()->id)->where('user_type', 'USER')->where('is_api', 1)->where('is_used', 0)->where('id', $actionId)->first();
        if (!$userAction) {
            $notify[] = 'Sorry! Unable to process';
            return responseError('validation_error', $notify);
        }

        $details = $userAction->details;

        $requestor = User::find($details->requestor_id);
        if (!$requestor) {
            $notify[] = 'Requestor user not found';
            return responseError('validation_error', $notify);
        }

        $user          = auth()->user();
        $requestDetail = RequestMoney::where('receiver_id', $user->id)->findOrFail($details->request_id);

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

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

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

        $userTrx                = new Transaction();
        $userTrx->user_id       = $user->id;
        $userTrx->user_type     = 'USER';
        $userTrx->before_charge = $details->amount;
        $userTrx->amount        = $details->amount;
        $userTrx->post_balance  = $user->balance;
        $userTrx->charge        = 0;
        $userTrx->trx_type      = '-';
        $userTrx->charge_type   = '+';
        $userTrx->remark        = 'request_money';
        $userTrx->details       = 'Accept money request from';
        $userTrx->receiver_id   = $requestor->id;
        $userTrx->receiver_type = "USER";
        $userTrx->trx           = getTrx();
        $userTrx->save();

        $afterCharge = ($details->amount - $details->charge);
        $requestor->balance += $afterCharge;
        $requestor->save();

        $requestorTrx                = new Transaction();
        $requestorTrx->user_id       = $requestor->id;
        $requestorTrx->user_type     = 'USER';
        $requestorTrx->before_charge = $details->amount;
        $requestorTrx->amount        = $afterCharge;
        $requestorTrx->post_balance  = $requestor->balance;
        $requestorTrx->charge        = $details->charge;
        $requestorTrx->charge_type   = '-';
        $requestorTrx->trx_type      = '+';
        $requestorTrx->remark        = 'request_money';
        $requestorTrx->details       = 'Money request has been accepted from';
        $requestorTrx->receiver_id   = $user->id;
        $requestorTrx->receiver_type = "USER";
        $requestorTrx->trx           = $userTrx->trx;
        $requestorTrx->save();

        notify($requestor, 'ACCEPT_REQUEST_MONEY_REQUESTOR', [
            'amount'       => showAmount($details->amount, currencyFormat: false),
            'to_requested' => auth()->user()->username,
            'charge'       => showAmount($details->charge, currencyFormat: false),
            'balance'      => showAmount($requestor->balance, currencyFormat: false),
            'trx'          => $userTrx->trx,
            'time'         => showDateTime($userTrx->created_at, 'd/M/Y @h:i a'),
        ]);

        notify(auth()->user(), 'ACCEPT_REQUEST_MONEY', [
            'amount'    => showAmount($details->amount, currencyFormat: false),
            'requestor' => $requestor->username,
            'balance'   => showAmount($user->balance, currencyFormat: false),
            'trx'       => $userTrx->trx,
            'time'      => showDateTime($userTrx->created_at, 'd/M/Y @h:i a'),
        ]);

        $requestDetail->status = 1;
        $requestDetail->save();

        $notify[] = 'Money request has been accepted';
        return responseSuccess('request_accept_out_done', $notify);
    }

    public function requestReject(Request $request)
    {
        $validator = Validator::make(
            $request->all(),
            [
                'request_id' => 'required|integer',
            ],
            [
                'request_id.required' => 'Transfer details is required',
            ]
        );

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

        $transfer = RequestMoney::where('receiver_id', auth()->user()->id)->find($request->request_id);
        if (!$transfer) {
            $notify[] = 'Sorry, Invalid request';
            return responseError('validation_error', $notify);
        }

        $transfer->status = 1;
        $transfer->save();

        $notify[] = 'Request has been rejected';
        return responseSuccess('rejected', $notify);
    }

    public function transfer()
    {
        $notify[]       = "Transfer Money";
        $transferCharge = TransactionCharge::where('slug', 'send_money')->first();
        return responseSuccess('money_out', $notify, [
            'otp_type'        => otpType(),
            'transfer_charge' => $transferCharge,
        ]);
    }

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

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

        $user = auth()->user();

        if ($user->username == $request->user || $user->email == $request->user) {
            $notify[] = 'Can\'t transfer balance to your own';
            return responseError('validation_error', $notify);
        }

        $transferCharge = TransactionCharge::where('slug', 'send_money')->first();

        if (!$transferCharge) {
            $notify[] = 'Sorry, Transaction charge not found';
            return responseError('validation_error', $notify);
        }

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

        $fixedCharge = $transferCharge->fixed_charge;
        $totalCharge = $request->amount * $transferCharge->percent_charge / 100 + $fixedCharge;

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

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

        if ($transferCharge->daily_limit != -1 && auth()->user()->trxLimit('transfer_money')['daily'] + $totalAmount >= $transferCharge->daily_limit) {
            $notify[] = 'Daily transfer limit has been exceeded';
            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);
        }

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

        $userAction            = new UserActionProcess();
        $userAction->user_id   = auth()->user()->id;
        $userAction->user_type = 'USER';
        $userAction->act       = 'transfer_money';

        $userAction->details = [
            'amount'      => $request->amount,
            'totalAmount' => $totalAmount,
            'totalCharge' => $totalCharge,
            'receiver_id' => $receiver->id,
            'done_route'  => 'api.transfer.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 transferMoneyDone($actionId)
    {
        $userAction = UserAction::where('user_id', auth()->user()->id)->where('user_type', 'USER')->where('is_api', 1)->where('is_used', 0)->where('id', $actionId)->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);
        }

        $user = auth()->user();

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

        $userAction->is_used = 1;
        $userAction->save();

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

        $senderTrx                = new Transaction();
        $senderTrx->user_id       = auth()->id();
        $senderTrx->user_type     = 'USER';
        $senderTrx->before_charge = $details->amount;
        $senderTrx->amount        = $details->totalAmount;
        $senderTrx->post_balance  = $user->balance;
        $senderTrx->charge        = $details->totalCharge;
        $senderTrx->charge_type   = '+';
        $senderTrx->trx_type      = '-';
        $senderTrx->remark        = 'transfer_money';
        $senderTrx->details       = 'Transfer Money to';
        $senderTrx->receiver_id   = $receiver->id;
        $senderTrx->receiver_type = "USER";
        $senderTrx->trx           = getTrx();
        $senderTrx->save();

        $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        = 'transfer_money';
        $receiverTrx->details       = 'Received Money From';
        $receiverTrx->receiver_id   = auth()->id();
        $receiverTrx->receiver_type = "USER";
        $receiverTrx->trx           = $senderTrx->trx;
        $receiverTrx->save();

        notify(auth()->user(), 'TRANSFER_MONEY', [
            'amount'  => showAmount($details->totalAmount, currencyFormat: false),
            'charge'  => showAmount($details->totalCharge, 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' => auth()->user()->fullname . ' ( ' . auth()->user()->username . ' )',
            'trx'       => $senderTrx->trx,
            'time'      => showDateTime($senderTrx->created_at, 'd/M/Y @h:i a'),
            'balance'   => showAmount($receiver->balance, currencyFormat: false),
        ]);

        $notify[] = 'Money transferred successfully';
        return responseSuccess('money_transfer_done', $notify);
    }
}
