<?php

namespace App\Http\Controllers;

use App\Http\Requests\AuthForgotPassword;
use App\Http\Requests\AuthLogin;
use App\Http\Requests\AuthRegister;
use App\Http\Requests\AuthVerifyTwoFactor;
use App\Http\Requests\BaseShow;
use App\Http\Requests\EmailVerification;
use App\Http\Requests\UserFrontendResetPassword;
use App\Http\Resources\UserResource;
use App\Libs\Services\UserService;
use App\Notifications\TwoFactorCode;
use App\Models\TrustedDevice;
use App\Models\User;
use Illuminate\Auth\Events\PasswordReset;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Password;
use Illuminate\Http\Request;
use Illuminate\Auth\Events\Registered;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;

class AuthController extends Controller
{
    public function postRegister(AuthRegister $request, UserService $userService)
    {
        $data = $request->validated();

        $data['state'] = "pendingEmailValidation";
        $data['role'] = "user";
        $user = $userService->createUser($data);

        if (empty($user)) {
            return response(['error' => 'Wrong Credentials'], 401);
        }

        event(new Registered($user));
        return new UserResource($user);
    }

    public function postLogin(AuthLogin $request)
    {
        $credentials = $request->only('email', 'password');
        if (!Auth::attempt($credentials)) {
            return response(['error' => 'Wrong Credentials'], 401);
        }

        $user = User::where('email', $credentials['email'])->first();

        if ($user->state === 'inactive') {
            Auth::guard('api')->logout();
            $request->session()->invalidate();
            $request->session()->regenerateToken();

            return response(['error' => 'Contact Admin'], 401);
        }

        if ($user->state === 'pendingEmailValidation') {
            Auth::guard('api')->logout();
            $request->session()->invalidate();
            $request->session()->regenerateToken();

            return response(['error' => 'You need to verify your email'], 401);
        }

        if ($user->state === 'pendingApproval') {
            Auth::guard('api')->logout();
            $request->session()->invalidate();
            $request->session()->regenerateToken();

            return response(['error' => 'Your registration is pending approval by Energy Traders Europe'], 401);
        }

        // Check if this device is trusted via cookie
        $deviceToken = $request->cookie('two_factor_device_token');
        if ($deviceToken) {
            $trusted = TrustedDevice::where('user_id', $user->id)
                ->where('device_token', $deviceToken)
                ->exists();

            if ($trusted) {
                return new UserResource($user);
            }
        }

        $code = str_pad(random_int(0, 999999), 6, '0', STR_PAD_LEFT);

        $user->two_factor_code       = $code;
        $user->two_factor_expires_at = now()->addMinutes(5);
        $user->save();

        $request->session()->put('two_factor_user_id', $user->id);
        $request->session()->put('two_factor_remember', $request->boolean('remember'));

        $user->notify(new TwoFactorCode($code));

        Auth::guard('api')->logout();

        return response(['requires_2fa' => true], 200);
    }

    public function postVerifyTwoFactor(AuthVerifyTwoFactor $request)
    {
        $userId = $request->session()->get('two_factor_user_id');

        if (!$userId) {
            return response(['error' => 'No pending 2FA session found.'], 422);
        }

        $user = User::find($userId);

        if (!$user) {
            return response(['error' => 'User not found.'], 404);
        }

        $codeMatches = $user->two_factor_code === $request->input('code');
        $codeValid   = $user->two_factor_expires_at && $user->two_factor_expires_at->isFuture();

        if (!$codeMatches || !$codeValid) {
            throw ValidationException::withMessages([
                'code' => ['Invalid or expired verification code.'],
            ]);
        }

        // Clear the 2FA code
        $user->two_factor_code = null;
        $user->two_factor_expires_at = null;
        $user->save();

        $remember = $request->session()->get('two_factor_remember', false);
        $request->session()->forget(['two_factor_user_id', 'two_factor_remember']);

        Auth::login($user, $remember);

        $response = [
            'user' => new UserResource($user)
        ];

        // Optionally trust this device for 60 days via cookie
        if ($request->boolean('remember_device')) {
            $deviceToken = Str::random(60);

            TrustedDevice::create([
                'user_id'      => $user->id,
                'device_token' => $deviceToken,
            ]);

            $days = config('auth.two_factor_remember_days', 60);

            return response($response)->withCookie(
                cookie('two_factor_device_token', $deviceToken, $days * 24 * 60, '/', null, $request->secure(), true, false, 'Lax')
            );
        }

        return response($response, 200);
    }

    public function postForgotPassword(AuthForgotPassword $request)
    {
        $data = $request->validated();

        Password::sendResetLink($data, function($user, $token) {
            $user->sendPasswordUserResetNotification($token, $user->email);
        });

        return response(['message' => 'Success']);
    }

    public function postResetPassword(UserFrontendResetPassword $request)
    {
        $data = $request->validated();

        $status = Password::reset(
            $data,
            function (User $user, string $password) {
                $user->forceFill([
                    'password' => Hash::make($password)
                ])->setRememberToken(Str::random(60));

                $user->save();

                event(new PasswordReset($user));
            }
        );

        return $status === Password::PASSWORD_RESET
                ? response()->json(['message' => 'Password reset successfully.'], 200)
                : response()->json(['message' => 'Password reset failed.'], 404);
    }

    public function postLogout(Request $request)
    {
        Auth::guard('api')->logout();
        $request->session()->invalidate();
        $request->session()->regenerateToken();

        return response(['message' => 'Logout']);
    }

    protected function verify(EmailVerification $request)
    {
        $request->fulfill();

        return response(['message' => 'Email successfully verified.']);
    }

    protected function resend(BaseShow $request, UserService $userService)
    {
        $data = $request->validated();
        $userId = $data['slug'];
        $user = $userService->findById($userId);
        if (empty($user)) {
            return response(['message' => 'User does not exist.']);
        }
        if ($user->state !== 'pendingEmailValidation') {
            return response(['message' => 'This email is already validated.']);
        }
        event(new Registered($user));
        return response(['message' => 'Resend email verification.']);
    }
}
