<?php

namespace App\Http\Controllers\Frontend;

use App\Facades\AccountsService;
use App\Facades\JwtService;
use App\Http\Controllers\Controller;
use App\Http\Requests\EmailVerification;
use App\Http\Requests\RequestChangePassword;
use App\Http\Requests\UserEmailRequest;
use App\Http\Requests\UserIdShow;
use App\Http\Requests\UserLogin;
use App\Http\Requests\UserProfileFullUpdateRequest;
use App\Http\Requests\UserProfileUploadRequest;
use App\Http\Requests\UserUpdate;
use App\Http\Requests\UserResetPassword;
use App\Http\Requests\UserCreate;
use App\Http\Requests\UserEmailCodeRequest;
use App\Http\Resources\User\UserResultJuryMemberResource;
use App\Http\Resources\UserResource;
use App\Models\User;
use Illuminate\Auth\Events\PasswordReset;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Password;
use App\Facades\UserService;
use App\Http\Requests\UserProfileUpdateRequest;
use App\Http\Resources\AccountProfileResultWinnerResource;
use App\Http\Resources\BasicSelectResource;
use App\Models\UserProfileRole;
use App\Models\UserProfileSpecialisation;

class UsersController extends Controller
{
    /* FE Function */
    public function create(UserCreate $request)
    {
        $data = $request->validated();

        // Checks if user exists with pending email confirmation
        $user = User::where('email', $data['email'])->where('status', User::STATUS_PENDING_EMAIL_CONFIRMATION)->first();
        if ($user) {
            $user = UserService::updateUserPasswordForRegistrationRetry($user, $data);
        } else {
            $user = UserService::createUser($data);
        }

        if (empty($user)) {
            return response()->json(['error' => 'There was a problem creating the user'], 401);
        }

        if ($user->status === User::STATUS_ACTIVE) {
            Auth::guard('api')->login($user);
        }

        return new UserResource($user);
    }

    /* FE Function */
    public function login(UserLogin $request)
    {
        $credentials = $request->only('email', 'password');
        $legacyUser = User::where('email', $credentials['email'])
            ->where('is_legacy_password', true)->first();

        if ($legacyUser && $legacyUser->is_legacy_password) {
            if (md5($credentials['password']) === $legacyUser->password) {
                $legacyUser->password = Hash::make($credentials['password']);
                $legacyUser->is_legacy_password = false;
                $legacyUser->save();
            } else {
                return response(['error' => 'Wrong Credentials'], 401);
            }
        }

        if (!Auth::attempt($credentials)) {
            return response(['error' => 'Wrong Credentials'], 401);
        }

        /** @var User $user */
        $user = Auth::user();

        $data = $request->validated();

        if (!empty($data['invitationToken'])) {
            AccountsService::acceptInvitation($user, $data['invitationToken']);
            if ($user->status === User::STATUS_PENDING_EMAIL_CONFIRMATION) {
                $user->status = User::STATUS_ACTIVE;
                $user->save();
            }
        } elseif ($user->status === User::STATUS_PENDING_EMAIL_CONFIRMATION) {
            Auth::guard('api')->logout();
            $request->session()->invalidate();
            $request->session()->regenerateToken();

            return response(['error' => 'You need to verify your email'], 401);
        }
        $jwtCookie = JwtService::makeRotatedCookie($user);
        $response = (new UserResource($user))
            ->response();
        if ($jwtCookie) {
            $response->withCookie($jwtCookie);
        }
        return $response;
    }

    /* FE Function */
    public function getToken(Request $request)
    {
        /** @var User|null $user */
        $user = $request->user();

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

        $jwtCookie = JwtService::makeRotatedCookie($user);

        $response = response()->json(['message' => 'Token regenerated'], 200);
        if ($jwtCookie) {
            $response->withCookie($jwtCookie);
        }

        return $response;
    }

    /* FE Function */
    public function logout(Request $request)
    {
        $userId = Auth::id();
        $user = User::find($userId);

        if ($user) {
            $user->increment('jwt_token_version');
        }

        Auth::guard('api')->logout();
        $user->tokens()->delete();
        $request->session()->invalidate();
        $request->session()->regenerateToken();

        return response(['message' => 'Logout'])
            ->withCookie(JwtService::forgetCookie());
    }

    /* FE Function */
    public function changePassword(RequestChangePassword $request)
    {
        $userData = Auth::user();
        $data = $request->validated();
        $response = UserService::changePassword($data, $userData);
        if (!$response) {
            return response()->json(['message' => __('passwords.previous_password_incorrect')], 422);
        }
        return response()->json(['message' => __('passwords.password_updated_successfully')]);
    }

    /* FE Function */
    public function getUser()
    {
        $userData = Auth::user();

        return new UserResource($userData);
    }

    /* FE Function */
    public function update(UserUpdate $request)
    {
        $data = $request->validated();
        $user= Auth::user();

        $userData = UserService::updateUser($user, $data);

        return new UserResource($userData);
    }

    public function updateProfile(UserProfileUpdateRequest $request)
    {
        $data = $request->validated();
        $user = Auth::user();

        $userData = UserService::updateUserProfile($user, $data);

        return new UserResource($userData);
    }

    public function updateFullProfile(UserProfileFullUpdateRequest $request)
    {
        $data = $request->validated();

        $user = Auth::user();

        $userData = UserService::updateUserFullProfile($user, $data);

        return new UserResource($userData);
    }

    /* FE Function */
    public function forgotPassword(UserEmailRequest $request)
    {
        $data = $request->validated();

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

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

    /* FE Function */
    public function resetPassword(UserResetPassword $request)
    {
        $data = $request->validated();

        $status = Password::reset(
            $data,
            function (User $user, string $password) {
                $user->forceFill([
                    'password' => Hash::make($password),
                    'is_legacy_password' => false,
                ])->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);
    }

    /* FE Function */
    protected function verify(EmailVerification $request)
    {
        $data = $request->validated();
        UserService::verifyEmail($data['id']);

        return response(['message' => __('response.email_verified')]);
    }

    /* FE Function */
    protected function resend(UserIdShow $request)
    {
        $data = $request->validated();
        $userId = $data['id'];
        $user = UserService::getUser($userId);
        if (empty($user)) {
            return response(['message' => 'User does not exist.']);
        }
        if ($user->status !== User::STATUS_PENDING_EMAIL_CONFIRMATION) {
            return response(['message' => 'This account is already validated.']);
        }
        UserService::generateUserCode($userId);
        return response(['message' => 'Resend email code verification.']);
    }

    /* FE Function */
    public function resendCode(UserEmailRequest $request)
    {
        $data = $request->validated();
        $user = User::where('email', $data['email'])->first();
        $status = UserService::generateUserCode($user->id);
        if (!$status) {
            return response()->json(['message' => 'Verification code still valid.'], 422);
        }
        return response()->json(['message' => 'E-Mail sended.']);
    }

    /* FE Function */
    public function checkCode(UserEmailCodeRequest $request)
    {
        $data = $request->validated();
        $user = UserService::checkUserCode($data);
        if (!$user) {
            return response()->json(['message' => 'Invalid code or expired.'], 422);
        }

        Auth::guard('api')->login($user);

        return new UserResource($user);
    }

    public function getUserProfileRoles()
    {
        return BasicSelectResource::collection(UserProfileRole::full()->get());
    }

    public function getUserProfileSpecialisations()
    {
        return BasicSelectResource::collection(UserProfileSpecialisation::full()->get());
    }

    public function uploadProfileImage(UserProfileUploadRequest $request)
    {
        $data = $request->validated();
        $image = $data['image'] ?? null;
        $user = Auth::user();

        $success = UserService::uploadProfileImage($user, $image);
        return [
            'success' => $success
        ];
    }

    public function getUserJuryMembers()
    {
        $user = Auth::user();
        $juryMembers = UserService::getUserJuryMembers($user);

        return UserResultJuryMemberResource::collection($juryMembers);
    }

    public function getUserResultWinners()
    {
        $user = Auth::user();
        $resultWinners = UserService::getUserResultWinners($user);

        return AccountProfileResultWinnerResource::collection($resultWinners);
    }
}
