<?php

namespace App\Modules\Company\Account;

use App\Models\Company;
use App\Models\Worker;
use App\Models\CompanyUser;
use App\Models\CompanyExperience;
use App\Models\Experience;
use App\Models\CompanyBurdenRate;
use App\Models\CompanyExpertise;

use Illuminate\Support\Str;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\DB;
use Illuminate\Http\Request;

use App\Traits\ValidatorTraits;
use App\Traits\MobileNumberValidatorTraits;
use App\Jobs\Company\ProcessSendEmailNewCompany;

use Carbon\Carbon;

class Register {
    use ValidatorTraits, MobileNumberValidatorTraits;

    public function register($payload){

        $rules = array(
            'company_name' => 'required|max:100|unique:companies,name',
            'password' => 'required|min:8',
            'phone_num' => 'required',
            'first_name' => 'required|max:50',
            'last_name' => 'required|max:50',
            'email_address' => 'required|max:191|unique:workers,email_address',
            'password_confirmation' => 'required|same:password',
            'expertises' => 'required',
        );

        $validate = $this->validateRequest($payload, $rules);
        if ($validate) {
            return $validate;
        }

        $validate = $this->validatePhoneNumber($payload->phone_num);
        if ($validate) {
            return response()->json(['errors' => ["Sorry, you have used non-existing US mobile number."]])->setStatusCode(201);
        }

        DB::beginTransaction();

        

        $emailAddress = strtolower($payload->email_address);

        // Create company
        $companyData = array(
            'name' => $payload->company_name,
            'email_address' => $emailAddress,
            'service_charge' => 10, //default service charge
            'is_iec_member' => 'false',
            'is_banned' => 'false',
            
        );

        $companyTransaction = $this->createCompany($companyData);

        $emailVerificationToken = hash('sha256', Str::random(40));
        
        // create worker data
        $workerData = array(
            'email_address' => $emailAddress,
            'first_name' => ucfirst($payload->first_name),
            'last_name' => ucfirst($payload->last_name),
            'phone_num' => $this->databaseFormatNumber($payload->phone_num),
            'password' => Hash::make($payload->password),
            'email_verification_code' => $emailVerificationToken
        );

        $workerTransaction = $this->createWorker($workerData);
        // create company user
        $companyUserData = array(
            'worker_id' => $workerTransaction->id,
            'company_id' => $companyTransaction->id,
            'role_id' => 1,  //admin role
        );

        $expertises = $payload->expertises;
        $companyExpertiseTransactionList = [];
        foreach($expertises as $expertise){
            $companyExpertise = array(
                'expertise_id' => $expertise,
                'company_id' => $companyTransaction->id,
            );
            array_push($companyExpertiseTransactionList, $this->createCompanyExpertise($companyExpertise));
        }

        

        $companyUserTransaction = $this->createCompanyUser($companyUserData);

        $createCompanyExperiencesTransaction = $this->createDefaultCompanyExperiences($companyTransaction->id);

        //process of sending email verification
        $baseUrl = env('APP_URL');
        $email_address = $emailAddress;
        $user_data = [
            'title' => 'ConX Email Verification',
            'email' => $email_address,
            'verification_url' => stripslashes($baseUrl . '/verify-email?code=' . $emailVerificationToken),
            'company_name' => $payload->company_name,
            'name' => ucfirst($payload->first_name) ." ". ucfirst($payload->last_name),
        ];

        ProcessSendEmailNewCompany::dispatch($email_address, $user_data)->onConnection('jobs_emails')->onQueue('sendemail');

        foreach($companyExpertiseTransactionList as $companyExpertiseTransaction){
            if(!$companyTransaction || !$workerTransaction || !$companyUserTransaction || !$createCompanyExperiencesTransaction || !$companyExpertiseTransaction){
                DB::rollBack();
                return response()->json(['errors' => 'Something went wrong. Please try again later.']); 
            }
        }
        
        DB::commit();
        return response()->json(['success' => 'Personal acount and company successfully created.']);
        
    }  

    public function createCompany($data){
        return Company::create($data);
    }

    public function createWorker($data){
        return Worker::create($data);
    }

    public function createCompanyUser($data){
        return CompanyUser::create($data);
    }

    public function createCompanyExpertise($data){
        return CompanyExpertise::create($data);
    }

    public function createDefaultCompanyExperiences($companyID){

        $adminExperiences = Experience::get();
        foreach ($adminExperiences as $experience) {

            $companyExperience = CompanyExperience::create([
                'company_id' => $companyID,
                'name' => $experience->name,
            ]);

            CompanyBurdenRate::create([
                'company_id' => $companyID,
                'company_experience_id' => $companyExperience->id,
                'burden_rate' => 0, //default burn rate
                'burden_rate_type' => 'percent', //default burn type
            ]);
        }

        return true;
    }


    // from Setup
    public function verify($payload)
    {
        $emailVerificationCode = $payload->code;
        $emailVerification = Worker::select('email_address')
            ->where('email_verification_code', $emailVerificationCode)
            ->limit(1)
            ->get();
        if ($emailVerification->isEmpty()) {
            return response()->json(['errors' => ['Token not found.']])
                ->setStatusCode(201);
        } else {
            return response()->json([
                'success' => ['Token found.'],
                'email_address' => $emailVerification[0]->email_address,
            ])->setStatusCode(201);
        }
    }

    public function setup($payload)
    {
        // start transaction
        DB::beginTransaction();
        $password = Hash::make($payload->password);
        $emailAddress = $payload->email_address;
        $emailVerificationCode = $payload->token;
        
        $userData = array(
            'email_verification_code' => null,
            'password' => $password,
            'email_verified_at' => Carbon::now(),
        );
        $updateWorkerTransaction = Worker::where('email_address', $emailAddress)
            ->where('email_verification_code', $emailVerificationCode)
            ->update($userData);

        // if there's an error or queries don't do their job, rollback!
        if (!$updateWorkerTransaction) {
            DB::rollBack();
            return response()->json(['error' => 'Server error.', "transaction" => $updateWorkerTransaction]);
        } else {
            DB::commit();
            return response()->json(['success' => 'Data updated successfully.'])->setStatusCode(201);
        }
    }


}