<?php

namespace App\Console\Commands\Ethereum;

use App\Mail\Deposits\AdminDepositReceived;
use App\Mail\Deposits\DepositReceived;
use App\Models\Deposit\Deposit;
use App\Models\Network\Network;
use App\Models\Wallet\WalletAddress;
use App\Repositories\Currency\CurrencyRepository;
use App\Repositories\Deposit\DepositRepository;
use App\Repositories\Wallet\WalletRepository;
use App\Services\PaymentGateways\Coin\Ethereum\Services\EthereumService;
use App\Services\Wallet\WalletService;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;
use Setting;

class MonitorErcDepositsCommand extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'ethereum:monitor-erc-deposits';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Command description';

    public $depositRepository;

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();

        $this->depositRepository = new DepositRepository();
    }

    /**
     * Execute the console command.
     *
     * @return int
     */
    public function handle()
    {
        if(Network::where('id', NETWORK_ERC)->where('deposit_status', false)->count()) {
            return false;
        }

        $wallets = WalletAddress::with(['wallet.currency', 'user'])->whereIn('network_id', [NETWORK_ERC])->has('user')->orderByDesc('created_at')->get();

        foreach ($wallets as $wallet) {

            if(config('app.readonly') && !$wallet->user->hasRole('admin')) {
                continue;
            }

            $this->check($wallet);

            usleep(500000);
        }


    }

    public function check($wallet, $currency = false) {

        $response = Http::get(env('APP_ETHERSCAN_API', 'https://api.etherscan.io/api'), [
            'module' => 'account',
            'action' => 'tokentx',
            'address' => $wallet->address,
            'startblock' => '0',
            'endblock' => '999999999',
            'page' => '1',
            'offset' => '100',
            'sort' => 'desc',
            'apikey' => $this->getApiKey(),
        ]);

        $data = $response->json();

        if($response->successful() && isset($data['status']) && $data['status'] == 1) {

            foreach ($data['result'] as $transaction) {

                if(!$transaction['hash']) continue;

                if($transaction['to'] !== mb_strtolower($wallet->address)) continue;

                $currency = (new CurrencyRepository())->getCurrencyByContract($transaction['contractAddress']);

                if (!$currency || in_array(NETWORK_ERC, $currency->disabled_deposit_networks)) continue;

                $deposit = Deposit::where('txn', $transaction['hash'])->where('network_id', NETWORK_ERC)->first();

                // Deposit exists
                if($deposit) {

                    if($deposit->status == DEPOSIT_PENDING && $transaction['confirmations'] >= $currency->min_deposit_confirmation) {

                        $amount = math_sub($deposit->amount, $deposit->system_fee);

                        $deposit->status = DEPOSIT_CONFIRMED;
                        $deposit->confirms = intval($transaction['confirmations']);
                        $deposit->update();

                        $currencyWallet = (new WalletRepository())->getWalletByCurrency($wallet->user_id, $currency->id, false);

                        (new WalletService())->increase($currencyWallet, $amount);

                        try {
                            // Notify user
                            Mail::to($wallet->user)->queue(new DepositReceived($wallet->user, $deposit->amount, $currency->symbol));

                            // Admin Email Notification
                            $adminEmail = Setting::get('notification.admin_email', false);
                            $notificationAllowed = Setting::get('notification.crypto_deposits', false);

                            if($adminEmail && $notificationAllowed) {
                                $route = route('admin.reports.deposits') . "?search=" . $deposit->deposit_id;
                                Mail::to($adminEmail)->queue(new AdminDepositReceived($deposit->amount, $currency->symbol, $route));
                            }
                            // END Admin Email Notification

                        } catch (\Exception $e) {
                            Log::error('Deposit Notify Email Exception');
                        }
                    }

                    continue;

                }

                $service = new EthereumService();

                $data = [
                    'user_id' => $wallet->user_id,
                    'symbol' => $currency->symbol,
                    'hash' => $transaction['hash'],
                    'deposit_id' => generate_string(),
                    'fee' => $transaction['cumulativeGasUsed'],
                    'address' => $transaction['to'],
                    'contract' => $transaction['contractAddress'],
                    'confirms' => $transaction['confirmations'],
                    'amount' => math_divide($transaction['value'], (string)pow(10, $transaction['tokenDecimal'])),
                    'full_amount' => $transaction['value']
                ];

                $service->handleDeposit('erc20', $data);

            }

        }

        if(!$response->successful()) {
            Log::error('Etherscan Exception:');
            Log::error($response->body());
        }

    }

    public function getApiKey() {
        $keys = explode(',', env('APP_ETHERSCAN_KEY'));

        if(count($keys) == 1) return $keys[0];

        $timeframe = intval(date('i'));

        if($timeframe <= 12) {
            return $keys[0];
        } elseif($timeframe >= 13 && $timeframe <= 25) {
            return $keys[1];
        } elseif($timeframe >= 26 && $timeframe <= 38) {
            return $keys[2];
        } elseif($timeframe >= 39 && $timeframe <= 51) {
            return $keys[3];
        } elseif($timeframe >= 52 && $timeframe <= 59) {
            return $keys[4];
        }
    }
}
