<?php

namespace App\Http\Controllers\Admin;

use App\Constants\Status;
use App\Http\Controllers\Controller;
use App\Lib\RequiredConfig;
use App\Lib\TreeInvestLab;
use App\Models\Invest;
use App\Models\Project;
use App\Models\TimeSetting;
use App\Models\Transaction;
use App\Rules\FileTypeValidate;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;

class ManageProjectController extends Controller {
    public function index() {
        $pageTitle = "All Projects";
        $projects  = Project::searchable(['name', 'per_tree_amount', 'total_quantity', 'investment', 'timeSetting:name,time'])->with('timeSetting')->orderBy('id', 'desc')->get();
        return view('admin.project.index', compact('pageTitle', 'projects'));
    }

    public function dispatchableProjects() {
        $pageTitle = "Dispatchable Projects";
        $projects  = Project::with('timeSetting')->where('harvest_date', '<', now())->where('is_dispatch', Status::INTEREST_NOT_DISPATCH)->orderBy('id', 'desc')->get();
        return view('admin.project.dispatchable', compact('pageTitle', 'projects'));
    }

    public function dispatchedProjects() {
        $pageTitle = "Dispatched Projects";
        $projects  = Project::with('timeSetting')
            ->where('is_dispatch', Status::INTEREST_DISPATCH)
            ->orderBy('id', 'desc')
            ->get();

        return view('admin.project.dispatched', compact('pageTitle', 'projects'));
    }

    public function create() {
        $pageTitle = "Create New Project";
        $times     = TimeSetting::active()->get();
        abort_if(request()->step && !in_array(request()->step, [1, 2]), 404);

        $step = request()->step ?? 1;

        $project = Project::active()->where('step', 1)->first();
        if ($project) {
            return to_route('admin.project.edit', $project->id) . "?step=2";
        }
        return view('admin.project.form', compact('pageTitle', 'times', 'step'));
    }

    public function edit($id) {
        $pageTitle = "Edit Project";
        $times     = TimeSetting::active()->get();
        abort_if(request()->step && !in_array(request()->step, [1, 2]), 404);
        $step    = request()->step ?? 1;
        $project = Project::findOrFail($id);
        return view('admin.project.form', compact('pageTitle', 'times', 'project', 'step'));
    }

    public function store(Request $request, $id = 0) {
        $this->validation($request, $id);

        if ($id) {
            $project  = Project::findOrFail($id);
            $notify[] = ['success', 'Project updated successfully'];
        } else {
            $project       = new Project();
            $project->step = 1;
            RequiredConfig::configured('project_initiate');
            $notify[] = ['success', 'Project create successfully'];
        }

        $this->saveData($project, $request);

        if ($id) {
            $step = $request->step;
        } else {
            $step = 2;
        }

        return redirect(route('admin.project.edit', $project->id) . "?step=$step")->withNotify($notify);
    }

    protected function saveData($project, $request) {
        $purifier = new \HTMLPurifier();
        if ($request->step == 1) {
            if ($request->hasFile('image')) {
                try {
                    $thumb          = getFileSize('project', thumb: true);
                    $old            = @$project->image;
                    $project->image = fileUploader($request->image, getFilePath('project'), getFileSize('project'), $old, $thumb);
                } catch (\Exception $exp) {
                    $notify[] = ['error', 'Couldn\'t upload project image'];
                    return back()->withNotify($notify);
                }
            }

            $investEndDate = Carbon::parse($request->invest_end_date);
            $harvestMonths = (int) $request->harvest_time;
            $harvestDate   = $investEndDate->addMonths($harvestMonths);

            $project->name             = $request->name;
            $project->slug             = $request->slug;
            $project->per_tree_amount  = $request->per_tree_amount;
            $project->investment       = ($request->total_quantity * $request->per_tree_amount);
            $project->total_quantity   = $request->total_quantity;
            $project->minimum_quantity = $request->minimum_quantity;
            $project->maximum_quantity = $request->maximum_quantity;
            $project->harvest_time     = $harvestMonths;
            $project->harvest_date     = $harvestDate;
            $project->invest_end_date  = $request->invest_end_date;
            $project->video_link       = $request->video_link;
            $project->interest_type    = $request->interest_type == Status::PERCENTAGE ? Status::PERCENTAGE : Status::FIXED;
            $project->minimum_interest = @$request->minimum_interest ?? Status::NO;
            $project->maximum_interest = @$request->maximum_interest ?? Status::NO;
            $project->fixed_interest   = @$request->fixed_interest ?? Status::NO;
            $project->time_setting_id  = $request->time_setting_id;
            $project->lifetime         = $request->return_type == Status::LIFETIME ? Status::LIFETIME : Status::REPEAT;
            $project->capital_back     = $request->capital_back ?? Status::NO;
            $project->repeat_time      = $request->repeat_time ?? Status::NO;
            $project->featured         = $request->featured ? Status::YES : Status::NO;
            $project->about            = $purifier->purify($request->about);
            $project->overview         = $purifier->purify($request->overview);
            $project->crop_duration    = $request->crop_duration;
            $project->crop_date        = getFutureYear($request->crop_duration);
        } else {
            if (!$request->overview) {
                $project->step   = 2;
                $project->status = Status::ENABLE;
            }
            $project->faqs = [
                'question' => $request->question,
                'answer'   => $request->answer,
            ];
        }
        $project->save();
    }
    protected function validation($request, $id) {

        if ($request->step == 1) {
            $isRequired = $id ? 'nullable' : 'required';
            $request->validate([
                'image'            => ["$isRequired", 'file', new FileTypeValidate(['jpg', 'jpeg', 'png'])],
                'about'            => 'required',
                'name'             => 'required|string',
                'slug'             => ['required', 'string', Rule::unique('projects', 'slug')->ignore($id)],
                'per_tree_amount'  => 'required|numeric',
                'total_quantity'   => 'required|integer|gt:maximum_quantity',
                'investment'       => 'required|numeric',
                'minimum_quantity' => 'required|integer|gt:0',
                'maximum_quantity' => 'required|integer|gt:minimum_quantity',
                'invest_end_date'  => 'required',
                'date_format:Y-m-d',
                'after:yesterday',
                'harvest_time'     => 'required|integer|gt:0',
                'video_link'       => 'nullable|url',
                'interest_type'    => 'required|in:1,2',
                'minimum_interest' => 'nullable|required_if:interest_type,1|gt:0',
                'maximum_interest' => 'nullable|required_if:interest_type,1|gt:minimum_interest',
                'fixed_interest'   => 'nullable|required_if:interest_type,2|numeric|gt:0',
                'time_setting_id'  => ['required', 'integer', 'gt:0', Rule::exists('time_settings', 'id')->where(function ($query) {
                    $query->where('status', Status::YES);
                })],
                'return_type'      => 'required|integer|in:1,2',
                'repeat_time'      => 'nullable|required_if:return_type,2|gt:0',
                'capital_back'     => 'nullable|required_if:return_type,2|in:1,0',
                'crop_duration'    => 'required|integer|gt:0',
                'overview'         => 'required',

            ], [
                'time_setting_id.required' => 'Interest Interval period is required',
            ]);
        } else {
            $request->validate([
                'question.*' => 'required',
                'answer.*'   => 'required',
            ]);
        }
    }
    public function status($id) {
        return Project::changeStatus($id);
    }

    public function investHistory($id) {
        $pageTitle = 'Invest History';
        $invests   = Invest::where('project_id', $id)->with('project', 'user')->orderBy('id', 'desc')->paginate(getPaginate());
        return view('admin.project.invest_history', compact('pageTitle', 'invests'));
    }

    public function interestDispatch(Request $request, $id) {
        $project = Project::where('id', $id)->where('harvest_date', '<', now())->where('is_dispatch', Status::INTEREST_NOT_DISPATCH)->with('invests')->whereHas('invests', function ($q) {
            $q->where('status', Status::INVEST_RUNNING);
        })->active()->firstOrFail();

        $request->validate([
            'interest' => [
                Rule::requiredIf($project->interest_type == Status::PERCENTAGE),
                'integer',
                Rule::when($project->interest_type == Status::PERCENTAGE, [
                    'between:' . $project->minimum_interest . ',' . $project->maximum_interest,
                ]),
            ],
        ]);

        foreach ($project->invests as $item) {
            if ($project->interest_type == Status::PERCENTAGE) {
                $interestAmount = ($item->amount * $request->interest) / 100;
                $interest       = $request->interest . '%';
            } else {
                $interestAmount = $project->fixed_interest;
                $interest       = showAmount($interestAmount);
            }

            $hours  = (int) $project->timeSetting->time;
            $next   = now()->addHours($hours)->toDateTimeString();
            $period = ($project->lifetime == Status::LIFETIME) ? -1 : $project->repeat_time;

            $shouldPay = -1;
            if ($period > 0) {
                $shouldPay = $interestAmount * $period;
            }

            //data-update
            $item->interest   = $interestAmount;
            $item->next_time  = $next;
            $item->should_pay = $shouldPay;
            $item->save();

            notify($item->user, 'INTEREST_DISPATCH', [
                'interest'     => $interest,
                'payable'      => showAmount($shouldPay),
                'project_name' => @$project->name,
                'harvest_date' => showDateTime(@$project->harvest_date, 'd-M-Y'),
                'next_pay'     => showDateTime(@$next),
            ]);
        }

        $project->reserved_interest = $interest;
        $project->is_dispatch       = Status::INTEREST_DISPATCH;
        $project->save();

        $notify[] = ['success', 'Invest config & Project interest successfully dispatched'];
        return back()->withNotify($notify);
    }

    public function cancelInvest(Request $request) {
        $request->validate([
            'invest_id' => 'required|integer',
            'action'    => 'required|in:1,2,3,4',
        ]);

        $invest = Invest::with('user')->where('status', Status::INVEST_RUNNING)->findOrFail($request->invest_id);

        if ($invest->project->is_dispatch) {
            $notify[] = ['error', 'Project dispatched'];
            return back()->withNotify($notify);
        }
        if ($request->action == 1 || $request->action == 2) {
            TreeInvestLab::capitalReturn($invest);
        }

        if ($request->action == 2 || $request->action == 4) {
            $this->interestBack($invest);
        }

        $invest->status = Status::INVEST_CANCELLED;
        $invest->save();

        $notify[] = ['success', 'Investment canceled successfully'];
        return back()->withNotify($notify);
    }

    private function interestBack($invest) {
        $user      = $invest->user;
        $totalPaid = $invest->paid;
        $user->balance -= $totalPaid;

        if ($totalPaid <= $user->balance) {
            $this->createTransaction($user->id, $totalPaid, $user->balance);
        } else {
            $this->createTransaction($user->id, $user->balance, 0, );
        }
    }

    private function createTransaction($userId, $amount, $postBalance) {
        $transaction               = new Transaction();
        $transaction->user_id      = $userId;
        $transaction->amount       = $amount;
        $transaction->post_balance = $postBalance;
        $transaction->charge       = 0;
        $transaction->trx_type     = '-';
        $transaction->details      = 'Interest return for investment canceled';
        $transaction->trx          = getTrx();
        $transaction->remark       = 'interest_return';
        $transaction->save();
    }

    // Seo-Start //
    public function frontendSEO($id) {
        $key       = 'Manage Project SEO';
        $data      = Project::findOrFail($id);
        $pageTitle = 'SEO Configuration';
        return view('admin.project.seo', compact('pageTitle', 'key', 'data'));
    }

    public function updateSEO(Request $request, $id) {
        $request->validate([
            'image' => ['nullable', new FileTypeValidate(['jpeg', 'jpg', 'png'])],
        ]);

        $data  = Project::findOrFail($id);
        $image = @$data->seo_content->image;
        if ($request->hasFile('image')) {
            try {
                $path  = getFilePath('project') . '/seo';
                $image = fileUploader($request->image, $path, getFileSize('seo'), @$data->seo_content->image);
            } catch (\Exception $exp) {
                $notify[] = ['error', 'Couldn\'t upload the image'];
                return back()->withNotify($notify);
            }
        }
        $data->seo_content = [
            'image'              => $image,
            'description'        => $request->description,
            'social_title'       => $request->social_title,
            'social_description' => $request->social_description,
            'keywords'           => $request->keywords,
        ];
        $data->save();

        $notify[] = ['success', 'SEO content updated successfully'];
        return back()->withNotify($notify);
    }

    public function checkSlug($id = null) {

        $project = Project::where('slug', request()->slug);
        if ($id) {
            $project = $project->where('id', '<>', $id);
        }
        $exist = $project->exists();
        return response()->json([
            'exists' => $exist,
        ]);
    }
}
