<?php

namespace App\Http\Controllers\User;

use Exception;
use App\Models\Deposit;
use Illuminate\Support\Arr;
use Illuminate\Http\Request;
use App\Models\DepositMethod;
use chillerlan\QRCode\QRCode;
use App\Models\AdminNotification;
use Illuminate\Support\Facades\Log;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Mail;
use App\DataTables\User\DepositDataTable;
use App\Http\Requests\User\DepositRequest;
use App\Models\User;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Http\Exceptions\HttpResponseException;
use Jenssegers\Agent\Agent;
use Stevebauman\Location\Facades\Location;

class DepositController extends Controller {
	public function __construct(Request $request) {
        $this->user_agent = new Agent();
        $this->location = Location::get($request->ip());
	}
    public function getNew() {
        $components['breadcrumb'] = (object) [
            'first' => 'Deposit Baru',
            'second' => 'Deposit'
        ];
        $components['deposit_payments'] = DepositMethod::where([['type', '<>', 'Direct'], ['status', '1']])->selectRaw('payment')->distinct()->oldest('payment')->get();
        $components['deposit_methods'] = DepositMethod::where([['type', '<>', 'Direct'], ['status', '1']])->latest('id')->get();
        return view('user.deposit.new', $components);
    }
    public function postNew(PostRequest $request) {
        if ($request->ajax() == false) abort('404');
        $check_user = $user = User::find(Auth::id());
        if ($user->username == 'demouser') {
            return response()->json([
                'status'  => false, 
                'type'    => 'alert',
                'message' => 'Aksi tidak diperbolehkan.'
            ]);
        }
        $input_data = [
            'user_id'           => $user->id,
            'deposit_method_id' => escape_input($request->deposit_method),
            'amount'            => fixed_amount($request->amount),
            'phone_number'      => $request->phone_number,
            'balance'           => 0,
            'status'            => 'Pending',
            'ip_address'        => $request->ip()
        ];
        $check_data = [
            'deposit_method' => DepositMethod::find($input_data['deposit_method_id']),
            'deposit_limit'  => Deposit::where([['user_id', $user->id], ['status', 'Pending']])->get(),
        ];
        if ($input_data['amount'] < $check_data['deposit_method']['min']) {
            return response()->json([
                'status'  => false, 
                'type'    => 'alert',
                'message' => 'Minimal deposit adalah Rp '.number_format($check_data['deposit_method']['min'],0,',','.').'.'
            ]);
        } elseif ($check_data['deposit_limit']->count() >= 3) {
            return response()->json([
                'status'  => false, 
                'type'    => 'alert',
                'message' => 'Anda masih memiliki '.$check_data['deposit_limit']->count().' Deposit berstatus Pending.'
            ]);
        } else {
            $snap_token = '';
            if (!in_array($check_data['deposit_method']['payment'], ['Pulsa'])) {
                for ($i = 0; $i < 100; $i++) {
                    $input_data['amount'] = $input_data['amount'] + rand(100, 1000);
                    if (Deposit::where('amount', $input_data['amount'])->first() == true) continue;
                    break;
                }
            }
            if ($check_data['deposit_method']['is_tripay'] == '1') {
                for ($i = 0; $i < 100; $i++) {
                    $merchantRef = rand(1, 1000000);
                    if (Deposit::where('reference', $merchantRef)->first() == true) continue;
                    break;
                }
                $header_api = ["Authorization: Bearer ".website_config('tripay_payment')->api_key];
                $post_api = [
                    'method'            => $check_data['deposit_method']['tripay_payment_code'],
                    'merchant_ref'      => $merchantRef,
                    'amount'            => $input_data['amount'],
                    'customer_name'     => preg_replace('/\s/', '', website_config('main')->website_name).' - '.$user->username,
                    'customer_email'    => $user->email,
                    'customer_phone'    => $user->phone_number,
                    'allow_html'        => 0,
                    'order_items'       => [
                        [
                        'sku'       => 'Deposit',
                        'name'      => $check_data['deposit_method']['name'],
                        'price'     => $input_data['amount'],
                        'quantity'  => 1
                        ]
                    ],
                    'callback_url'      => url('callback'),
                    'return_url'        => url('redirect'),
                    'expired_time'      => (time()+(24*60*60)), // 24 jam
                    'signature'         => hash_hmac('sha256', website_config('tripay_payment')->merchant_code.$merchantRef.$input_data['amount'], website_config('tripay_payment')->private_key)
                ];
                $curl = tripay_curl('https://tripay.co.id/api/transaction/create', $header_api, $post_api, 'post');
                $curl_response = json_decode($curl, true);
                if (isset($curl_response['success']) AND $curl_response['success'] == false) {
                    return response()->json([
                        'status'  => false, 
                        'type'    => 'alert',
                        'message' => 'Silahkan coba lagi nanti.'
                    ]);
                }
                $input_data['reference'] = $curl_response['data']['reference'];
                $iteration = 1;
                foreach ($curl_response['data']['instructions'] as $item) {
                    $instructions = '<h5>'.$iteration.'. '.$item['title'].'</h5>';
                    $instructions .= '<ol>';
                    foreach ($item['steps'] as $step) {
                        $instructions .= '<li>'.$step.'</li>';
                    }
                    $instructions .= '</ol>';
                    $instructions_array[] = $instructions;
                    $iteration++;
                }
                $input_data['additional_note'] = implode('', $instructions_array);
                $check_data['deposit_method']['note'] = implode('', $instructions_array);
                if (in_array($check_data['deposit_method']['tripay_payment_code'], ['QRIS', 'QRISC']) == true) {
                    $input_data['additional_note'] .=  '<img src="'.(new QRCode())->render($curl_response['data']['qr_string']).'" alt="QR Code" />';
                    $check_data['deposit_method']['note'] .= '<img src="'.(new QRCode())->render($curl_response['data']['qr_string']).'" alt="QR Code" />';
                }
            }
            if ($check_data['deposit_method']['is_midtrans'] == '1') {
                for ($i = 0; $i < 100; $i++) {
                    $merchantRef = rand(1, 1000000);
                    if (Deposit::where('reference', $merchantRef)->first() == true) continue;
                    break;
                }
                $header_api = [
                    'Accept: application/json',
                    'Content-Type: application/json',
                    'Authorization: Basic '.base64_encode(website_config('midtrans_payment')->server_key.':').'',
                ];
                $post_api = [
                    'transaction_details' => [
                        'order_id' => $merchantRef,
                        'gross_amount' => $input_data['amount'],
                    ],
                ];
                $curl = midtrans_curl('https://app.midtrans.com/snap/v1/transactions', $header_api, $post_api, 'post');
                $curl_response = json_decode($curl, true);
                if (!isset($curl_response['token'])) {
                    return response()->json([
                        'status'  => false, 
                        'type'    => 'alert',
                        'message' => 'Silahkan coba lagi nanti.'
                    ]);
                }
                $input_data['reference'] = $merchantRef;
                $snap_token = $curl_response['token'];
                $input_data['token'] = $snap_token;
                $input_data['additional_note'] = "<button onclick=\"snap_pay('$snap_token')\" class=\"btn btn-sm btn-success\">Bayar Disini</button>";
                $check_data['deposit_method']['note'] = 'Silahkan lakukan pembayaran.';
            }
            $input_data['balance'] = $input_data['amount'] * $check_data['deposit_method']['rate'];
            $input_data['deposit_method_name'] = $check_data['deposit_method']['name'];
            if ($this->location) {
                $input_data['location'] = $this->location->countryName.' - '.$this->location->regionName.' - '.$this->location->cityName.' ('.$this->user_agent->device().' - '.$this->user_agent->platform().'/'.$this->user_agent->version($this->user_agent->platform()).' - '.$this->user_agent->browser().'/'.$this->user_agent->version($this->user_agent->browser()).')';
            } else {
                $input_data['location'] = '('.$this->user_agent->device().' - '.$this->user_agent->platform().'/'.$this->user_agent->version($this->user_agent->platform()).' - '.$this->user_agent->browser().'/'.$this->user_agent->version($this->user_agent->browser()).')';
            }
            $insert_data = Deposit::create($input_data);
            if ($insert_data == true) {
                if (json_decode($user->notification)->deposit == '1') {
                    $email_details = [
                        'content' => [
                            'id'         => $insert_data->id,
                            'method'     => $check_data['deposit_method']['name'].' ('.$check_data['deposit_method']['payment'].' - '.$check_data['deposit_method']['type'].')',
                            'amount'     => $input_data['amount'],
                            'status'     => 'Pending',
                            'ip_address' => $request->ip(),
                        ],
                        'receiver' => [
                            'email' => $user->email,
                            'name'  => $user->full_name,
                        ]
                    ];
                    send_email($email_details, 'Informasi Deposit - '.website_config('main')->website_name.'', 'user.mail.notification.deposit');
                }
                if (website_config('notification')->email <> '' AND website_config('notification')->deposit == '1') {
                    $email_details = [
                        'content' => [
                            'username'   => $user->username,
                            'full_name'  => $user->full_name,
                            'id'         => $insert_data->id,
                            'method'     => $check_data['deposit_method']['name'].' ('.$check_data['deposit_method']['payment'].' - '.$check_data['deposit_method']['type'].')',
                            'amount'     => $input_data['amount'],
                            'status'     => 'Pending',
                            'ip_address' => $request->ip(),
                        ],
                        'receiver' => [
                            'email' => website_config('notification')->email,
                            'name'  => 'Admin',
                        ]
                    ];
                    send_email($email_details, 'Informasi Deposit - '.website_config('main')->website_name.'', 'admin.mail.notification.deposit');
                }
                return response()->json([
                    'status'  => true, 
                    'is_midtrans' => $check_data['deposit_method']['is_midtrans'],
                    'snap_token' => $snap_token,
                    'deposit_detail' => url('deposit/detail/'.$insert_data->id.''),
                    'message' => '
                        Deposit anda segera diproses, lunasi pembayaran anda.
                        <br /><b>ID:</b> '.$insert_data->id.'
                        <br /><b>Metode:</b> '.$check_data['deposit_method']['name'].'
                        <br /><b>Jumlah:</b> Rp '.number_format($input_data['amount'],0,',','.').'
                        <br /><b>Catatan:</b> '.$check_data['deposit_method']['note'].'
                        <br /><b>Harap men-transfer sesuai jumlah deposit.</b>
                    '
                ]);
            } else {
                return response()->json([
                    'status'  => false, 
                    'type'    => 'alert',
                    'message' => 'Terjadi kesalahan.'
                ]);
            }
        }
    }
    public function history(DepositDataTable $dataTable) {
        $components['breadcrumb'] = (object) [
            'first' => 'Riwayat',
            'second' => 'Deposit'
        ];
        $components['methods'] = Deposit::where('user_id', Auth::user()->id)->get(['deposit_method_id', 'deposit_method_name'])->unique('deposit_method_id')->unique('deposit_method_name');
        $components['statuses'] = ['Pending', 'Success', 'Canceled'];
        $components['created_at'] = Deposit::where('user_id', Auth::user()->id)->selectRaw('DATE(created_at) AS created_at')->distinct()->latest('created_at')->get();
        $components['total'] = [
            'total' => Deposit::where('user_id', Auth::user()->id)->sum('amount'),
            'count' => Deposit::where('user_id', Auth::user()->id)->count('*')
        ];
        $components['pending'] = [
            'total' => Deposit::where('user_id', Auth::user()->id)->where('status', 'Pending')->sum('amount'),
            'count' => Deposit::where('user_id', Auth::user()->id)->where('status', 'Pending')->count('*')
        ];
        $components['canceled'] = [
            'total' => Deposit::where('user_id', Auth::user()->id)->where('status', 'Canceled')->sum('amount'),
            'count' => Deposit::where('user_id', Auth::user()->id)->where('status', 'Canceled')->count('*')
        ];
        $components['success'] = [
            'total' => Deposit::where('user_id', Auth::user()->id)->where('status', 'Success')->sum('amount'),
            'count' => Deposit::where('user_id', Auth::user()->id)->where('status', 'Success')->count('*')
        ];
        return $dataTable->render('user.deposit.history', $components);
    }
    public function detail(Deposit $target, Request $request) {
        if ($request->ajax() == false) abort('404');
        if ($target->user_id <> Auth::user()->id) return false;
        return view('user.deposit.detail', compact('target'));
    }
    public function report(Request $request) {
        if ($request->ajax() == false) abort('404');
        $check_data = Deposit::where('user_id', Auth::user()->id)->with('deposit_method')->select('deposits.*')->when(request(), function ($query) use ($request) {
            if ($request->has('start_date') AND $request->has('end_date') AND $request->start_date <> '' AND $request->end_date <> '') {
                $request->start_date = month_format($request->start_date);
                $request->end_date = month_format($request->end_date);
                $query->whereRaw('DATE(created_at) BETWEEN "'.date('Y-m-d', strtotime($request->start_date)).'" AND "'.date('Y-m-d', strtotime($request->end_date)).'"');
            }
            if ($request->has('method') <> '' AND $request->method <> '') {
                $query->where(function($query) {
                    $query
                    ->whereHas('deposit_method', function($query) {
                        $query->where('name', 'like', "%".escape_input(request('method'))."%");
                    })
                    ->orWhere('deposits.deposit_method_name', 'like', "%".escape_input(request('method'))."%");
                });
            }
            if ($request->has('status') <> '' AND $request->status <> '') {
                $query->where('deposits.status', '=', escape_input(request('status')));
            }
            if ($request->has('search') <> '' AND $request->search <> '') {
                $query->where(function($query) {
                    $query
                    ->whereHas('deposit_method', function($query) {
                        $query->where('name', 'like', "%".escape_input(request('search'))."%");
                    })
                    ->orWhere('deposits.id', 'like', "%".escape_input(request('search'))."%")
                    ->orWhere('deposits.deposit_method_name', 'like', "%".escape_input(request('search'))."%")
                    ->orWhere('deposits.amount', 'like', "%".escape_input(request('search'))."%")
                    ->orWhere('deposits.balance', 'like', "%".escape_input(request('search'))."%")
                    ->orWhere('deposits.status', 'like', "%".escape_input(request('search'))."%");
                });
            }
        })->get();
        return response()->json([
            'status'  => true, 
            'total' => 'Rp '.number_format($check_data->sum('amount'),0,',','.').' ('.number_format($check_data->count('*'),0,',','.').')',
            'pending' => 'Rp '.number_format($check_data->where('status', 'Pending')->sum('amount'),0,',','.').' ('.number_format($check_data->where('status', 'Pending')->count('*'),0,',','.').')',
            'canceled' => 'Rp '.number_format($check_data->where('status', 'Canceled')->sum('amount'),0,',','.').' ('.number_format($check_data->where('status', 'Canceled')->count('*'),0,',','.').')',
            'success' => 'Rp '.number_format($check_data->where('status', 'Success')->sum('amount'),0,',','.').' ('.number_format($check_data->where('status', 'Success')->count('*'),0,',','.').')',
            
        ]);
    }
}

class PostRequest extends FormRequest {
    protected function prepareForValidation() {
        $this->merge([
            'amount' => $this->amount <> '' ? fixed_amount($this->amount) : '',
        ]);
    }
    protected function getValidatorInstance() {
        $instance = parent::getValidatorInstance();
        if ($instance->fails() == true) {
            throw new HttpResponseException(response()->json([
                'status'  => false, 
                'type'    => 'validation',
                'message' => parent::getValidatorInstance()->errors()
            ]));
        } else {
            if (RateLimiter::attempt('limit: '.Auth::user()->username, 1, function() {}, 30) == false) {
                $seconds = RateLimiter::availableIn('limit: '.Auth::user()->username);
                throw new HttpResponseException(response()->json([
                    'status'  => false, 
                    'type'    => 'alert',
                    'message' => 'Terlalu banyak permintaan.'
                ], 429)->header('retry-after', $seconds));
            }
            return parent::getValidatorInstance();
        }
    }
    public function rules(Request $request) {
        return [
            'deposit_method'    => 'required|numeric|exists:deposit_methods,id',
            'amount'            => 'required|numeric|integer|min:0',
            'phone_number'      => $request->payment == 'Pulsa' ? 'required|numeric|phone:ID,mobile' : '',
        ];
    }
    public function attributes() {
        return [
            'deposit_method' => 'Metode',
            'amount'            => 'Jumlah',
            'phone_number'      => 'No. Pengirim',
            'approval'          => 'Persetujuan',
        ];
    }
}