package ru.soune.nocopy.handler;

import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.mail.MessagingException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import ru.soune.nocopy.dto.BaseRequest;
import ru.soune.nocopy.dto.BaseResponse;
import ru.soune.nocopy.dto.MessageCode;
import ru.soune.nocopy.dto.register.RegAnswer;
import ru.soune.nocopy.dto.register.VerifyUserRequest;
import ru.soune.nocopy.entity.user.AuthToken;
import ru.soune.nocopy.entity.user.EmailVerificationToken;
import ru.soune.nocopy.entity.user.User;
import ru.soune.nocopy.exception.NotValidFieldException;
import ru.soune.nocopy.exception.UserNotFoundException;
import ru.soune.nocopy.repository.AuthTokenRepository;
import ru.soune.nocopy.repository.EmailVerificationTokenRepository;
import ru.soune.nocopy.repository.UserRepository;
import ru.soune.nocopy.service.mail.EmailService;
import ru.soune.nocopy.service.register.AuthService;
import ru.soune.nocopy.service.user.UserService;

import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Optional;

@Component
@Slf4j
@RequiredArgsConstructor
public class VerifyRegisterUserHandler implements RequestHandler {
    private final ObjectMapper objectMapper;

    private final EmailVerificationTokenRepository emailVerificationTokenRepository;

    private final EmailService emailService;

    private final UserRepository userRepository;

    private final UserService userService;

    private final AuthTokenRepository authTokenRepository;

    private final AuthService authService;

    @Override
    public BaseResponse handle(BaseRequest request) throws MessagingException, IOException {
        VerifyUserRequest verifyUserRequest = objectMapper.convertValue(request.getMessageBody(), VerifyUserRequest.class);

        Long userId = verifyUserRequest.getUserId();

        User user = userRepository.findById(userId)
                .orElseThrow(() -> new UserNotFoundException("User not found with id: " + userId));

        List<AuthToken> userAuthTokens = authTokenRepository.findByUserId(userId);

        AuthToken authToken = userAuthTokens.isEmpty() ? authService.generateAuthToken(user): userAuthTokens.getFirst();

        if (verifyUserRequest.getResend() != null && verifyUserRequest.getResend() == 1) {
            return handleResend(request, user, authToken);
        }

        return handleVerify(request, user, authToken, verifyUserRequest.getVerifyToken());
    }

    private BaseResponse handleResend(BaseRequest request, User user, AuthToken authToken) throws MessagingException, IOException {

        EmailVerificationToken token = emailVerificationTokenRepository.findByUserId(user.getId());

//        if (token != null && !token.isExpired()) {
//            emailService.sendVerificationEmail(user, token.getToken());
//
//            log.info("Verification token resent for user {}", user.getEmail());
//            return successResponse(request, authToken, "Verification code has been resent", false,
//                    false, user.getEmail());
//        }

        if (token != null) {
            emailVerificationTokenRepository.delete(token);
        }

        EmailVerificationToken newToken = emailService.createEmailVerificationToken(authToken);

        emailService.sendVerificationEmail(user, newToken.getToken());

        log.info("New verification token generated for user {}", user.getEmail());

        return successResponse(request, authToken, "New verification code has been sent",
                false, false, user.getEmail());
    }


    private BaseResponse handleVerify(BaseRequest request, User user, AuthToken authToken, String providedToken) {

        EmailVerificationToken token = emailVerificationTokenRepository.findByUserIdAndToken(user.getId(), providedToken);

        if (token == null || token.isExpired()) {
            throw new NotValidFieldException("Invalid or expired token",
                    new BaseResponse(request.getMsgId(), MessageCode.INVALID_TOKEN.getCode(),
                            MessageCode.INVALID_TOKEN.getDescription(), Map.of("userId", user.getId())));
        }

        User updateUser = userService.activateAndVerifyUser(user.getId());

        emailVerificationTokenRepository.delete(token);

        return successResponse(request, authToken, MessageCode.SUCCESS.getDescription(), updateUser.isActive(),
                updateUser.isEmailVerified(), updateUser.getEmail());
    }

    private BaseResponse successResponse(BaseRequest request, AuthToken authToken, String message, boolean isActive,
                                         boolean isVerified, String email) {
        RegAnswer regAnswer = new RegAnswer();
        regAnswer.setToken(authToken.getToken());
        regAnswer.setVerified(isVerified);
        regAnswer.setActive(isActive);
        regAnswer.setEmail(email);

        return new BaseResponse(request.getMsgId(), MessageCode.SUCCESS.getCode(), message, regAnswer);
    }
}
