<?php

namespace App\Http\Controllers\Invest\User;


use App\Models\IvInvest;
use App\Models\IvProfit;

use App\Models\UserMeta;
use App\Helpers\MsgState;
use Brick\Math\BigDecimal;
use App\Services\GraphData;

use Illuminate\Http\Request;
use App\Enums\InvestmentStatus;
use Illuminate\Support\Facades\DB;
use App\Http\Controllers\Controller;
use Illuminate\Validation\ValidationException;
use App\Exceptions\Invest\User\InvestNoPlanException;
use App\Services\Investment\IvBalanceTransferService;
use App\Services\Investment\User\IvInvestmentService;
use App\Http\Requests\Invest\User\PayoutProceedRequest;

class InvestmentController extends Controller
{   
    private $ivInvestmentService;
    private $transferProcessor;

    public function __construct(            
        IvInvestmentService $ivInvestmentService,
        IvBalanceTransferService $transferProcessor
    ) {
        $this->ivInvestmentService = $ivInvestmentService;
        $this->transferProcessor = $transferProcessor;
    }
    
    public function index(Request $request, GraphData $graph)
    {
        $user_id = auth()->id();

        $investments = IvInvest::whereIn('status', [
            InvestmentStatus::PENDING,
            InvestmentStatus::ACTIVE,
            InvestmentStatus::COMPLETED
        ])->where('user_id', $user_id)
            ->orderBy('id', 'desc')->get()->groupBy('status');

        $recents = IvInvest::where('user_id', $user_id)->where('status', InvestmentStatus::COMPLETED)->latest()->limit(3)->get();
        $actived = IvInvest::where('user_id', $user_id)->where('status', InvestmentStatus::ACTIVE)->get();

        // Profit calculate
        if ($actived->count() > 0) {
            $this->ivInvestmentService->bulkCalculate($actived);
        }

        $amounts = $this->ivInvestmentService->getIvDashboardAmount($user_id);

        // Graph chart
        $graph->set('profit', 'term_start');

        $profit = IvInvest::select(DB::raw('SUM(profit) as profit,term_start'))
                ->where('status', InvestmentStatus::ACTIVE)
                ->groupBy(DB::RAW('CAST(term_start as DATE)'))
                ->get();

        $profitChart = $graph->getDays($profit, 31)->flatten();

        $graph->set('amount', 'term_start');

        $investment = IvInvest::select(DB::raw('SUM(amount) as amount,term_start'))
                    ->where('status', InvestmentStatus::ACTIVE)
                    ->groupBy(DB::RAW('CAST(term_start as DATE)'))
                    ->get();

        $investChart = $graph->getDays($investment, 31)->flatten();

        return view("investment.user.dashboard", compact('investments', 'recents', 'amounts', 'profitChart', 'investChart'));
    }

    public function planList(Request $request)
    {
        try {
            $plans = $this->ivInvestmentService->getInvestmentPlanList($request);            
            return view("investment.user.invest-plans", compact('plans'));
        } catch (InvestNoPlanException $e) {
            $errors = MsgState::of('no-plan', 'invest');
            return view("investment.user.invest.errors", $errors);
        }
    }

    public function investmentHistory(Request $request, $status = null)
    {
        $investmentsHistory = $this->ivInvestmentService->getInvestmentsHistory($request, $status);

        return view("investment.user.history", $investmentsHistory);
    }

    public function investmentDetails($id)
    {
        $invest = $this->ivInvestmentService->getInvestmentDetails($id);

        return view("investment.user.plan", compact('invest'));
    }

    public function transactionList(Request $request, $type=null)
    {
        $ivTnxList = $this->ivInvestmentService->getIvTnxList($request, $type);

        return view("investment.user.transactions", [
            'transactions' => data_get($ivTnxList, 'transactions'),
            'sources' => data_get($ivTnxList, 'sources'),
            'ledgers' => data_get($ivTnxList, 'ledgers'),
            'type'    => data_get($ivTnxList, 'type') ?? 'all',
            'filter_count' => data_get($ivTnxList, 'filterCount'),
            'input' => data_get($ivTnxList, 'input'),
        ]);
    }

    public function payoutInvest(Request $request)
    {
        $min = min_to_compare();
        $balance = user_balance(AccType('invest'));

        if ($request->ajax()) {
            $balance = (BigDecimal::of($balance)->compareTo($min) != 1) ? false : $balance;

            return view("investment.user.misc.modal-payout", compact("balance"))->render();
        } else {
            return redirect()->route('user.investment.dashboard');
        }
    }

    public function payoutProceed(PayoutProceedRequest $request)
    {
        $min = min_to_compare();
        $amount = $request->get('amount');
        $balance = user_balance(AccType('invest'));

        $this->transferProcessor->checkBeforeTransfer($min, $amount, $balance);

        $transfer = $this->transferProcessor->transfer($amount);

        if ($transfer) {
            return response()->json(['title' => __('Fund Transfered'), 'msg' => __('Your funds successfully transferred into your main account balance.'), 'reload' => true ]);
        } else {
            throw ValidationException::withMessages(['warning' => __('Sorry, something went wrong! Please reload the page and try again.')]);
        }
    }

    public function ivSettings(Request $request)
    {
        $user = auth()->user();
        $metas = UserMeta::where('user_id', $user->id)->pluck('meta_value', 'meta_key')->toArray();
        $setting = $user->auto_transfer_settings;

        if ($request->ajax()) {
            return view('investment.user.misc.modal-settings', compact('metas', 'setting'))->render();
        } else {
            return redirect()->route('user.investment.dashboard');
        }
    }

    public function saveIvSettings(Request $request)
    {
        $input = $request->validate([
            'auto_transfer' => 'string',
            'min_transfer' => 'bail|nullable|numeric|gte:'.gss("iv_min_transfer")
        ], [
            'min_transfer.numeric' => __('Minimum amount must be a valid number.'),
            'min_transfer.gte' => __('Minimum amount must be greater than or equal to :amount.', ['amount' => money(gss("iv_min_transfer"), base_currency())]),
        ]);
        $input['auto_transfer'] = $request->get('auto_transfer', 'off');

        foreach ($input as $key => $value) {
            UserMeta::updateOrCreate([
                'user_id' => auth()->user()->id,
                'meta_key' => 'setting_'.$key
            ], ['meta_value' => $value ?? null]);
        }

        return response()->json(['title' => __('Settings Updated!'), 'msg' => __('Auto Transfer setting has been updated successfully.'), 'reload' => true]);
    }
}
