<?php

namespace App\Http\Controllers;

use App\Core\Service\ApiAccessTokenService;
use App\Core\Service\UserPropertyMappingService;
use App\Exceptions\ApiErrorException;
use Illuminate\Support\Facades\Auth;
use App\Core\Validator\User\UserLoginValidator;
use App\Models\User;
use App\Core\Service\JwtService;
use Illuminate\Http\Request;
use Firebase\JWT\ExpiredException;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Hash;
use Firebase\JWT\JWT;
use Illuminate\Support\Facades\Config;
use App\Core\Service\PermissionService;

use Illuminate\Support\Facades\Log;
use Laravel\Lumen\Routing\Controller as BaseController;

class AuthController extends BaseController
{

    private $request;
    private $apiAccessTokenService;
    private $jwtService;
    private $userLoginValidator;
    private $userPropertyMappingService;
    private $permissionService;


    public function __construct(
        Request $request,
        UserPropertyMappingService $userPropertyMappingService,
        UserLoginValidator $userLoginValidator,
        PermissionService $permissionService,
        ApiAccessTokenService $apiAccessTokenService,
        JwtService $jwtService

    )
    {
        $this->request = $request;
        $this->userLoginValidator = $userLoginValidator;
        $this->jwtService = $jwtService;
        $this->userPropertyMappingService = $userPropertyMappingService;
        $this->permissionService = $permissionService;
        $this->apiAccessTokenService = $apiAccessTokenService;
    }

    public function authenticate(User $user)
    {

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

            $return = [];

            $validationData = [
                'email' => $this->request->input('email'),
                'password' => $this->request->input('password')
            ];

            $locale = $this->request->input('locale');
            $rememberMe = $this->request->input('remember_me') ;

            $validationResult = $this->userLoginValidator->validate($validationData);
            if ($validationResult->errors()->first()) {
                $errors = $validationResult->errors()->all();
                throw new ApiErrorException($errors);
            }
            $user = User::where('email', $this->request->input('email'))->where('status', 1)->first();
            if (!$user) {
                throw new ApiErrorException(lang('Email or password is wrong.'));
            }

            if (Hash::check($this->request->input('password'), $user->password)) {
                $jwtToken = $this->jwtService->jwtCreate(['user_id' => $user['id'], 'remember_me' => $rememberMe, 'day_counter' => 5]);
                if ($jwtToken['status'] != 'success') {
                    throw new ApiErrorException(lang('An unknown error occurred.'));
                }

                $jwtToken = $jwtToken['data'];

                $return = [
                    'token' => $jwtToken['token']
                ];
            } else {
                throw new ApiErrorException(lang('Email or password is wrong.'));
            }

            $saveToken = [
                "token" => md5(fillOnUndefined($jwtToken, "token")),
                "expire_date" => fillOnUndefined($jwtToken, "exp"),
                "user_id" => fillOnUndefined($user, "id"),
                "invalidate" => fillOnUndefined($jwtToken, "invalidate", 0),
            ];

            $saveTokenTo = $this->apiAccessTokenService->create($saveToken);
            if ($saveTokenTo['status'] != 'success') {

                throw new ApiErrorException(lang('General error'));

            }

            $return = [
                'token' => $jwtToken['token'],
                'expire_time' => $saveTokenTo['data']['expire_time'],
                'locale' => $user['locale']
            ];

            $onesignalKey = $this->request->input('onesignal_key');

            if(isset($onesignalKey) && $onesignalKey){
                if(strlen($onesignalKey) > 36){
                    throw new ApiErrorException(lang('Onesignal Key Size error'));
                }
                $userUpdateStatus = User::where('id', $user['id'])->where('status', 1)
                    ->update(['onesignal_key' => $onesignalKey]);

                if ($userUpdateStatus !== 1) {
                    throw new ApiErrorException(lang('Onesignal Key Update Error'));
                }
            }

            $mappingPropertiesCriteria = [
                'criteria' => [
                    ['field' => 'user_id', 'condition' => '=', 'value' => $user['id']],
                    ['field' => 'status', 'condition' => '=', 'value' => 1],

                ],
                'with' => ['property.defaultPropertyPhoto'],
            ];

            $mappingProperties = $this->userPropertyMappingService->select($mappingPropertiesCriteria);
            if (!$mappingProperties['data']) {
                throw new ApiErrorException(lang('User Property mapping not found'));
            }
            $propertyList = collect($mappingProperties['data'])->map(function ($value) use ($user, $locale) {
                $menuParams = [
                    'user_id' => $user['id'],
                    'property_id' => $value['property']['id'],
                    'status' => $value['property']['status'],
                    'locale' => $locale
                ] ;
                if (is_array($value['property'])) {
                    $defaultPhoto = isset($value['property']['default_property_photo']) ? $value['property']['default_property_photo'] : null ;

                    $photoUrlThumbFilePath = '/assets/img/placeholder.png';
                    if(isset($defaultPhoto['photo_name'])){
                        $photoUrlThumbFilePath = Config::get('app.fileSystemDriver') . "/property-photos/{$value['property']['id']}" . "/{$defaultPhoto['photo_name']}_200x200.{$defaultPhoto['file_ext']}";

                        if (File::exists($photoUrlThumbFilePath)) {
                            $photoUrlThumbFilePath = Config::get('app.imageUrl') . "/property-photos/{$value['property']['id']}" . "/{$defaultPhoto['photo_name']}_200x200.{$defaultPhoto['file_ext']}";
                        }else {
                            $photoUrlThumbFilePath = Config::get('app.imageUrl') . "/property-photos/{$value['property']['id']}" . "/{$defaultPhoto['photo_name']}_thumbnail.{$defaultPhoto['file_ext']}";
                        }
                    }
                    return $value['property'] = [
                        'id' => $value['property']['id'],
                        'name' => $value['property']['name'],
                        'status' => $value['property']['status'],
                        'default_photo' =>  $photoUrlThumbFilePath ,
                         // 'property_menu' => $this->permissionService->getMenuTreeForUser($menuParams)
                    ];
                }
            })->where('status' , '=', 1);

            $propertyList = $propertyList->map(function ($value) {
                return [

                    'id' => $value['id'],
                    'name' => $value['name'],
                    'default_photo' => $value['default_photo'],
                ];
            })->toArray();
            $return['property_list'] = $propertyList;

            $return['user'] = [
                'name' => $user['name'],
                'surname' => $user['surname'],
                'language' => $user['language']
            ];


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

        } 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 apiResponse($response['status'], $response['message'], $response['data'], $response['statusCode']);

    }

    public function refreshToken(Request $request)
    {

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

            $token = $request->header('authToken');
            $credentials = JWT::decode($token, Config::get('app.jwt.secret'), ['HS256']);
            $rememberMe = $credentials->remember_me ;
            $userId =  $request->credentials->user_id;

            $findTokenCriteria = [
                'criteria' => [
                    ['field' => 'token', 'condition' => '=', 'value' => md5($token) ],
                    ['field' => 'expire_date', 'condition' => '>', 'value' => time() ],
                    ['field' => 'user_id', 'condition' => '=', 'value' => $userId ],
                    ['field' => 'invalidate', 'condition' => '=', 'value' => 0 ],
                ],
                'firstRow' => 1
            ];
            $getTokenData = $this->apiAccessTokenService->select($findTokenCriteria);

            if(!$getTokenData['data']){
                throw new ApiErrorException(lang('Token data not found'));
            }
            $getTokenData = $getTokenData['data'];
            $jwtToken = $this->jwtService->jwtCreate(['user_id' => $userId, 'remember_me' => $rememberMe, 'day_counter' => 0.5]);
            if ($jwtToken['status'] != 'success') {
                throw new ApiErrorException(lang('An unknown error occurred.'));
            }
            $jwtToken = $jwtToken['data'];

            $updateToken = [
                "token" => md5(fillOnUndefined($jwtToken, "token")),
                "expire_date" => fillOnUndefined($jwtToken, "exp"),
                "updated_at" => time(),
            ];


            $updateTokenTo = $this->apiAccessTokenService->update($getTokenData['id'], $updateToken);
            if ($updateTokenTo['status'] != 'success') {
                throw new ApiErrorException(lang('General error'));
            }

            $return = [
                'token' => $jwtToken['token'],
                'expire_time' => $updateTokenTo['data']['expire_time']
            ];

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

        } 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 apiResponse($response['status'], $response['message'], $response['data'], $response['statusCode']);


    }

    public function logOut(Request $request)
    {

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

            $token = $request->header('authToken');
            $userId =  $request->credentials->user_id;

            $findTokenCriteria = [
                'criteria' => [
                    ['field' => 'token', 'condition' => '=', 'value' => md5($token)],
                    ['field' => 'expire_date', 'condition' => '>', 'value' => time()],
                    ['field' => 'user_id', 'condition' => '=', 'value' => $userId],
                    ['field' => 'invalidate', 'condition' => '=', 'value' => 0 ],
                ],
                'firstRow' => 1
            ];
            $getTokenData = $this->apiAccessTokenService->select($findTokenCriteria);

            if(!$getTokenData['data']){
                throw new ApiErrorException(lang('Token data not found.'));
            }

            $getTokenData = $getTokenData['data'];
            $updateToken = [
                "updated_at" => time(),
                "invalidate" => 1 ,
            ];


            $updateTokenTo = $this->apiAccessTokenService->update($getTokenData['id'], $updateToken);
            if ($updateTokenTo['status'] != 'success') {
                throw new ApiErrorException(lang('An unknown error occurred.'));
            }

            /*$userUpdateStatus = User::where('id', $userId)->where('status', 1)
                ->update(['onesignal_key' => null]);

            if ($userUpdateStatus !== 1) {
                throw new ApiErrorException(lang('Onesignal Key Update Error'));
            }*/



            $response = ['status' => 1, 'statusCode' => 200, 'message' => 'Logged out.', '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 apiResponse($response['status'], $response['message'], $response['data'], $response['statusCode']);


    }

}
