package com.alttd.altitudeweb.services.mail;

import com.alttd.altitudeweb.database.Databases;
import com.alttd.altitudeweb.database.web_db.mail.EmailVerification;
import com.alttd.altitudeweb.database.web_db.mail.EmailVerificationMapper;
import com.alttd.altitudeweb.setup.Connection;
import jakarta.mail.MessagingException;
import jakarta.mail.internet.MimeMessage;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;

import java.time.Instant;
import java.util.Optional;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;

@Slf4j
@Service
@RequiredArgsConstructor
public class MailVerificationService {

    private final JavaMailSender mailSender;

    @Value("${spring.mail.username}")
    private String fromEmail;

    public java.util.List<EmailVerification> listAll(UUID userUuid) {
        java.util.concurrent.CompletableFuture<java.util.List<EmailVerification>> future = new java.util.concurrent.CompletableFuture<>();
        Connection.getConnection(Databases.DEFAULT)
                .runQuery(sql -> {
                    EmailVerificationMapper mapper = sql.getMapper(EmailVerificationMapper.class);
                    future.complete(mapper.findAllByUser(userUuid));
                });
        return future.join();
    }

    public EmailVerification submitEmail(UUID userUuid, String email) {
        String code = generateCode();
        Instant now = Instant.now();
        final String finalEmail = email.toLowerCase();

        CompletableFuture<EmailVerification> future = new CompletableFuture<>();
        Connection.getConnection(Databases.DEFAULT)
                  .runQuery(sql -> {
                    EmailVerificationMapper mapper = sql.getMapper(EmailVerificationMapper.class);
                    EmailVerification existing = mapper.findByUserAndEmail(userUuid, finalEmail);
                    EmailVerification toPersist;
                    if (existing == null) {
                        toPersist = new EmailVerification(UUID.randomUUID(), userUuid, finalEmail, code, false, now, null, now);
                        mapper.insert(toPersist);
                    } else {
                        mapper.updateCodeAndLastSent(existing.id(), code, now);
                        toPersist = new EmailVerification(existing.id(), userUuid, finalEmail, code, false, existing.createdAt(), null, now);
                    }
                    future.complete(toPersist);
                });
        EmailVerification saved = future.join();
        sendVerificationEmail(saved);
        return saved;
    }

    public Optional<EmailVerification> verifyCode(UUID userUuid, String code) {
        CompletableFuture<Optional<EmailVerification>> future = new CompletableFuture<>();
        Connection.getConnection(Databases.DEFAULT)
                .runQuery(sql -> {
                    EmailVerificationMapper mapper = sql.getMapper(EmailVerificationMapper.class);
                    EmailVerification found = mapper.findByUserAndCode(userUuid, code);
                    if (found == null) {
                        future.complete(Optional.empty());
                        return;
                    }
                    mapper.markVerified(found.id(), Instant.now());
                    future.complete(Optional.of(found));
                });
        return future.join();
    }

    public EmailVerification resend(UUID userUuid, String email) {
        String code = generateCode();
        Instant now = Instant.now();
        final String finalEmail = email.toLowerCase();
        CompletableFuture<EmailVerification> future = new CompletableFuture<>();
        Connection.getConnection(Databases.DEFAULT)
                  .runQuery(sql -> {
                    EmailVerificationMapper mapper = sql.getMapper(EmailVerificationMapper.class);
                    EmailVerification existing = mapper.findByUserAndEmail(userUuid, finalEmail);
                    if (existing != null) {
                        mapper.updateCodeAndLastSent(existing.id(), code, now);
                        future.complete(new EmailVerification(existing.id(), userUuid,
                                finalEmail, code, false, existing.createdAt(), null, now));
                    } else {
                        future.complete(null);
                    }
                });
        EmailVerification updated = future.join();
        if (updated != null) {
            sendVerificationEmail(updated);
        }
        return updated;
    }

    public boolean delete(UUID userUuid, String email) {
        final String finalEmail = email.toLowerCase();
        CompletableFuture<Boolean> future = new CompletableFuture<>();
        Connection.getConnection(Databases.DEFAULT)
                .runQuery(sql -> {
                    EmailVerificationMapper mapper = sql.getMapper(EmailVerificationMapper.class);
                    EmailVerification existing = mapper.findByUserAndEmail(userUuid, finalEmail);
                    if (existing != null) {
                        mapper.deleteByUserAndEmail(userUuid, finalEmail);
                        future.complete(true);
                    } else {
                        future.complete(false);
                    }
                });
        return future.join();
    }

    private void sendVerificationEmail(EmailVerification emailVerification) {
        try {
            MimeMessage message = mailSender.createMimeMessage();
            MimeMessageHelper helper = new MimeMessageHelper(message, true);
            helper.setFrom(fromEmail);
            helper.setTo(emailVerification.email().toLowerCase());
            helper.setSubject("Your verification code");
            helper.setText("Your verification code is: " + emailVerification.verificationCode(), false);
            mailSender.send(message);
        } catch (MessagingException e) {
            log.error("Failed to send verification email to {}", emailVerification.email(), e);
        }
    }

    private String generateCode() {
        // 6-digit numeric code
        Random random = new Random();
        int num = 100000 + random.nextInt(899999);
        return String.valueOf(num);
    }
}
