<?php

namespace App\Http\Controllers;

use App\Http\Requests\SignUpRequest;
use App\Mail\ResetPasswordMail;
use App\Notifications\RandomPasswordGenerated;
use App\Repositories\CompanyRepository;
use App\Repositories\UserRepository;
use App\User;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Str;
use Tymon\JWTAuth\JWTAuth;

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

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

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

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

    public function register(Request $request) {
        try {
            $pwd = Str::random(10);
            $request["password"] = $pwd;
            $user = UserRepository::create($request->all());
            $user->notify((new RandomPasswordGenerated($user, $pwd))->delay(Carbon::now()->addSeconds(5)));
        }
        catch (\Exception $e) {
            return response()->json(["error" => "No se ha podido realizar el registro: " . $e->getMessage()], 400);
        }

        return response()->json($user, 200);
    }

    /**
     * Get the authenticated User.
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function me()
    {
        $user = auth()->user();
        $user->user_subscriptions = UserRepository::userSubscriptions($user->id, null, null, ["active" => true]);
        foreach($user->user_subscriptions as $sub) {
            $sub->company = CompanyRepository::find($sub->pricing->company_id);
        }
        return response()->json($user);
    }

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

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

    /**
     * Refresh a token.
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function refresh(Request $request)
    {
        $custom_user_id = $request->query("custom_user_id");
        return $this->respondWithToken(auth()->refresh(), $custom_user_id);
    }

    /**
     * Get the token array structure.
     *
     * @param  string $token
     *
     * @return \Illuminate\Http\JsonResponse
     */
    protected function respondWithToken($token, $custom_user_id = null)
    {
        $user = auth()->user();
        $subscriptions = [];

        foreach(UserRepository::userSubscriptions($user->id, null, null, ["active" => true]) as $sub) {
            //Subscription Selection Level "Company"
            if($sub->role != null && $sub->role->slug == "company_admin") {
                $us = clone $sub;
                $us->pricing = null;
                $us->role = null;
                array_push($subscriptions, [
                    "box" => null,
                    "company" => $sub->company->makeHidden("boxes"),
                    "role" => $sub->role,
                    "pricing" => $sub->pricing->makeHidden("boxes"),
                    "us" => $us->makeHidden("pricing")->makeHidden("role")->makeHidden("company"),
                    "level" => "Company"
                ]);
            }
            else if($sub->role != null && $sub->role->slug == "super_admin") {
                if($custom_user_id == null) {
                    //mirem si vol nomes la de super admin
                    $us = clone $sub;
                    $us->role = null;
                    $us->pricing = null;
                    array_push($subscriptions, [
                        "box" => null,
                        "company" => null,
                        "pricing" => null,
                        "role" => $sub->role,
                        "us" => $us->makeHidden("pricing")->makeHidden("role")->makeHidden("company"),
                        "level" => "Super"
                    ]);
                }
                else {
                    //o si ha demanat un usuari en concret
                    auth()->setUser(User::findOrFail($custom_user_id));
                    return $this->respondWithToken(auth()->fromUser(auth()->user()), null); //ho tallem aqui... es suposa que mai fara login a un superadmin
                }
            }

            //Subscription Selection Level "Box"
            if($sub->pricing != null) {
                foreach($sub->pricing->boxes as $box) {
                    $company = $box->company ? $box->company : CompanyRepository::find($box->company_id);
                    $us = clone $sub;
                    $b = clone $box;
                    $company->makeHidden("boxes");
                    unset($b->company);
                    array_push($subscriptions, [
                        "box" => $b,
                        "company" => $company,
                        "role" => $sub->role,
                        "pricing" => $sub->pricing->makeHidden("boxes"),
                        "us" => $us->makeHidden("pricing")->makeHidden("role")->makeHidden("company"),
                        "level" => "Box"
                    ]);
                }
            }
        }

        $user->user_subscriptions = null;
        return response()->json([
            'access_token' => $token,
            'token_type' => 'bearer',
            'expires_in' => auth()->factory()->getTTL() * 60,
            "user" => $user,
            "subscriptions" => $subscriptions
        ]);
    }

    public function resetPassword(Request $request) {
        //we will send an email
        $email = $request->email;
        if(!User::where('email', $email)->exists()) {
            return response()->json([
                "error" => "Email does not exist."
            ], Response::HTTP_NOT_FOUND);
        }
        else {
            //Mirem si ja té un token generat, sinó el creem
            $token = null;
            if(($token = DB::table('password_resets')->select("token")->where("email", $email))->exists()) {
                $token = $token->first()->token;
            }
            else {
                $token = Str::random(20);

                //Guardem el token
                DB::table('password_resets')->insert([
                    "email" => $email,
                    "token" => $token,
                    "created_at" => Carbon::now()
                ]);
            }

            //Enviem el correu
            Mail::to($email)->send(new ResetPasswordMail($token));
            return response()->json([
                "data" => "Reset email has been sent. Please check your inbox."
            ], Response::HTTP_OK);
        }
    }

    public function changePassword(Request $request) {
        $password = $request->password;
        $token = $request->token;

        if( ($row = DB::table('password_resets')->select("email")->where("token", $token))->exists()) {
            $email = $row->first()->email;
            $row->delete();
            User::where("email", $email)->update(["password" => bcrypt($password)]);
            return response()->json([
                "data" => "Password changed"
            ], Response::HTTP_OK);
        }
        else {
            return response()->json([
                "error" => "Token not valid for this email"
            ], Response::HTTP_NOT_FOUND);
        }
    }
}
