<?php

namespace App\Core\Service;

use App\Core\Repository\User\UserRepository;
use Illuminate\Http\Request;

use App;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Config;
use Exception;
use App\Exceptions\ApiErrorException;
use App\Core\Validator\User\UserCreateValidator;
use App\Core\Validator\User\UserNewPasswordValidator;
use App\Core\Validator\User\ChangePasswordValidator;
use App\Core\Validator\User\ResetPasswordValidator;
use Illuminate\Support\Str;
use App\Core\Validator\User\UserProfileUpdateValidator;

class UserService
{

    private  $request ;
    private  $userRepository ;
    private  $userCreateValidator ;
    private  $userNewPasswordValidator;
    private  $changePasswordValidator;
    private $resetPasswordValidator ;
    private $profileUpdateValidator;

    public function __construct
    (
        Request $request,
        ResetPasswordValidator $resetPasswordValidator,
        UserRepository $userRepository,
        UserNewPasswordValidator $userNewPasswordValidator,
        ChangePasswordValidator $changePasswordValidator,
        UserCreateValidator $userCreateValidator,
        UserProfileUpdateValidator $profileUpdateValidator
    )
    {
        $this->request = $request;
        $this->userRepository = $userRepository;
        $this->userCreateValidator = $userCreateValidator;
        $this->userNewPasswordValidator = $userNewPasswordValidator;
        $this->changePasswordValidator = $changePasswordValidator;
        $this->resetPasswordValidator = $resetPasswordValidator;
        $this->profileUpdateValidator = $profileUpdateValidator;
    }

    /*
     *
    select
    create
    update
    delete

     * */

    public function select($param = [], $column = ['*'])
    {

        $response = ['status' => -1, 'message' => '', 'data' => null];

        try {

           $data = $this->userRepository->findByCriteria($param, $column);
           if(!$data){
               throw new ApiErrorException(lang('An unknown error occurred'));
           }

            $response['status'] = 1;
            $response['data'] = $data;


        } catch (ApiErrorException $e) {
            $response['status'] = 0;
            $response['message'] = implode(', ', $e->getMessageArr());
        } catch (Exception $e) {
            $message = $e->getFile() . " " . $e->getLine() . " " . $e->getMessage();
            Log::error($message);
            $response['message'] = $e->getMessage();
        }

        return output($response);
    }

    public function create($param = [])
    {
        $response = ['status' => -1, 'message' => '', 'data' => null];
        try {

            // Todo add permission
            $userData =
                [
                    "gender" => fillOnUndefined($param, "gender"),
                    "name" => fillOnUndefined($param, "name"),
                    "surname" => fillOnUndefined($param, "surname"),
                    "phone" => fillOnUndefined($param, "phone"),
                    "language" => fillOnUndefined($param, "language"),
                    "email" => fillOnUndefined($param, "email"),
                    "password" => Str::random(6),
                    "hash_key" => hash('sha512', Str::random(32) ),
                    "status" => fillOnUndefined($param, "status", 0),
                    "created_by" => fillOnUndefined($param, "user_id", 1),
                    "updated_by" => fillOnUndefined($param, "user_id", 1),
                    "created_at" => time(),
                    "updated_at" => time(),
                ];

            $validationResult = $this->userCreateValidator->validate($userData);
            if ($validationResult->errors()->first()) {
                $errors = $validationResult->errors()->all();
                throw new ApiErrorException($errors);
            }

            $userPassword = $userData['password'] ;
            $userData['password'] = Hash::make($userData['password']) ;
            $userCreateResult = $this->userRepository->create($userData);

            if ($userCreateResult['status'] != 'success') {
                throw new Exception('api-unknown_error');
            }
            $response['status'] = 1;
            $userCreateResult["data"]["userPassword"] = $userPassword;
            $response['data'] = $userCreateResult["data"];

        } catch (ApiErrorException $e) {
            $response['status'] = 0;
            $response['message'] = implode(', ', $e->getMessageArr());
        } catch (Exception $e) {
            $message = $e->getFile() . " " . $e->getLine() . " " . $e->getMessage();
            Log::error($message);
            $response['message'] = $e->getMessage();
        }

        return output($response);
    }

    public function update($param = [])
    {
        $response = ['status' => -1, 'message' => '', 'data' => null ];

        try {

            // Todo add permission
            $userUpdateData = fillOnUndefined($param, 'user_update_data', []) ;
            $validateKeys = ['name', 'surname', 'gender', 'phone', 'password', 'status'];
            $updateData = [] ;
            foreach ($userUpdateData as $key => $value){
                if(!in_array($key,$validateKeys)){
                    throw new ApiErrorException(lang('Disallowed field'));
                }
                $updateData[$key] = $value ;
                if($key == 'password'){
                    $updateData['password'] = Hash::make($value) ;
                }
            }
            if($updateData){
                $updateData['updated_by'] = $param['user_id'] ;
            }

            $userUpdateResult = $this->userRepository->update($param['update_user_id'], $updateData);
            if ($userUpdateResult['status'] != 'success') {
                throw new Exception('api-unknown_error');
            }

            $response['status'] = 1;
            $response['data'] = $userUpdateResult["data"];


        } catch (ApiErrorException $e) {
            $response['status'] = 0;
            $response['message'] = implode(', ', $e->getMessageArr());
        } catch (Exception $e) {
            $message = $e->getFile() . " " . $e->getLine() . " " . $e->getMessage();
            Log::error($message);
            $response['message'] = $e->getMessage();
        }

        return output($response);
    }

    private function _updateUserProfile($id, $param = [])
    {
        $response = ['status' => -1, 'message' => '', 'data' => null];
        try {
            $updateResult = $this->userRepository->update($id, $param);
            if ($updateResult['status'] != 'success') {
                throw new Exception('api-unknown_error');
            }
            $updateData = $updateResult["data"];
            $response = [
                'status' => true,
                'data' => $updateData,
            ];

        } catch (ApiErrorException $e) {
            $response['message'] = implode(', ', $e->getMessageArr());
        } catch (Exception $e) {
            $message = $e->getFile() . " " . $e->getLine() . " " . $e->getMessage();
            Log::error($message);
            $response['message'] = $e->getMessage();
        }

        return output($response);
    }

    public function forgotPassword($params = [])
    {
        $response = ['status' => -1, 'message' => '', 'data' => null ];

        try {

            $userCriteria = [
                'criteria' => [
                    ['field' => 'email', 'condition' => '=', 'value' => $params['email']],
                ],
                'firstRow' => 1
            ];
            $findUser = $this->select($userCriteria);
            if (!$findUser['status'] || !$findUser['data']) {
                throw new ApiErrorException(lang('User not found'));
            }
            $findUser = $findUser['data'] ;
            $hashKey = hash('sha512', Str::random(32) );
            $updateParams = [
                'hash_key' => $hashKey,
                'updated_by' => $findUser['id'],
                'updated_at' => time()
            ];
            $userUpdateResult = $this->userRepository->update($findUser['id'], $updateParams);
            if ($userUpdateResult['status'] != 'success') {
                throw new Exception('api-unknown_error');
            }
            $userData = $userUpdateResult["data"];
            $response = [
                'status' => 1,
                'data' => $userData,
            ];


        } catch (ApiErrorException $e) {
            $response['status'] = 0;
            $response['message'] = implode(', ', $e->getMessageArr());
        } catch (Exception $e) {
            $message = $e->getFile() . " " . $e->getLine() . " " . $e->getMessage();
            Log::error($message);
            $response['message'] = $e->getMessage();
        }

        return output($response);
    }

    public function resetPassword($params = [])
    {
        $response = ['status' => -1, 'message' => '', 'data' => null];

        try {

            $validationResult = $this->resetPasswordValidator->validate($params);
            if ($validationResult->errors()->first()) {
                $errors = $validationResult->errors()->all();
                throw new ApiErrorException($errors);
            }

            $userCriteria = [
                'criteria' => [
                    ['field' => 'email', 'condition' => '=', 'value' => $params['email']],
                    ['field' => 'hash_key', 'condition' => '=', 'value' => $params['hash_key']],
                ],
                'firstRow' => 1
            ];
            $findUser = $this->select($userCriteria);
            if (!$findUser['status'] || !$findUser['data']) {
                throw new ApiErrorException(lang('User not found'));
            }

            $findUser = $findUser['data'] ;
            $hashKey = hash('sha512', Str::random(32) );
            $updateParams = [
                'hash_key' => $hashKey,
                'password' => Hash::make($params['password']),
                'updated_by' => $findUser['id'],
                'updated_at' => time()
            ];
            $userUpdateResult = $this->userRepository->update($findUser['id'], $updateParams);
            if ($userUpdateResult['status'] != 'success') {
                throw new Exception('api-unknown_error');
            }
            $response['status'] = 1;
            $response['data'] = $userUpdateResult["data"];


        } catch (ApiErrorException $e) {
            $response['status'] = 0;
            $response['message'] = implode(', ', $e->getMessageArr());
        } catch (Exception $e) {
            $message = $e->getFile() . " " . $e->getLine() . " " . $e->getMessage();
            Log::error($message);
            $response['message'] = $e->getMessage();
        }

        return output($response);
    }

    public function findUser($id)
    {
        return $this->userRepository->find($id);
    }

    public function checkUserKey($params){

        $response = ['status' => -1, 'message' => '', 'data' => null];
        try{
            $userCriteria = [
              'criteria' => [
                  ['field' => 'email' , 'condition' => '=' , 'value' => $params['email'] ],
                  ['field' => 'hash_key' , 'condition' => '=' , 'value' => $params['key'] ],
              ],
                'firstRow' => true,
            ];

            $userData = $this->userRepository->findByCriteria($userCriteria, ['id', 'name', 'surname', 'email', 'hash_key', 'status']) ;
            if(!$userData){
                throw new ApiErrorException(lang('User not found')) ;
            }
            if($userData['status'] == 1){
                throw new ApiErrorException(lang('This user already activated'));
            }

            $response['status'] = 1;
            $response['data'] = $userData;

        }catch (ApiErrorException $e) {
            $response['status'] = 0;
            $response['message'] = implode(', ', $e->getMessageArr());
        }catch (Exception $e) {
            $message = $e->getFile() . " " . $e->getLine() . " " . $e->getMessage();
            Log::error($message);
            $response['message'] = $e->getMessage();
        }

        return output($response);
    }

    public function newPassword($params){

        $response = ['status' => -1, 'message' => '', 'data' => null ];
        try{

            $userData = [
                'email' => fillOnUndefined($params, 'email'),
                'hash_key' => fillOnUndefined($params, 'hash_key'),
                'password' => fillOnUndefined($params, 'password'),
                'password_confirmation' => fillOnUndefined($params, 'password_confirmation'),
            ];

            $validationResult = $this->userNewPasswordValidator->validate($userData);
            if ($validationResult->errors()->first()) {
                $errors = $validationResult->errors()->all();
                throw new ApiErrorException($errors);
            }


            $userUpdateData = [
                'password' => Hash::make($userData['password']) ,
                'status' => 1 ,
                'updated_by' => $params['user_id'],
                'updated_at' => time()
            ];

            $userData = $this->userRepository->update($params['user_id'], $userUpdateData) ;

            if(!$userData){
                throw new Exception('api-unknown_error');
            }

            $response['status'] = 1;
            $response['data'] = $userData;


        } catch (ApiErrorException $e) {
            $response['status'] = 0;
            $response['message'] = implode(', ', $e->getMessageArr());
        }catch (Exception $e) {
            $message = $e->getFile() . " " . $e->getLine() . " " . $e->getMessage();
            Log::error($message);
            $response['message'] = $e->getMessage();
        }

        return output($response);
    }

    public function changePassword($params){

        $response = ['status' => -1, 'message' => '', 'data' => null ];
        try{

            $userData = [
                'user_id' => fillOnUndefined($params, 'user_id'),
                'old_password' => fillOnUndefined($params, 'old_password'),
                'password' => fillOnUndefined($params, 'password'),
                'password_confirmation' => fillOnUndefined($params, 'password_confirmation'),
            ];

            $validationResult = $this->changePasswordValidator->validate($userData);

            if ($validationResult->errors()->first()) {
                $errors = $validationResult->errors()->all();
                throw new ApiErrorException($errors);
            }

            $userUpdateData = [
                'password' => Hash::make($userData['password']) ,
                'updated_by' => $params['user_id'],
                'updated_at' => time()
            ];

            $userData = $this->userRepository->update($userData['user_id'], $userUpdateData) ;

            if(!$userData){
                throw new Exception('api-unknown_error');
            }

            $response['status'] = 1;
            $response['data'] = $userData;


        } catch (ApiErrorException $e) {
            $response['status'] = 0;
            $response['message'] = implode(', ', $e->getMessageArr());

        }catch (Exception $e) {
            $message = $e->getFile() . " " . $e->getLine() . " " . $e->getMessage();
            Log::error($message);
            $response['message'] = $e->getMessage();
        }

        return output($response);
    }

    public function getProfile($params, $fields = ['*']){

        $response = ['status' => false, 'message' => '', 'data' => null, 'statusCode' => 500];
        try {

            $profileRequest = [
                'criteria' => [
                    ['field' => 'id', 'condition' => '=', 'value' => $params['user_id']],
                    ['field' => 'status', 'condition' => '=', 'value' => $params['status']],
                ],
                'firstRow' => true
            ];

            $profileData = $this->select($profileRequest, $fields);

            $response = ['status' => 1, 'statusCode' => 200, 'message' => null, 'data' => $profileData['data'] ];

        } catch (ApiErrorException $e) {
            $response['message'] = implode(', ', $e->getMessageArr());
            $response['statusCode'] = 400;
        } catch (Exception $e) {
            $message = $e->getFile() . " " . $e->getLine() . " " . $e->getMessage();
            Log::error($message);
            $response['message'] = $e->getMessage();
            $response['statusCode'] = 500;
        }

        return output($response);
    }

    public function profileUpdate($params = []){

        $response = ['status' => -1, 'message' => '', 'data' => null];
        try {

            $validationResult = $this->profileUpdateValidator->validate($params);

            if ($validationResult->errors()->first()) {
                $errors = $validationResult->errors()->all();
                throw new ApiErrorException($errors);
            }

            $updateData =
                [
                    'name' => fillOnUndefined($params, 'name'),
                    'surname' => fillOnUndefined($params, 'surname'),
                    'gender' => fillOnUndefined($params, 'gender'),
                    'language' => fillOnUndefined($params, 'language'),
                    'phone' => fillOnUndefined($params, 'phone'),
                    "updated_by" => fillOnUndefined($params, "user_id"),
                    "updated_at" => time()
                ];

            $updateResult = $this->_updateUserProfile($params['user_id'], $updateData);
            if ($updateResult['status'] != 'success') {
                throw new ApiErrorException($updateResult['message']);
            }
            $userData = $updateResult["data"];
            $response = [
                'status' => true,
                'data' => $userData,
            ];

        } catch (ApiErrorException $e) {
            $response['message'] = implode(', ', $e->getMessageArr());
        } catch (Exception $e) {
            $message = $e->getFile() . " " . $e->getLine() . " " . $e->getMessage();
            Log::error($message);
            $response['message'] = $e->getMessage();
        }

        return output($response);
    }

}
