<?php

namespace Wave\Http\Controllers\API;

use App\Http\Controllers\Controller;
use App\Mail\ForgetPasswordOtp;
use App\Models\Company;
use App\Models\Role;
use App\Models\User;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Notification;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
use Tymon\JWTAuth\Facades\JWTAuth;
use Wave\ApiKey;
use Wave\Notifications\VerifyEmail;

class AuthController extends Controller
{
    /**
     * Create a new AuthController instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('auth:api', ['except' => ['login', 'token', 'register', 'getRoles', 'forgotPasswordSendOtp']]);
    }

    /**
     * Get a JWT via given credentials.
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function login()
    {
        $credentials = request(['email', 'password']);

        if (! $token = JWTAuth::attempt($credentials)) {
            return response()->json(['error' => 'Unauthorized'], 401);
        }

        $user = JWTAuth::user();
        if(!$user->verified){
		    auth()->guard('api')->logout();
            return response()->json(['error' => 'Please verify your email before logging into your account.'], 401);
        }
        if(!in_array($user->role_id, [Role::OWNER_ROLE, Role::ADMINISTRATOR_ROLE, Role::BOOKKEEPER_ROLE, Role::COMPANY_SECRETARY_ROLE])) {
		    auth()->guard('api')->logout();
            return response()->json(['error' => 'Unauthorized'], 401);
        }

        return $this->respondWithToken($token);
    }

    /**
     * Log the user out (Invalidate the token).
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function logout()
    {
		auth()->guard('api')->logout();

        return response()->json(['message' => 'Successfully logged out']);
    }

    public function token(){
        $request = app('request');

        if(isset($request->key)){

            $key = ApiKey::where('key', '=', $request->key)->first();

            $key->update([
                'last_used_at' => Carbon::now(),
            ]);

            if(isset($key->id)){
                return response()->json(['access_token' => JWTAuth::fromUser($key->user, ['exp' => config('wave.api.key_token_expires', 1)])]);
            } else {
                abort('400', 'Invalid Api Key');
            }

        } else {
            abort('401', 'Unauthorized');
        }

    }

    /**
     * Refresh a token.
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function refresh()
    {
        $token = JWTAuth::getToken();
        return $this->respondWithToken(JWTAuth::refresh($token));
    }

    /**
     * Get the token array structure.
     *
     * @param  string $token
     *
     * @return \Illuminate\Http\JsonResponse
     */
    protected function respondWithToken($token)
    {
        $user = JWTAuth::user();
        return response()->json([
            'access_token' => $token,
            'token_type' => 'bearer',
			'expires_in' => env('JWT_TTL', 60),
            'role_id' => $user->role_id,
        ]);
    }

    public function register(Request $request)
    {
        $validator = Validator::make($request->all(), [
            '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 ($validator->fails()) {
            return response()->json(['error' => $validator->errors()], 422);
        }

        $emailExists = User::where('email', $request['email'])->first();
        if ($emailExists) {
            return response()->json(['error' => 'Email already exists!'], 403);
        }
        
        $verification_code = Str::random(30);
        $verified = true;
        $username = null;
        if(isset($request['username']) && !empty($request['username'])){
            $username = $request['username'];
        } elseif(isset($request['name']) && !empty($request['name'])) {
            $username = Str::slug($request['name']);
        } else {
            $username = $this->getUniqueUsernameFromEmail($request['email']);
        }

        $username_original = $username;
        $counter = 1;

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

        $company = Company::create([
            'email' => $request['company_email'],
        ]);

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

        if(!$verified){
            $this->sendVerificationEmail($user);
        }
        
        $credentials = ['email' => $request['email'], 'password' => $request['password']];

        if (! $token = JWTAuth::attempt($credentials)) {
            return response()->json(['error' => 'Unauthorized'], 401);
        }

        return $this->respondWithToken($token);

    }

    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 getRoles()
    {
        $roles = Role::whereIn('id', [Role::OWNER_ROLE, Role::ADMINISTRATOR_ROLE])->get();

        return response()->json([
            'message' => 'User roles has successfully retrieved!',
            'roles' => $roles,
        ]);
    }

    protected function validator(array $data)
    {
        return Validator::make($data, [
            'name' => 'required|string|max:255',
            'email' => 'required|string|email|max:255|unique:users',
            'password' => 'required|string|min:6|confirmed',
        ]);
    }

    private function sendVerificationEmail($user){
        Notification::route('mail', $user->email)->notify(new VerifyEmail($user));
    }
}
