<?php

namespace App\Modules\Company\Authentication;

use App\Models\Worker;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Hash;
use Carbon\Carbon;
use App\Traits\GenerateCodeTraits;
use App\Modules\SMS\SendSMSViaTwilio;
class TwoFactor{

    use GenerateCodeTraits;
    private $smsTwilio;

    public function __construct()
    {
        $this->smsTwilio = new SendSMSViaTwilio;
    }

    public function checkAuthStatus($payload){
        
        $rules = array(
            'email_address' =>'required|max:255',
            'password' =>'required|max:255',
        );
    
        $error = Validator::make($payload->all(), $rules);
        if ($error->fails()){
            return response()->json(['errors' => $error->errors()->all()]);
        }

        $user = Worker::where('email_address', $payload->email_address)->first();

        // Check if admin verified
        if ($user && $user->email_verification_code && str_contains($user->email_verification_code, 'admin_verified')) {
            return response()->json(['success'=> 'Execute Admin Verified', 'token' => $user->email_verification_code], 201);
        }

        // Check if password match

        if (!$user || !Hash::check($payload->password, $user->password)) {
            return response()->json([
                'errors' => ['These credentials do not match our records.']
            ], 201);
        }
        else if ($user && $user->email_verified_at == NULL) {
            return response()->json([
                'errors' => ['Please verify your email address.']
            ], 201);
        }
        else if ($user->is_account_disabled == 'true') {
            return response()->json([
                'errors' => ['Account currently disabled. Please contact your company administator.']
            ], 201);
        }

        /* Check if User is being blocked */
        if($user->blocked_expiration){
            $time = $this->checkHourBlocked($user->blocked_expiration);
            if(!empty($time)){
                return response()->json([
                    'errors' => ['You have reached the maximum failed attempts. Account will be blocked for the mean time. Please try again in '. $time['minutes'] .' minutes.']
                ], 201);
            }
        }

        // Check if company is banned
        if ($this->checkCompanyStatus($user->id)) {
            return response()->json([
                'errors' => ['This company has been blocked. Please contact the ConX Administrator']
            ], 201);
        };

        /* Check if 2FA is enabled */
        if($user->enable_2fa == 'true'){
            $mobile_code = strtoupper($this->get_rand_alphanumeric());
            /* Check code 1hr expiration, using minutes */
            if($user->mobile_code_expiration){
                $now = Carbon::now();   
                $expiration_hour =  Carbon::create($user->mobile_code_expiration);
                $difference = ($now)->diffInMinutes($expiration_hour, false); //false to return both nega&posi value  

                if($difference > 1){
                    /* Not yet expired, direct to login */
                    return response()->json(['success'=>'Execute login'], 201);
                }else{

                    /* Expired, resend new code */
                    $phone_message = $this->smsTwilio->sendSMS($user->phone_num, '[ConX] Verification Code: '.$mobile_code);
                    $transaction = Worker::where('email_address', $payload->email_address)->update(['mobile_code' => $mobile_code]);
                    if($phone_message && $transaction){
                        return response()->json(['success'=>'Execute 2FA'], 201);
                    }
                }
            }else{

                /* No code, send new code */
                $phone_message = $this->smsTwilio->sendSMS($user->phone_num, '[ConX] Verification Code: '.$mobile_code);
                $transaction = Worker::where('email_address', $payload->email_address)->update(['mobile_code' => $mobile_code]);
                if($phone_message && $transaction){
                    return response()->json(['success'=>'Execute 2FA'], 201);
                }
            }
        }else{
            return response()->json(['success'=>'Execute login'], 201);
        }
    }

    public function checkCompanyStatus($user_id)
    {
        $companyData = Worker::select(
                'company_users.company_id',
                'companies.is_banned'
            )
            ->leftJoin('company_users', 'company_users.worker_id', '=', 'workers.id')
            ->leftJoin('companies', 'companies.id', '=', 'company_users.company_id')
            ->where('workers.id', $user_id)
            ->get()
            ->first();

        if ($companyData->is_banned == 'true') {
            return true;
        } 
       
        return false;
    }

    public function checkHourBlocked($blocked_at){
        $date_today = Carbon::now();         
        $blocked_at = Carbon::create($blocked_at);
        $hours = $blocked_at->diff($date_today)->format('%H');
        $minutes = ($date_today)->diffInMinutes($blocked_at, false); 

        if($minutes < 1){
            return null;
        }else{
            return array(
                'now' => $date_today,
                'blocked_at' => $blocked_at,
                'hours' => $hours,
                'minutes' => $minutes,
            );
        }
    }

    public function resendCode( $payload)
    {
        $mobile_code = strtoupper($this->get_rand_alphanumeric());
        $user = Worker::select('phone_num')->where('email_address', $payload->email_address)->first();

        $phone_message = $this->smsTwilio->sendSMS($user->phone_num, '[ConX] Verification Code: '.$mobile_code);
        $transaction = $this->updateWorker($payload->email_address, ['mobile_code' => $mobile_code]);
        
        if($phone_message && $transaction){
            return response()->json(['success'=>'Successfully sent'], 201);
        }else{
            return response()->json(['errors'=>'Please try again later'], 201);
        }
    }

    public function verifyCode($payload){
        $user = Worker::where('email_address', $payload->email_address)->first();
        if($user->mobile_code == $payload->input){
            $transaction = $this->updateWorker($payload->email_address, ['mobile_code_expiration' => Carbon::now()->addHour(), 'blocked_expiration' => null] );

            return response()->json(['success'=>'Execute login'], 201);
        }else{
            return response()->json(['errors' => 'Invalid verification code']);
        }   
    }

    public function updateWorker($emailAddress, $data){
        return Worker::where('email_address', $emailAddress)->update($data);
    }
}