<?php

namespace App\Http\Controllers\Auth;

use App\Helpers\ClientHelper;
use App\Http\Controllers\Controller;
use App\Http\Requests\Auth\PhoneDoLoginRequest;
use App\Http\Requests\Auth\PhoneLoginRequest;
use App\Http\Requests\User\ProfileUpdateRequest;
use App\Models\Token;
use App\Models\User;
use App\Notifications\Login;
use App\Services\Auth\AuthProcessService;
use Carbon\Carbon;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Inertia\Inertia;
use Inertia\Response;

class PhoneLoginController extends Controller
{
    use ClientHelper;

    /**
     * Show Login Form
     */
    public function show(Request $request): Response
    {
        return Inertia::render('Auth/Login', [
            'status' => $request->status,
            'prev' => $request->prev,
        ])->title(__('messages.title.login'));
    }

    /**
     * Process Login
     */
    public function process(PhoneLoginRequest $request, AuthProcessService $authProcessService): RedirectResponse
    {
        // find user
        $user = User::where('phone', $request->validated('phone'))->first();

        // check read-only owner
        if ($user != null && $user->phone == "09999999999" && $user->username == "#demo") {
            auth()->loginUsingId($user->id);
            return redirect()->route('admin.dashboard');
        }

        // auth status
        $authStatus = $request->has('status') && $request->status == 'password' ? 'password' : 'token';

        // register user if not exist
        if ($user == null) {
            $user = $authProcessService->registerUser($request);
            $authStatus = 'token';
        }

        if ($authStatus == 'password') {
            // with password
            return redirect()->route('login.verify', ['phone' => $request->validated('phone'), 'status' => $authStatus, 'prev' => $request->prev]);
        } else {
            // with otp
            // process authentication token
            $token = $authProcessService->createToken($request, $user);

            if ($token == 'to_verify')
                return redirect()->route('login.verify', ['phone' => $request->validated('phone'), 'prev' => $request->prev]);

            if ($authProcessService->sendToken($token, $user))
                return redirect()->route('login.verify', ['phone' => $request->validated('phone'), 'prev' => $request->prev]);

            return redirect()->back()->withErrors(['codeError' => __('messages.unknown_error')]);
        }
    }

    /**
     * Verify Authentication Code
     */
    public function verify(PhoneLoginRequest $request, AuthProcessService $authProcessService): Response | RedirectResponse
    {
        // find user
        $user = User::where('phone', $request->validated('phone'))->first();
        if ($user === null)
            return redirect()->route('login');

        // auth status
        $authStatus = $request->has('status') && $request->status == 'password' ? 'password' : 'token';

        if ($authStatus == 'password') {
            // with password
            return Inertia::render('Auth/Verify', [
                "phone" => $request->phone,
                "status" => "password",
                "prev" => $request->prev,
            ])->title(__('messages.title.verify_login'));
        } else {
            // with otp
            // check for exist valid token
            $token = $authProcessService->currentToken($request, $user);
            // redirect to login page if no exist valid token
            if ($token == null)
                return redirect()->route('login');

            return Inertia::render('Auth/Verify', [
                "phone" => $request->phone,
                "remaining" => (Carbon::parse($token->created_at)->timestamp + Token::EXPIRATION_TIME) - Carbon::now()->timestamp,
                "prev" => $request->prev,
            ])->title(__('messages.title.verify_login'));
        }
    }

    /**
     * do login
     */
    public function login(PhoneDoLoginRequest $request, AuthProcessService $authProcessService): Response | RedirectResponse | \Illuminate\Http\Response
    {
        // find user
        $user = User::where('phone', $request->validated('phone'))->first();
        if ($user === null)
            return redirect()->route('login');

        // auth status
        $authStatus = $request->has('status') && $request->status == 'password' ? 'password' : 'token';

        // do login
        if ($authStatus == 'password') {
            // with password
            $request->validate([
                'password' => ['required']
            ]);

            if (!$user->with_password) {
                return redirect()->back()->withErrors(['codeError' => __('messages.password_is_wrong')]);
            }

            if (!Hash::check($request->password, $user->password)) {
                return redirect()->back()->withErrors(['codeError' => __('messages.password_is_wrong')]);
            }

            Auth::login($user, $request->boolean('remember'));
            $request->session()->regenerate();

            // update token
            $user->tokens()->create([
                'code'    => 'pass',
                'ip'      => $this->getUserIp(),
                'used'    => true,
                'session' => $request->session()->getId(),
                'meta' => serialize($this->getDeviceMeta($request))
            ]);

            $loginStatus = true;
        } else {
            // with otp
            $request->validate([
                'code' => ['required']
            ]);

            $loginStatus = $authProcessService->loginUser($request, $user);
        }

        if ($loginStatus) {
            // notify user login
            $user->notify(new Login());

            if ($user->name === null || $user->name === "")
                return redirect()->route('login.account.information', ['prev' => $request->prev]);

            if ($request->prev != null)
                return redirect($request->prev);

            if ($user->type == "owner" || $user->type == "admin")
                return Inertia::location(route('admin.dashboard'));

            return redirect()->route('index');
        } else {
            return redirect()->back()->withErrors(['codeError' => __('messages.auth_code_wrong')]);
        }
    }

    /**
     * user account information component
     */
    public function accountInformation(Request $request): Response | RedirectResponse
    {
        // auth user
        $user = auth()->user();

        if ($user->name !== null && $user->name !== '')
            return redirect()->route('index');

        return Inertia::render('Auth/AccountInformation', [
            "name" => $user->name,
            "with_password" => $user->with_password,
            "prev" => $request->prev,
        ])->title(__('messages.title.complete_account_infromation'));
    }

    /**
     * update user account information
     */
    public function accountInformationUpdate(Request $request): Response | RedirectResponse | \Illuminate\Http\Response
    {
        /**
         * auth user
         * @var \App\Models\User $user
         */
        $user = auth()->user();

        // update user fullname
        $validated = $request->validate([
            'name' => ['required', 'string', 'max:255'],
        ]);
        $user->name = $validated['name'];

        if ($request->filled('password')) {
            $passwordRules = [
                'string',
                'min:8',
                'max:255',
                'regex:/^(?=.*\D).+$/',
                function ($attribute, $value, $fail) use ($user) {
                    if ($user->with_password == 0) {
                        return;
                    }

                    if (Hash::check($value, $user->password)) {
                        $fail(__('messages.password_same_current_error'));
                    }
                },
                'confirmed',
            ];

            $request->validate([
                'password' => $passwordRules,
            ], [
                'password.confirmed' => __('messages.password_repeat_error'),
            ]);

            $user->password = Hash::make($request->password);

            if ($user->with_password == 0) {
                $user->with_password = 1;
            }
        }

        $user->save();

        if ($request->prev != null)
            return redirect($request->prev);

        if ($user->type == "owner" || $user->type == "admin")
            return Inertia::location(route('admin.dashboard'));

        return Inertia::location(route('index'));
    }

    /**
     * logout
     */
    public function logout(Request $request, AuthProcessService $authProcessService): RedirectResponse | \Illuminate\Http\Response
    {
        // do logout
        Auth::logout();

        // invalidate token and session
        $authProcessService->invalidateCurrentToken($request);

        return Inertia::location(route('index'));
    }
}
