<?php

namespace App\Services\Investment\User;


use App\Models\IvInvest;
use App\Models\IvLedger;
use App\Models\IvProfit;
use App\Models\IvScheme;
use App\Helpers\MsgState;
use App\Services\Service;
use App\Enums\SchemeStatus;
use App\Filters\PlansFilter;
use Illuminate\Http\Request;
use App\Filters\LedgerFilter;
use App\Enums\InvestmentStatus;
use App\Enums\LedgerTnxType;
use App\Traits\WrapInTransaction;
use App\Services\InvestormService;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\ValidationException;
use App\Exceptions\Invest\User\InvestNoPlanException;
use App\Services\GraphData;

Class IvInvestmentService extends Service {

    use WrapInTransaction;
    private $investment;

    public function __construct(InvestormService $investment)
    {
        $this->investment = $investment;

    }

    public function getIvDashboardAmount($user_id)
    {
        $amounts = [];

        $invested = IvInvest::where('user_id', $user_id)->where('status', InvestmentStatus::ACTIVE);
        $pending = IvInvest::where('user_id', $user_id)->where('status', InvestmentStatus::PENDING);
        $profits = IvProfit::where('user_id', $user_id)->whereNull('payout');

        $amounts['invested'] = $invested->sum('amount');
        $amounts['profit'] = $invested->sum('profit');
        $amounts['locked'] = to_sum($profits->sum('amount'), $pending->sum('amount'));

        return $amounts;
    }

    public function getIvTnxList(Request $request, $type = null)
    {
        $input = array_filter($request->only(['type', 'source', 'query']));
        $filterCount = count(array_filter($input, function ($item) {
            return !empty($item) && $item !== 'any';
        }));
        $filter = new LedgerFilter(new Request(array_merge($input, ['type' => $type ?? $request->get('type')])));
        $ledgers = get_enums(LedgerTnxType::class, false);
        $sources = [AccType('main'), AccType('invest')];

        $transactions = IvLedger::loggedUser()->with(['invest'])->orderBy('id', 'desc')
            ->filter($filter)
            ->paginate(user_meta('iv_tnx_perpage', 10))->onEachSide(0);

        return compact('transactions', 'sources', 'ledgers', 'type', 'filterCount', 'input');
        
    }

    public function getInvestmentsHistory($request, $status)
    {
        $input = array_filter($request->only(['status', 'query']));
        $eligibleStatus = [
            InvestmentStatus::PENDING,
            InvestmentStatus::ACTIVE,
            InvestmentStatus::COMPLETED
        ];

        $investCount = IvInvest::select('id', 'status')->loggedUser()->get()
            ->groupBy('status')->map(function ($item) {
                return count($item);
            });

        $filter = new PlansFilter(new Request(array_merge($input, ['status' => $status ?? $request->get('status')])));
        $investQuery = IvInvest::loggedUser()->orderBy('id', 'desc')->filter($filter);

        if ($status && in_array($status, $eligibleStatus)) {
            $investQuery->where('status', $status);
            $listing = $status;
        } else {
            $listing = 'all';
        }

        $investments = $investQuery->paginate(user_meta('iv_history_perpage', 20))->onEachSide(0);

        return compact('investments', 'investCount', 'listing');

    }

    public function getInvestmentDetails($id)
    {
        $invest = IvInvest::find(get_hash($id));

        if (blank($invest)) {
            throw ValidationException::withMessages(['invest' => 'Invalid Investment!']);
        }

        $this->profitCalculate($invest);

        $invest = $invest->fresh()->load(['profits' => function ($q) {
            $q->orderBy('term_no', 'asc');
        }]);

        return $invest;

    }

    public function bulkCalculate($investments)
    {
        if (empty($investments)) {
            return false;
        }

        foreach ($investments as $invest) {
            $this->profitCalculate($invest);
        }

        return true;
    }

    public function profitCalculate(IvInvest $invest)
    {
        if (empty($invest)) {
            return false;
        }

        try {
            if (in_array($invest->status, [InvestmentStatus::ACTIVE, InvestmentStatus::COMPLETED])) {
                $this->wrapInTransaction(function ($invest) {
                    $this->investment->processInvestmentProfit($invest);
                }, $invest);
            }
        } catch (\Exception $e) {
            save_error_log($e, 'profit-calc');
        }

        return true;
    }

    public function getInvestmentPlanList($request)
    {
        $planQuery = IvScheme::query();
        $planOrder = sys_settings('iv_plan_order');

        switch ($planOrder) {
            case "reverse":
                $planQuery->orderBy('id', 'desc');
                break;
            case "random":
                $planQuery->inRandomOrder();
                break;
            case "featured":
                $planQuery->orderBy('featured', 'desc');
                break;
        }

        $plans = $planQuery->where('status', SchemeStatus::ACTIVE)->get();

        if (blank($plans)) {
            throw new InvestNoPlanException();
        }  
        
        return $plans;
    }

}


