<?php

namespace App\Libraries;

use App\Models\Patient;
use App\Rules\AlphaSpace;
use App\Rules\ArabicAlphaSpace;
use App\Rules\GeneralText;
use App\Rules\Mobile;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\Rule;
use Illuminate\Support\Facades\Validator;

class PatientCommon
{

    private $response;

    public function __construct()
    {
        $this->response = '';
    }

    public function getResponse()
    {
        return $this->response;
    }
    //-------------------------------------------------------
    /**
     * Patient Login
     *
     * @param Request $request
     * @param boolean $is_api_request
     * @return void
     */
    public function login(Request $request, bool $is_api_request = false)
    {
        // validate the form

        $rules = [
            'mobile' => ['required', new Mobile],
            'password' => ['required'],
        ];

        if ($is_api_request) {

            $validator = Validator::make($request->all(), $rules);

            if ($validator->fails()) {

                $this->response = response()->json(['error' => $validator->errors()], 400);

                return false;
            }
        } else {

            $validated = $request->validate($rules);
        }


        // Validate credentials

        $patient_info = Patient::where('mobile', $request->input('mobile'))->first();

        if ($patient_info && Hash::check($request->input('password'), $patient_info['password'])) {

            // if user is blocked
            if ($patient_info->is_blocked) {

                if ($is_api_request) {
                    $this->response = response()->json(['error' => __('patient/login.error.blocked')], 400);
                } else {
                    session()->flash('error', __('patient/login.error.blocked'));
                }

                return false;
            }

            // Success

            $info = [
                'patient_id' => $patient_info->id,
                'name'       => $patient_info->first_name,
            ];

            if ($is_api_request) {

                // if patient has tokens, delete them and generate new one
                $has_tokens = ($patient_info->tokens->count()) ? true : false;

                if ($has_tokens) {

                    $patient_info->tokens()->delete();
                }

                $token = $patient_info->createToken('api_token')->plainTextToken;

                $info['token'] = $token;

                $this->response = response()->json(['patient_info' => $info], 201);
            } else {

                session()->put('patient_info', $info);
            }

            return true;
        } else {

            if ($is_api_request) {

                $this->response = response()->json(['error' => __('patient/login.error.invalid')], 400);
            } else {

                session()->flash('error', __('patient/login.error.invalid'));
            }

            return false;
        }
    }
    //-------------------------------------------------------
    /**
     * Add new patient
     *
     * @param Request $request
     * @param boolean $self_registered
     * @return void
     */
    public function register(Request $request, bool $self_registered = false, bool $is_api_request = false, bool $do_register = true)
    {

        $this->response = '';

        $min_dob = date('Y-m-d', strtotime("-90 years"));
        $max_dob = date('Y-m-d');

        // set the rules
        $rules = [
            'first-name' => ['required', 'min:3', 'max:50', new ArabicAlphaSpace],
            'second-name' => ['nullable', 'min:3', 'max:50', new ArabicAlphaSpace],
            'third-name' => ['nullable', 'min:3', 'max:50', new ArabicAlphaSpace],
            'last-name' => ['required', 'min:3', 'max:50', new ArabicAlphaSpace],
            'dob' => ['required', 'date_format:Y-m-d', 'before_or_equal:' . $max_dob, 'after_or_equal:' . $min_dob],
            'gender' => ['required',  Rule::in(['m', 'f'])],
            'region' => ['required', 'integer', 'exists:regions,id'],
            'address' => ['nullable', 'max:250', new GeneralText],
            'email' => ['nullable', 'email', 'unique:patients,email'],
            'password' => ['required', 'min:6', 'max:20'],
            //'cpassword' => ['required', 'same:password'],
            'mobile' => ['required', 'unique:patients,mobile', new Mobile],
            'comment' => ['nullable', 'max:500', new GeneralText],
        ];

        if ($is_api_request) {

            $validator = Validator::make($request->all(), $rules);

            if ($validator->fails()) {

                $this->response = response()->json(['error' => $validator->errors()], 400);

                return false;
            }
        } else {

            $validated = $request->validate($rules);
        }

        if ($do_register) {

            // Setting the db insert array 
            $patient = [
                'first_name' => $request->input('first-name'),
                'second_name' => $request->input('second-name'),
                'third_name' => $request->input('third-name'),
                'last_name' => $request->input('last-name'),
                'dob' => date('Y-m-d', strtotime($request->input('dob'))),
                'gender' => $request->input('gender'),
                'email' => $request->input('email'),
                'mobile' => $request->input('mobile'),
                'region_id' => $request->input('region'),
                'address' => $request->input('address'),
                'password' => Hash::make($request->input('password')),
                'comment' => $request->input('comment'),
            ];

            // for patients added by admin users when using verification code
            if (!$self_registered && !$is_api_request) {
                $patient['is_verified'] = 1;
            } else {
                $patient['is_verified'] = 0;
            }


            if (array_key_exists('blocked', $request->all())) {
                $patient['is_blocked'] = true;
            }

            $new_patient = Patient::create($patient);

            $patient_info = [
                'patient_id' => $new_patient->id,
                'name'       => $new_patient->first_name . ' ' . $new_patient->last_name,
            ];

            // if patient is sel-registered and using api (mobile)
            if ($self_registered && $is_api_request) {

                $token = $new_patient->createToken('api_token')->plainTextToken;

                $patient_info['token'] = $token;
            }

            if ($is_api_request) {

                $this->response = response()->json(['patient_info' => $patient_info], 200);
            } else {

                //session()->put('patient_info', $patient_info);
            }
        }

        return true;
    }

    /**
     * Patient Profile Update
     *
     * @param Request $request
     * @param Patient $patient
     * @param boolean $self_registered
     * @param boolean $is_api_request
     * @return void
     */
    public function updateProfile(Request $request, Patient $patient, bool $self_registered = false, bool $is_api_request = false, bool $do_update = true)
    {

        $this->response = '';

        $min_dob = date('Y-m-d', strtotime("-90 years"));
        $max_dob = date('Y-m-d');

        $rules = [
            'first-name' => ['required', 'min:3', 'max:50', new AlphaSpace],
            'second-name' => ['nullable', 'min:3', 'max:50', new AlphaSpace],
            'third-name' => ['nullable', 'min:3', 'max:50', new AlphaSpace],
            'last-name' => ['required', 'min:3', 'max:50', new AlphaSpace],
            'dob' => ['required', 'date_format:Y-m-d', 'before_or_equal:' . $max_dob, 'after_or_equal:' . $min_dob],
            'gender' => ['required',  Rule::in(['m', 'f'])],
            'region' => ['required', 'integer', 'exists:regions,id'],
            'address' => ['nullable', 'max:250', new GeneralText],
            'email' => ['nullable', 'email', Rule::unique('patients', 'email')->ignore($patient->id)],
            'password' => ['nullable', 'string', 'min:6', 'max:20'],
            //'cpassword' => ['same:password'],
            'mobile' => ['required', Rule::unique('patients', 'mobile')->ignore($patient->id), new Mobile],
            'comment' => ['nullable', 'max:500', new GeneralText],
        ];



        if ($is_api_request) {

            $validator = Validator::make($request->all(), $rules);

            if ($validator->fails()) {

                $this->response = response()->json(['error' => $validator->errors()], 400);

                return false;
            }
        } else {
            $validated = $request->validate($rules);
        }

        if ($do_update) {

            $patient_info = [
                'first_name' => $request->input('first-name'),
                'second_name' => $request->input('second-name'),
                'third_name' => $request->input('third-name'),
                'last_name' => $request->input('last-name'),
                'dob' => date('Y-m-d', strtotime($request->input('dob'))),
                'gender' => $request->input('gender'),
                'email' => $request->input('email'),
                'mobile' => $request->input('mobile'),
                'region_id' => $request->input('region'),
                'address' => $request->input('address'),
                //'password' => Hash::make($request->input('password')),
                'comment' => $request->input('comment'),
            ];

            if (!empty(trim($request->input('password')))) {
                $patient_info['password'] = Hash::make($request->input('password'));
            }

            if (array_key_exists('blocked', $request->all())) {
                $patient_info['is_blocked'] = true;

                // if blocked => delete token

                $patient->tokens()->delete();
            } else {
                $patient_info['is_blocked'] = false;
            }

            Patient::where('id', $patient->id)->update($patient_info);

            $updated_patient = Patient::findOrFail($patient->id);

            $patient_info = [
                'patient_id' => $updated_patient->id,
                'name'       => $updated_patient->first_name . ' ' . $updated_patient->last_name,
            ];

            // if patient is sel-registered and uisn api (mobile)
            if ($self_registered && $is_api_request) {

                $token = $updated_patient->createToken('api_token')->plainTextToken;

                $patient_info['token'] = $token;

                $this->response = response()->json(['patient_info' => $patient_info], 201);
            } elseif ($self_registered && !$is_api_request) {

                // If patient is sel-registered => set the login details

                if (session()->has('patient_info')) {

                    session()->pull('patient_info');

                    session()->put('patient_info', $patient_info);
                } else {

                    session()->put('patient_info', $patient_info);
                }
            }
        }

        return true;
    }

    public function genOtpCode($length = 6)
    {

        $n = $length;
        // Take a generator string which consist of
        // all numeric digits
        $generator = "1357902468";

        // Iterate for n-times and pick a single character
        // from generator and append it to $result

        // Login for generating a random character from generator
        //     ---generate a random number
        //     ---take modulus of same with length of generator (say i)
        //     ---append the character at place (i) from generator to result

        $code = "";

        for ($i = 1; $i <= $n; $i++) {
            $code .= substr($generator, (rand() % (strlen($generator))), 1);
        }

        // Return result
        return $code;
    }

    /**
     * Save otp code in patient_otp table
     *
     * @param string $patient_mobile
     * @param int $code
     * @return void
     */
    public function saveOtpCode($patient_mobile, $code)
    {

        // check if patient mobile exists in password_reset table
        $count = DB::table('patient_otp')->where('mobile', $patient_mobile)->count();

        // if mobile doesn't exist => add new
        if ($count == 0) {

            DB::table('patient_otp')->insert([
                'mobile' => $patient_mobile,
                'code' => Hash::make($code),
                'created_at' => now()
            ]);
        } else {

            DB::table('patient_otp')->where('mobile', $patient_mobile)->update([
                'code' => Hash::make($code),
                'updated_at' => now()
            ]);
        }
    }
}
