package de.oaa.xxx.emailchange;

import de.oaa.xxx.mail.Email;
import de.oaa.xxx.mail.MailService;
import de.oaa.xxx.mail.MailTemplateService;
import de.oaa.xxx.registration.RegistrationRepository;
import de.oaa.xxx.user.UserRepository;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseCookie;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;
import java.security.Principal;
import java.util.UUID;
import java.util.regex.Pattern;

@RestController
@RequestMapping("/email-change")
public class EmailChangeController {

    private static final Logger LOGGER = LoggerFactory.getLogger(EmailChangeController.class);
    private static final Pattern EMAIL_PATTERN = Pattern.compile("^[^@\\s]+@[^@\\s]+\\.[^@\\s]+$");

    @Value("${app.base-url:http://localhost:8080}")
    private String baseUrl;

    private final EmailChangeRepository emailChangeRepository;
    private final UserRepository userRepository;
    private final RegistrationRepository registrationRepository;
    private final MailService mailService;
    private final MailTemplateService mailTemplateService;

    public EmailChangeController(EmailChangeRepository emailChangeRepository,
                                 UserRepository userRepository,
                                 RegistrationRepository registrationRepository,
                                 MailService mailService,
                                 MailTemplateService mailTemplateService) {
        this.emailChangeRepository = emailChangeRepository;
        this.userRepository = userRepository;
        this.registrationRepository = registrationRepository;
        this.mailService = mailService;
        this.mailTemplateService = mailTemplateService;
    }

    record EmailChangeRequest(String newEmail) {}

    @PostMapping
    public ResponseEntity<Void> requestChange(@RequestBody EmailChangeRequest request, Principal principal) {
        String currentEmail = principal.getName();
        String newEmail = request.newEmail();

        if (newEmail == null || newEmail.isBlank() || !EMAIL_PATTERN.matcher(newEmail).matches()) {
            return ResponseEntity.badRequest().build();
        }

        if (userRepository.findByEmail(newEmail).isPresent()
                || registrationRepository.findByEmail(newEmail).isPresent()) {
            return ResponseEntity.status(409).build();
        }

        // Remove any pending request for this user
        emailChangeRepository.findByUserEmail(currentEmail)
                .ifPresent(emailChangeRepository::delete);

        var user = userRepository.findByEmail(currentEmail);
        if (user.isEmpty()) return ResponseEntity.status(401).build();

        EmailChangeEntity entity = EmailChangeEntity.create(currentEmail, newEmail);
        emailChangeRepository.save(entity);

        Email email = new Email();
        email.setTitel("Bitte bestätige deine neue E-Mail-Adresse");
        email.setEmailAdresse(newEmail);
        String confirmLink = baseUrl + "/email-change/" + entity.getTokenId().toString();
        email.setText(mailTemplateService.buildEmailChangeMail(user.get().getName(), confirmLink, newEmail));

        if (!mailService.send(email)) {
            emailChangeRepository.delete(entity);
            return ResponseEntity.internalServerError().build();
        }

        return ResponseEntity.status(202).build();
    }

    @GetMapping("/{token}")
    public void confirm(@PathVariable String token, HttpServletResponse response) throws IOException {
        UUID tokenId;
        try {
            tokenId = UUID.fromString(token);
        } catch (IllegalArgumentException e) {
            response.sendRedirect("/login.html");
            return;
        }

        var entity = emailChangeRepository.findById(tokenId);
        if (entity.isEmpty()) {
            response.sendRedirect("/login.html");
            return;
        }

        var user = userRepository.findByEmail(entity.get().getUserEmail());
        if (user.isPresent()) {
            user.get().setEmail(entity.get().getNewEmail());
            userRepository.save(user.get());
            LOGGER.info("E-Mail geändert von {} zu {}", entity.get().getUserEmail(), entity.get().getNewEmail());
        }

        emailChangeRepository.delete(entity.get());

        // Clear JWT cookie so user must log in with new email
        ResponseCookie cookie = ResponseCookie.from("jwt", "")
                .httpOnly(true)
                .sameSite("Strict")
                .path("/")
                .maxAge(0)
                .build();
        response.addHeader(HttpHeaders.SET_COOKIE, cookie.toString());
        response.sendRedirect("/login.html?emailChanged=1");
    }
}
