<?php

namespace Wave\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\Models\InviteUser;
use App\Models\User;
use App\Models\Role as AppRole;
use App\Models\Company;
use Carbon\Carbon;
use Illuminate\Auth\Events\Registered;
use Illuminate\Foundation\Auth\RegistersUsers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Notification;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
use TCG\Voyager\Models\Role;
use Wave\Notifications\VerifyEmail;

class RegisterController extends Controller
{
    /*
    |--------------------------------------------------------------------------
    | Register Controller
    |--------------------------------------------------------------------------
    |
    | This controller handles the registration of new users as well as their
    | validation and creation. By default this controller uses a trait to
    | provide this functionality without requiring any additional code.
    |
    */

    use RegistersUsers;

    /**
     * Where to redirect users after registration.
     *
     * @var string
     */
    protected $redirectTo = '/dashboard';

    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('guest', ['except' =>
            [
                'complete'
            ]]);
    }

    /**
     * Get a validator for an incoming registration request.
     *
     * @param  array  $data
     * @return \Illuminate\Contracts\Validation\Validator
     */
    protected function validator(array $data)
    {
        $validatorArray = [
            'first_name' => 'required|string|max:255',
            'last_name' => 'required|string|max:255',
            'email' => 'required|string|email|max:255|unique:users',
            'phone' => 'required|string',
            'password' => 'required|string|min:6|confirmed',
            'role_id' => 'required|int',
        ];
        if (!isset($data['invite_token'])) {
            $validatorArray['company_email'] = 'required|string|email|max:255';
        }

        return Validator::make($data, $validatorArray);
    }

    /**
     * Create a new user instance after a valid registration.
     *
     * @param  array  $data
     * @return \App\Models\User
     */
    public function create(array $data)
    {
        // $verification_code = NULL;
        // $verified = 1;

        // if(setting('auth.verify_email', false)){
            $verification_code = Str::random(30);
            $verified = false;
        // }

        $username = null;
        if(isset($data['username']) && !empty($data['username'])){
            $username = $data['username'];
        } elseif(isset($data['name']) && !empty($data['name'])) {
            $username = Str::slug($data['name']);
        } else {
            $username = $this->getUniqueUsernameFromEmail($data['email']);
        }

        $username_original = $username;
        $counter = 1;

        while(User::where('username', '=', $username)->first()){
            $username = $username_original . (string)$counter;
            $counter += 1;
        }

        // $trial_days = setting('billing.trial_days', 14);
        // $trial_ends_at = null;
        // // if trial days is not zero we will set trial_ends_at to ending date
        // if(intval($trial_days) > 0){
        //     $trial_ends_at = now()->addDays(setting('billing.trial_days', 14));
        // }

        $company = null;
        if (isset($data['invite_token'])) {
            $inviteUser = InviteUser::where('token', $data['invite_token'])->first();
            if ($inviteUser) {
                $inviteUser->is_used = true;
                $inviteUser->save();

                $company = Company::find($inviteUser->company_id);
                $verified = true;
            }
        }
        else {
            $company = Company::create([
                'email' => $data['company_email'],
            ]);
        }

        $user = User::create([
            'first_name' => $data['first_name'],
            'last_name' => $data['last_name'],
            'name' => $data['first_name'] . ' ' . $data['last_name'],
            'email' => $data['email'],
            'username' => $username,
            'password' => bcrypt($data['password']),
            'role_id' => $data['role_id'],
            'verification_code' => $verification_code,
            'verified' => $verified,
            'trial_ends_at' => null,
            'company_id' => $company ? $company->id : null,
            'phone' => $data['phone'],
        ]);

        if(!$verified){
            $this->sendVerificationEmail($user);
        }

        return $user;
    }

    /**
     * Complete a new user registration after they have purchased
     *
     * @param  Request  $request
     * @return redirect
     */
    public function complete(Request $request){

        if(setting('auth.username_in_registration') && setting('auth.username_in_registration') == 'yes'){
            $request->validate([
                'name' => 'required|string|min:3|max:255',
                'username' => 'required|string|max:20|unique:users,username,' . auth()->user()->id,
                'password' => 'required|string|min:6'
            ]);
        } else {
            $request->validate([
                'name' => 'required|string|min:3|max:255',
                'password' => 'required|string|min:6'
            ]);
        }

        // Update the user info
        $user = auth()->user();
        $user->name = $request->name;
        $user->username = $request->username;
        $user->password = bcrypt($request->password);
        $user->save();


        return redirect()->route('wave.dashboard')->with(['message' => 'Successfully updated your profile information.', 'message_type' => 'success']);

    }

    private function sendVerificationEmail($user){
        $company = Company::where('id', $user->company_id)->first();
        Notification::route('mail', $company->email)->notify(new VerifyEmail($user));
    }

    public function showRegistrationForm()
    {
        // if(setting('billing.card_upfront')){
        //     return redirect()->route('wave.pricing');
        // }
        // return view('theme::auth.register');
        $token = request()->token ? request()->token : null;
        $inviteEmail = null;
        $roles = null;
        if ($token) {
            $inviteUser = InviteUser::where('token', $token)->first();
            if (!$inviteUser) {
                abort(404);
            }
            if ($inviteUser->is_used) {
                abort(404);
            }
            $userExists = User::where('email', $inviteUser->email)->first();
            if ($userExists) {
                abort(404);
            }
            $inviteEmail = $inviteUser->email;
            $roles = AppRole::whereIn('id', [AppRole::BOOKKEEPER_ROLE, AppRole::COMPANY_SECRETARY_ROLE])->get();
        }
        else {
            $roles = AppRole::whereIn('id', [AppRole::OWNER_ROLE, AppRole::ADMINISTRATOR_ROLE])->get();
        }
        
        return view('theme::auth.user-register', [
            'roles' => $roles,
            'invite_token' => $token,
            'invite_email' => $inviteEmail,
        ]);
    }

    public function verify(Request $request, $verification_code){
        $user = User::where('verification_code', '=', $verification_code)->first();

        if ($user) {
            $user->verification_code = NULL;
            $user->verified = 1;
            $user->email_verified_at = Carbon::now();
            $user->save();

            return view('theme::auth.verified');
        }

        // return redirect()->route('login')->with(['message' => 'Successfully verified your email. You can now login.', 'message_type' => 'success']);
        return redirect()->route('login')->with(['message' => 'Verification code expired', 'message_type' => 'error']);
    }

    /**
     * Handle a registration request for the application.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function register(Request $request)
    {
        $this->validator($request->all())->validate();

        event(new Registered($user = $this->create($request->all())));

        if(setting('auth.verify_email')){
            // send email verification
            return redirect()->route('login')->with(['message' => 'Thanks for signing up! Please check your email to verify your account.', 'message_type' => 'success']);
        } else {
            $this->guard()->login($user);

            return $this->registered($request, $user)
                        ?: redirect($this->redirectPath())->with(['message' => 'Thanks for signing up!', 'message_type' => 'success']);
        }
    }
    
    public function registerAjax(Request $request)
    {
        $validator = $this->validator($request->all());
        if ($validator->fails()) {
            return response()->json([
                'success' => false,
                'errors' => $validator->errors()
            ], 422);
        }
        else {
            event(new Registered($user = $this->create($request->all())));
    
            return response()->json([
                'success' => true,
                'message' => 'Thanks for signing up! Please check your email to verify your account.',
            ]);
        }
    }

    public function getUniqueUsernameFromEmail($email)
    {
        $username = strtolower(trim(Str::slug(explode('@', $email)[0])));

        $new_username = $username;

        $user_exists = User::where('username', '=', $username)->first();
        $counter = 1;
        while (isset($user_exists->id) ) {
            $new_username = $username . $counter;
            $counter += 1;
            $user_exists = User::where('username', '=', $new_username)->first();
        }

        $username = $new_username;

        if(strlen($username) < 4){
            $username = $username . uniqid();
        }

        return strtolower($username);
    }

    public function registerUser(Request $request)
    {
        $validate = Validator::make($request->all(), [
            'first_name' => 'required',
            'last_name' => 'required',
            'username' => 'required',
            'email' => 'required|unique:users',
            'company_email' => 'required',
            'password' => 'required',
            'phone' => 'required',
            'role_id' => 'required',
        ]);
        if ($validate->fails()) {
            return response()->json([
                'status' => false,
                'message' => $validate->messages(),
            ]);
        }

        $data = $request->all();

        $verification_code = Str::random(30);
        $verified = false;

        $username = null;
        if(isset($data['username']) && !empty($data['username'])){
            $username = $data['username'];
        } elseif(isset($data['name']) && !empty($data['name'])) {
            $username = Str::slug($data['name']);
        } else {
            $username = $this->getUniqueUsernameFromEmail($data['email']);
        }

        $username_original = $username;
        $counter = 1;

        while(User::where('username', '=', $username)->first()){
            $username = $username_original . (string)$counter;
            $counter += 1;
        }

        $company = null;
        if (isset($data['invite_token'])) {
            $inviteUser = InviteUser::where('token', $data['invite_token'])->first();
            if ($inviteUser) {
                $inviteUser->is_used = true;
                $inviteUser->save();

                $company = Company::find($inviteUser->company_id);
                $verified = true;
            }
        }
        else {
            $company = Company::create([
                'email' => $data['company_email'],
            ]);
        }
        $token = Str::random(60);

        $user = User::create([
            'first_name' => $data['first_name'],
            'last_name' => $data['last_name'],
            'name' => $data['first_name'] . ' ' . $data['last_name'],
            'email' => $data['email'],
            'username' => $username,
            'password' => bcrypt($data['password']),
            'role_id' => $data['role_id'],
            'verification_code' => $verification_code,
            'verified' => $verified,
            'trial_ends_at' => null,
            'company_id' => $company ? $company->id : null,
            'phone' => $data['phone'],
            'api_token' => hash('sha256', $token),
        ]);

        if(!$verified){
            // $this->sendVerificationEmail($user);
        }

        return response()->json([
            'status' => true,
            'message' => 'user successfully created and send verification code on the email'
        ]);
    }

    public function verifyEmail(Request $request){

        $validate = Validator::make($request->all(), [
            'verification_code' => 'required',
        ]);
        if ($validate->fails()) {
            return response()->json([
                'status' => false,
                'message' => $validate->messages(),
            ]);
        }

        $user = User::where('verification_code', '=', $request->verification_code)->first();

        if ($user) {
            $user->verification_code = NULL;
            $user->verified = 1;
            $user->email_verified_at = Carbon::now();
            $user->save();

            return response()->json([
                'status' => true,
                'message' => 'email successfully verified',
            ]);
        }

        return response()->json([
            'status' => false,
            'message' => 'Verification code expired',
        ]);
    }
}
