<?php

namespace App\Repositories\Option;

use App\Events\WalletUpdated;
use App\Models\Market\Market;
use App\Models\Option\Option;
use App\Models\Option\OptionTemplate;
use App\Models\Option\OptionTemplateUser;
use App\Models\Transaction\Transaction;
use App\Models\User\User;
use App\Repositories\Market\MarketRepository;
use App\Repositories\Wallet\WalletRepository;
use App\Services\Wallet\WalletService;
use Auth;
use Illuminate\Support\Facades\DB;
use Setting;

class OptionRepository
{
    public
        $order,
        $market,
        $walletService,
        $walletRepository,
        $orderService,
        $marketRepository,
        $user,
        $type;

    public function __construct()
    {
        $this->walletService = new WalletService();

        $this->marketRepository = new MarketRepository();
        $this->walletRepository = new WalletRepository();

    }

    public function get($market) {

        $market = Market::whereName($market)->value('id');

        $orders = Option::whereMarketId($market);

        return $orders->get();
    }

    public function findById($uuid) {
        return Option::find($uuid);
    }

    public function insert($insert) {

        Option::insert($insert);

        return $this->findById($this->uuid);
    }

    public function store() {

        $market = $this->marketRepository->get(request()->get('market'));
        $user = auth()->user()->getAuthIdentifier();
        $amount = request()->get('quantity');
        $type = request()->get('type');
        $side = request()->get('side');

        $marketPrice = market_get_stats($market->id, 'last');

        $templateId = null;
        $template = $this->getOptionsTemplateByFilter($market->id, $side, $type, $amount);

        $isException = false;
        $isUserUsed = false;

        if($template) {
            $isException = $template->action == 'profit' ? 'won' : 'lost';
            $templateId = $template->id;

            $isUserUsed = $this->isTemplateUsed($template->id, $user);

            if($isUserUsed) {
                $isException = null;
            } else {
                $this->storeTemplateUsed($template->id, $user);
            }
        }

        $pnlPercentage = config('app.options_pnl');
        $pnlSelected = $pnlPercentage[$type];

        $pnl = math_percentage($amount, $pnlSelected);

        $option = new Option();
        $option->market_id = $market->id;
        $option->user_id = $user;
        $option->currency_id = $market->quote_currency_id;
        $option->amount = $amount;
        $option->price = $marketPrice;
        $option->pnl = $pnl;
        $option->period = $type;
        $option->type = $side;
        $option->template_id = $templateId;
        $option->status = 'active';
        $option->uuid = generate_uuid();
        $option->is_exception = $isException;
        $option->save();

        $wallet = $this->walletRepository->getWalletByCurrency($user, $market->quote_currency_id);
        $this->walletService->decrease($wallet, $amount, 'wallet');

        event(new WalletUpdated($wallet));

        return $option->uuid;
    }

    public function storeTemplate($insert) {
        return OptionTemplate::insert($insert);
    }

    public function updateTemplate($id, $data) {

        $template = OptionTemplate::find($id);
        $template->update($data);
        return $template->fresh();
    }

    public function deleteTemplate($id) {

        $template = OptionTemplate::find($id);
        $template->delete();

        return true;
    }

    public function getOptionTemplateId($id) {
        return OptionTemplate::find($id);;
    }

    public function open($market = false) {

        $orders = Option::processable()->where('user_id', auth()->id());

        if($market) {
            $market = Market::whereName($market)->value('id');
            $orders->whereMarketId($market);
        }

        $orders->has('market');

        return $orders->get();
    }

    public function trades($market = false) {

        $orders = Option::processed()->where('user_id', auth()->id());

        if($market) {
            $market = Market::whereName($market)->value('id');
            $orders->whereMarketId($market);
        }

        $orders->limit(10);

        $orders->orderBy('created_at', 'desc');

        $orders->has('market');

        return $orders->get();
    }

    public function getReport() {

        $transaction = Option::query();

        $transaction->filter(request()->only(['search', 'referrer']))->orderByLatest();

        $transaction->has('market')->has('user')->has('currency');

        $transaction->with(['market', 'currency', 'user']);

        return $transaction->paginate(50)->withQueryString();
    }

    public function getReportUser(User $user) {

        $transaction = Option::query();

        $transaction->filterUser(request()->only(['market', 'side']))->orderByLatest();

        $transaction->has('market')->has('user')->has('currency');

        $transaction->with(['market', 'currency', 'user']);

        $transaction->where('user_id', $user->id);

        $transaction->where('status', '!=', 'active');

        return $transaction->paginate(50)->withQueryString();
    }

    public function getOptionsTemplates() {

        $options = OptionTemplate::query();

        $options->with('market');

        $options->orderBy('id', 'desc');

        return $options->paginate(50)->withQueryString();
    }

    public function getOptionsTemplateByFilter($market, $type, $period, $amount) {

        $options = OptionTemplate::query();

        $options->where('type', $type);
        $options->where('period', $period);
        $options->where('amount', $amount);
        $options->where('market_id', $market);

        return $options->first();
    }

    public function isTemplateUsed($id, $user) {
        return OptionTemplateUser::where('template_id', $id)->where('user_id', $user)->first();
    }

    public function storeTemplateUsed($id, $user) {
        $m = new OptionTemplateUser();
        $m->template_id = $id;
        $m->user_id = $user;
        $m->save();
    }

    public function getStatReport($period) {
        return DB::table('options')
            ->selectRaw('markets.name as pair, currencies.symbol, SUM(options.pnl) as income, COUNT(*) as total')
            ->join('currencies', 'currencies.id', 'options.currency_id')
            ->join('markets', 'markets.id', 'options.market_id')
            ->where('options.status', '!=', 'active')
            ->whereBetween('options.created_at', $period)
            ->groupByRaw('markets.name, currencies.symbol')->get();
    }

}
