<?php

namespace App\Console\Commands\Market;

use App\Events\OrderBookRefreshed;
use App\Models\Market\Market;
use App\Models\Order\Order;
use App\Models\User\User;
use App\Services\Liquidity\Binance\BinanceApi;
use App\Services\Order\OrderService;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;

use Illuminate\Console\Command;
use Setting;

class MarketTradeBotCommand extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'market:trade {marketName}';

    protected $market = null;

    public $maxTradeSize = null;

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

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

    /**
     * Execute the console command.
     *
     * @return int
     */
    public function handle()
    {
        $binanceApi = new BinanceApi();

        if(!$this->market) {
            $this->market = Market::where('name', $this->argument('marketName'))->first();
        }

        try {

            $user = User::find(1);
            $fee = Setting::get('trade.taker_fee', INITIAL_TRADE_TAKER_FEE);

            $binanceApi->depthStream(market_sanitize($this->market->name), function ($data, $symbol, $bids, $asks) use ($user, $fee) {

                $isBuy = rand(0,1);
                $tradeAllowed = rand(1, config('app.trade frequency'));

                DB::table('orders')
                    ->where('liquidity_id', 1)
                    ->where('market_id', $this->market->id)
                    ->delete();

                $askInsert = [];

                foreach ($asks as $ask) {

                    $this->info('[' . date('H:i:s') . '] Ask Price: ' . $ask[0]);
                    $this->info('[' . date('H:i:s') . '] Ask Quantity: ' . $ask[1]);

                    // Model data
                    $askInsert[] = [
                        'id' => Str::uuid(),
                        'user_id' => $user->id,
                        'market_id' => $this->market->id,
                        'type' => 'limit',
                        'side' => 'sell',
                        'liquidity_id' => 1,
                        'initial_quantity' => $ask[1],
                        'quantity' => $ask[1],
                        'initial_quote_quantity' => 0,
                        'quote_quantity' => 0,
                        'price' => $ask[0],
                        'fee' => 0,
                        'fee_rate' => $fee,
                        'base_currency_id' => $this->market->base_currency_id,
                        'quote_currency_id' => $this->market->quote_currency_id,
                        'created_at' => Carbon::now()
                    ];

                }

                // Store order
                Order::insert($askInsert);

                $bidInsert = [];

                foreach ($bids as $bid) {

                    // Model data
                    $bidInsert[] = [
                        'id' => Str::uuid(),
                        'user_id' => $user->id,
                        'market_id' => $this->market->id,
                        'type' => 'limit',
                        'side' => 'buy',
                        'liquidity_id' => 1,
                        'initial_quantity' => $bid[1],
                        'quantity' => $bid[1],
                        'initial_quote_quantity' => 0,
                        'quote_quantity' => 0,
                        'price' => $bid[0],
                        'fee' => 0,
                        'fee_rate' => $fee,
                        'base_currency_id' => $this->market->base_currency_id,
                        'quote_currency_id' => $this->market->quote_currency_id,
                        'created_at' => Carbon::now()
                    ];
                }

                // Store order
                Order::insert($bidInsert);

                $limitOrders = Order::limitType()->oldest()->where('market_id', $this->market->id)->where('liquidity_id', 0)->get();

                foreach($limitOrders as $limitOrder) {
                    (new OrderService())->processOrder($limitOrder, true);
                }

                // Find the lowest ask and cache
                $lowestAsk = Order::sellLimit()->lowest()->first();

                if($lowestAsk)
                    market_set_stats($this->market->id, 'ask', $lowestAsk->price);

                // Find the lowest bid and cache
                $highestBid = Order::buyLimit()->highest()->first();
                if($highestBid)
                    market_set_stats($this->market->id, 'bid', $highestBid->price);

                event(new OrderBookRefreshed($this->market->name));

                if($tradeAllowed == 1) {

                    if ($isBuy) {
                        $api = Http::withToken('X5I2OqNMXByS40roceNhkkxsT6pOvJRSBamk4QEN')->post(route('orders.store'), [
                            'type' => 'market',
                            'side' => 'buy',
                            'market' => $this->market->name,
                            'quoteQuantity' => math_formatter(math_multiply(generate_market_volume($this->market->name), $bids[0][0]), $this->market->quote_precision),
                        ]);

                        print_r($api->json());

                    } else {
                        $api = Http::withToken('X5I2OqNMXByS40roceNhkkxsT6pOvJRSBamk4QEN')->post(route('orders.store'), [
                            'type' => 'market',
                            'side' => 'sell',
                            'market' => $this->market->name,
                            'quantity' => generate_market_volume($this->market->name),
                        ]);
                        print_r($api->json());
                    }
                }

            });
        } catch (\Exception $e) {
            Log::error('Liquidity error');
            Log::error($e);
            $this->handle();
        }
    }
}
