<?php

namespace App\Http\Controllers\Web;

use App\City;
use App\ConsultingComplaint;
use App\ConsultingEvaluate;
use App\ConsultingRequest;
use App\DocumentationRequest;
use App\Helpers\ImageHelper;
use App\Helpers\Sms;
use App\Http\Requests\ConsultingComplaintRequest;
use App\Http\Requests\ConsultingEvaluateRequest;
use App\Http\Requests\Web\RegisterRequest;
use App\Http\Requests\Web\UpdateProfileRequest;
use App\Jobs\CodeVerificationJob;
use App\User;
use App\UsersNotification;
use Illuminate\Contracts\View\Factory;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\Validator;
use Illuminate\Http\Request;
use App\Http\Requests\Web\RegAndLogPhoneRequest;
use Illuminate\Support\Facades\Auth;
use App\Http\Controllers\Controller;
use Illuminate\View\View;
use Mockery\Exception;

class UserController extends Controller
{

    protected $view = 'web.users.';

    /**
     * User profile
     * @return Factory|View
     * @throws \Exception
     */
    public function profile()
    {
        $user = Auth::user();
        $title = __('members.my_profile');
        if (!in_array($user->role, ['user'])){
            return  abort(404);
        }
        $city = City::find($user->city_id) ?? null;
        $cityName = $city ? descriptions(City::find($user->city_id))->name : null;

        return view($this->view.'profile.index', get_defined_vars());
    }

    /**
     * All user consultings
     * @return Factory|View
     */
    public function myConsulting()
    {
        $title = __('members.my_consulting');
        $user = Auth::user();
        $consultings = ConsultingRequest::where('user_id', $user->id)->cursor();
        return view($this->view.'my_consulting.index', get_defined_vars());
    }

    /**
     * Consulting details
     * @param ConsultingRequest $consultingRequest
     * @return Factory|View|void
     */
    public function myConsultingDetails(ConsultingRequest $consultingRequest)
    {
        $user = Auth::user();
        if ($user->id != $consultingRequest->user_id){
            return abort(404);
        }

        $title = __('activeConsultings.office_consulting');
        if ($consultingRequest->consulting_way == 'phone'){
            $title = __('activeConsultings.office_consulting');
        }
        if ($consultingRequest->consulting_way == 'zoom'){
            $title = __('activeConsultings.zoom_consulting');
        }

        return view($this->view.'my_consulting.show', get_defined_vars());

    }

    /**
     * Consulting evaluate
     * @param ConsultingEvaluateRequest $request
     * @param ConsultingRequest $consultingRequest
     * @return JsonResponse
     */
    public  function consultingEvaluate(ConsultingEvaluateRequest $request, ConsultingRequest $consultingRequest)
    {
        $user = Auth::user();

        if ($user->id != $consultingRequest->user_id){
            return response()->json(['errors' => __('consultingEvaluates.evaluate_not_allowed')]);
        }

        if($consultingRequest->status != 'finished'){
            return response()->json(['errors' => __('consultingEvaluates.consulting_not_finished_yet')]);
        }

        $consultingEvaluateBefore = ConsultingEvaluate::where('consulting_request_id', $consultingRequest->id)->first();

        if ($consultingEvaluateBefore){
            return response()->json(['errors' => __('consultingEvaluates.consulting_evaluated_before')]);
        }

        $data = $request->all();
        $data['consulting_request_id'] = $consultingRequest->id;
        $data['user_id'] = $user->id;
        ConsultingEvaluate::create($data);
        return response()->json(['message' => __('consultingEvaluates.consulting_evaluated_success')]);

    }

    /**
     * Consulting complaint
     * @param ConsultingComplaintRequest $request
     * @param ConsultingRequest $consultingRequest
     * @return JsonResponse
     */
    public  function consultingComplaint(ConsultingComplaintRequest $request, ConsultingRequest $consultingRequest)
    {
        $user = Auth::user();

        if ($user->id != $consultingRequest->user_id){
            return response()->json(['errors' => __('consultingComplaints.complaint_not_allowed')]);
        }

        if($consultingRequest->status != 'finished'){
            return response()->json(['errors' => __('consultingComplaints.consulting_not_finished_yet')]);
        }

        $complaintEvaluateBefore = ConsultingComplaint::where('consulting_request_id', $consultingRequest->id)->first();

        $data = $request->all();
        $data['consulting_request_id'] = $consultingRequest->id;
        $data['user_id'] = $user->id;

        if ($complaintEvaluateBefore){
            $complaintEvaluateBefore->update($data);
            return response()->json(['message' => __('consultingComplaints.consulting_complaint_updated')]);
        }
        ConsultingComplaint::create($data);
        return response()->json(['message' => __('consultingComplaints.consulting_complaint_success')]);
    }


    /**
     * User documentation requests
     * @return Factory|View
     */
    public function myDocumentations()
    {
        $title = __('members.my_documentations');
        $user = Auth::user();
        $documentations = DocumentationRequest::where('user_id', $user->id)
            ->join('documentation_types', 'documentation_types.id', 'documentation_requests.documentation_type_id')
            ->join('documentation_type_descriptions as dtypeDesc', 'documentation_types.id', 'dtypeDesc.documentation_type_id')
            ->where('dtypeDesc.language_id', currentLanguage()->id)
            ->select(['documentation_requests.*', 'dtypeDesc.name as documentationTypeName'])->cursor();
        return view($this->view.'my_documentations.index', get_defined_vars());
    }


    /**
     * User documentation details
     * @param DocumentationRequest $documentationRequest
     * @return Factory|View|void
     */
    public function myDocumentationDetails(DocumentationRequest $documentationRequest)
    {
        $user = Auth::user();
        if ($user->id != $documentationRequest->user_id){
            return abort(404);
        }
        $languageId = currentLanguage()->id;
        $title = __('documentations.documentation_details');
        $documentation = DocumentationRequest::where('documentation_requests.id', $documentationRequest->id)
            ->where('documentation_requests.user_id', $user->id)
            ->join('documentation_types', 'documentation_types.id', 'documentation_requests.documentation_type_id')
            ->join('documentation_type_descriptions as dtypeDesc', 'documentation_types.id', 'dtypeDesc.documentation_type_id')
            ->where('dtypeDesc.language_id', $languageId);

        if ($documentationRequest->city_id){
            $documentation = $documentation->join('cities', 'cities.id', 'documentation_requests.city_id')
                ->join('city_descriptions as cDesc', 'cities.id', 'cDesc.city_id')
                ->where('cDesc.language_id', $languageId)->select([
                    'documentation_requests.*',
                    'cDesc.name as city_name',
                    'dtypeDesc.name as documentationTypeName'
                ])->first();
        } else {
            $documentation = $documentation->select([
                'documentation_requests.*',
                'dtypeDesc.name as documentationTypeName'
            ])->first();
        }
        return view($this->view.'my_documentations.show', get_defined_vars());
    }


    /**
     * User notifications
     * @return Factory|View
     */
    public function notifications()
    {
        $title = __('members.notifications');
        $user = Auth::user();
        $notifications = UsersNotification::orderByDesc('id')
            ->orWhere(function ($query) use ($user){
                $query->whereNull('user_id')
                    ->where('send_to', 'all_user')
                    ->whereJsonDoesntContain('is_read', "$user->id");
            })
            ->orWhere(function ($query) use ($user){
                $query->where('user_id', $user->id)
                    ->whereNull('send_to')
                    ->whereJsonDoesntContain('is_read', "$user->id");
            })->cursor();

        return view($this->view.'notifications.index', get_defined_vars());
    }


    public function makeNotificationAsRead(Request $request, UsersNotification $notification)
    {
        if ($request->ajax()){
            $user = Auth::user();
            $message = __('members.notification_deleted_successfully');
            if ($notification->id){
                if ($notification->user_id && ($notification->user_id != $user->id)){
                    return response()->json(['errors' => __('members.not_allowed_to_delete_notification')]);
                }

                $isRead = $notification->is_read;
                if (in_array($user->id, $isRead)){
                    return response()->json(['errors' => __('members.not_allowed_to_delete_notification')]);
                } else {
                    $isRead[] = "$user->id";
                }
                $notification->update(['is_read' => $isRead]);
            }
            if ($request->make_all_as_read){
                $notifications = UsersNotification::orderByDesc('id')
                    ->orWhere(function ($query) use ($user){
                        $query->whereNull('user_id')
                            ->where('send_to', 'all_user')
                            ->whereJsonDoesntContain('is_read', "$user->id");
                    })
                    ->orWhere(function ($query) use ($user){
                        $query->where('user_id', $user->id)
                            ->whereNull('send_to')
                            ->whereJsonDoesntContain('is_read', "$user->id");
                    })->cursor();

                if (count($notifications)){
                    foreach ($notifications as $notification) {
                        $isRead = $notification->is_read;
                        $isRead[] = "$user->id";
                        $notification->update(['is_read' => $isRead]);
                    }
                }
                $message = __('members.all_notifications_deleted_successfully');
            }

            return response()->json(['message' => $message]);

        }
    }

    /**
     * Show profile update from
     * @return Factory|View
     */
    public function profileForm()
    {
        $title = __('members.my_profile');
        $cities = City::withDescription();
        $user = Auth::user();
        return view($this->view.'profile.profile_form', get_defined_vars());
    }

    /**
     * Show phone change form
     * @return Factory|View
     */
    public function phoneForm()
    {
        $title = __('members.edit_phone');
        $user = Auth::user();
        return view($this->view.'profile.phone_form', get_defined_vars());
    }

    /**
     * Update user profile
     * @param UpdateProfileRequest $request
     * @param User $user
     * @return JsonResponse
     */
    public function updateProfile(UpdateProfileRequest $request, User $user)
    {
        $data = $request->all();
        if ($request->has('photo')){
            if (file_exists(public_path().'/'.$user->photo)){
                File::delete(public_path().'/'.$user->photo);
            }
            $data['photo'] = ImageHelper::upload($request->photo, 'users/profile');
        }

        $user->update($data);
        return response()->json(['url' => route('user.profile'),'message' => __('members.save_successfully')]);
    }

    public function updatePhone(UpdateProfileRequest $request, User $user)
    {
        $generateVerifyCode = $this->generateVerifyCode($user);
        if (($generateVerifyCode['errors'] ?? null)){
            return response()->json($generateVerifyCode);
        }

        session()->put([
            'operation_type' => 'change_phone',
            'user_phone' => $user->phone,
            'new_phone' => $request->phone
        ]);

        return response()->json(['url' => route('user.typeVerifyCode')]);
    }

    /**
     * Show type phone form
     * @return Factory|View
     */
    public function login()
    {
        session()->flash('login', 'yes');
        session()->forget(['operation_type', 'user_phone']);
        $buttonTitle = __('members.login');
        return view($this->view.'register_login', get_defined_vars());
    }

    /**
     * Show type phone form
     * @return Factory|RedirectResponse|View
     */
    public function register()
    {
        session()->flash('login', 'no');
        session()->forget(['operation_type', 'user_phone']);
        $cities = City::withDescription();
        $buttonTitle = __('members.register');
        return view($this->view.'register_login', get_defined_vars());
    }

    /**
     * Submit login
     * @param RegAndLogPhoneRequest $request
     * @return JsonResponse
     */
    public function doRegAndLogin(RegAndLogPhoneRequest $request)
    {
        $operationType = null;
        if (url()->previous() == route('user.login')){
            $user = User::where('phone', $request->phone)->first();

            if (!$user){
                return response()->json(['errors' => __('auth.failed')]);
            }

            /**
             *If user create account and go to login
             * without complete register
             * and without code verification
             */
            if (!$user->email_verified_at){
                session()->put(['operation_type' => 'register', 'user_phone' => $request->phone]);
                return response()->json(['url' => route('user.typeVerifyCode')]);
            }
            if (!$user->agreement){
                session()->put(['operation_type' => 'register', 'user_phone' => $request->phone]);
                return response()->json(['url' => route('user.completeRegister')]);
            }

            $operationType = 'login';
        }
        if (url()->previous() == route('user.register')){
            $date['phone'] = $request->phone;
            $date['role'] = 'user';
            $date['agreement'] = 0;
            $user = User::create($date);
            $operationType = 'register';
        }

        $generateVerifyCode = $this->generateVerifyCode($user);
        if ($generateVerifyCode['errors']){
            return response()->json($generateVerifyCode);
        }

        session()->put(['operation_type' => $operationType, 'user_phone' => $request->phone]);
        return response()->json(['url' => route('user.typeVerifyCode')]);
    }


    /**
     * Show register form
     * @return Factory|View
     */
    public function completeRegister()
    {
        if (session('operation_type') != 'register'){
            return redirect()->route('user.login');
        }

        $user = User::where('phone', session('user_phone'))->first();
        if (!$user->email_verified_at){
            return redirect()->route('user.typeVerifyCode');
        }

        $cities = City::withDescription();
        return view($this->view.'complete_register', get_defined_vars());
    }


    /**
     * Register new user
     * @param RegisterRequest $request
     * @return JsonResponse
     */
    public function doCompleteRegister(RegisterRequest $request)
    {
        if ($request->ajax() && session('operation_type') == 'register'){
            $user = User::where('phone', session('user_phone'))->first();
            if ($user){
                $user->update($request->all());
            } else {
                $user = User::create($request->all());
            }
            Auth::login($user);
            session()->forget(['operation_type', 'user_phone']);
            return response()->json(['url' =>route('user.profile')]);
        }
    }

    /**
     * check attempt try and generate code
     * @param $user
     * @return array
     */
    private function generateVerifyCode($user)
    {
        if ($user->attempt_send_code >= 10 && strtotime($user->last_attempt_date) == strtotime(date('Y-m-d')) ) {
            return ['errors' => __('members.verification_code_exceed')];
        }

        if ($user->last_attempt_date && strtotime($user->last_attempt_date) < strtotime(date('Y-m-d'))){
            $user->update(['code_verify_attempt' => 0, 'attempt_send_code' => 0,'last_attempt_date' => date('Y-m-d')]);
        }

        $attempt_send_code = $user->attempt_send_code + 1;
        $last_attempt_date = date('Y-m-d');
        $code = rand(1000,9999);

        session()->put(['verify_code' => $code]);

//        try{
//            Sms::send($user->phone, "Verification code is: {$code}");
//        } catch (Exception $exception){
//            return ['errors' => 'Sms send code error'];
//        }
//        $data = [
//            'user' => $user->name,
//            'email' => $user->email,
//            'code' => $code,
//        ];

//        CodeVerificationJob::dispatch($data, 'web.members.emails.verification_email');
        $user->update(
            [
                'verify_code' => $code,
                'attempt_send_code' => $attempt_send_code,
                'last_attempt_date' => $last_attempt_date,
            ]
        );

        return ['errors' => false];
    }

    /**
     * Show type verify code form
     * @return Factory|JsonResponse|View
     */
    public function typeVerifyCode()
    {
        if (!session('user_phone')){
            return redirect()->route('user.login')->with('errors',  'There\'s no code generated');
        }

        return view($this->view.'type_verify_code');
    }

    /**
     * Check verify code attempt and if it's correct or not
     * @param Request $request
     * @return array|JsonResponse
     */
    public function verifyCode(Request $request)
    {
        $code = implode('',  array_reverse($request->code));
        if (mb_strlen($code) < 4){
            return response()->json(['errors' => __('members.enter_full_code')]);
        }

        $user = User::where('phone', session('user_phone'))->first();
//            ->where('verify_code', $code)->first();

        if (!$user){
            return response()->json(['errors' => __('members.no_user_with_data')]);
        }

        // Check the number of attempts to check the code
        if ($user->code_verify_attempt >= 6 && strtotime($user->last_attempt_date) == strtotime(date('Y-m-d')) ) {
            return response()->json(['errors' => __('members.verification_tries_exceed')]);
        }

        // Check if date less then today
        if ($user->last_attempt_date && strtotime($user->last_attempt_date) < strtotime(date('Y-m-d'))){
            $user->update(['code_verify_attempt' => 0, 'last_attempt_date' => date('Y-m-d')]);
        }

        // The user entered the wrong code and the number of attempts increased
        if (strtotime($user->last_attempt_date) == strtotime(date('Y-m-d')) && $user->verify_code != $code){
            $user->update(['code_verify_attempt' => $user->code_verify_attempt+1]);
            return response()->json(['errors' => __('members.invalid_verification_code')]);
        }

        if (session('operation_type') == 'login'){
            Auth::login($user);
            session()->forget(['operation_type', 'user_phone']);
            return response()->json([
                'url' => route('user.profile'),
                'message' => __('members.correct_code')]);
        }
        if (session('operation_type') == 'register'){
            $user->update(['email_verified_at' => date('Y-m-d')]);
            return response()->json([
                'url' => route('user.completeRegister'),
                'message' => __('members.correct_code')
            ]);
        }
        if (session('operation_type') == 'change_phone'){
            $user->update(['phone' => session('new_phone')]);
            session()->forget(['operation_type', 'user_phone', 'new_phone']);
            return response()->json([
                'url' => route('user.profile'),
                'message' => __('members.phone_changed_successfully')
            ]);
        }
    }

    /**
     * Resend code for register and login
     * @return JsonResponse
     */
    public function resendCode()
    {
        if (request()->ajax()){
            $user = User::where('phone', session('user_phone'))->first();
            $generateVerifyCode = $this->generateVerifyCode($user);
            if ($generateVerifyCode['errors']){
                return response()->json($generateVerifyCode);
            }

            return response()->json(['success' => true]);
        }
    }

    public function logout()
    {
        Auth::logout();
        return redirect()->route('home');
    }


}
