package de.cannamanage.service;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import jakarta.mail.MessagingException;
import jakarta.mail.internet.MimeMessage;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

/**
 * Email service for sending transactional and notification emails via IONOS SMTP.
 * Supports:
 * - Staff invite emails
 * - Notification digest emails
 * - Event reminder emails
 * - Info board update emails
 * 
 * Rate limiting: max N emails per minute (configurable via cannamanage.mail.rate-limit).
 */
@Slf4j
@Service
public class EmailService {

    private final JavaMailSender mailSender;
    private final String baseUrl;
    private final String fromAddress;
    private final String replyToAddress;
    private final int rateLimit;

    // Simple rate limiter: track sends per minute window
    private final AtomicInteger sendCount = new AtomicInteger(0);
    private final AtomicLong windowStart = new AtomicLong(System.currentTimeMillis());

    public EmailService(JavaMailSender mailSender,
                        @Value("${app.base-url:http://localhost:8080}") String baseUrl,
                        @Value("${cannamanage.mail.from:noreply@cannamanage.plate-software.de}") String fromAddress,
                        @Value("${cannamanage.mail.reply-to:support@cannamanage.plate-software.de}") String replyToAddress,
                        @Value("${cannamanage.mail.rate-limit:50}") int rateLimit) {
        this.mailSender = mailSender;
        this.baseUrl = baseUrl;
        this.fromAddress = fromAddress;
        this.replyToAddress = replyToAddress;
        this.rateLimit = rateLimit;
    }

    /**
     * Sends an invite email to a new staff member with a link to set their password.
     */
    public void sendInviteEmail(String recipientEmail, String displayName,
                                String clubName, String token) {
        String setPasswordUrl = baseUrl + "/auth/set-password?token=" + token;

        String body = String.format("""
                Hallo %s,

                Du wurdest als Mitarbeiter/in beim Anbauverein "%s" eingeladen.

                Bitte klicke auf den folgenden Link, um dein Passwort festzulegen und deinen Account zu aktivieren:

                %s

                Dieser Link ist 72 Stunden gültig.

                Falls du diese Einladung nicht erwartet hast, kannst du diese E-Mail ignorieren.

                Viele Grüße,
                Dein CannaManage-Team
                """, displayName, clubName, setPasswordUrl);

        sendPlainTextEmail(recipientEmail, "Einladung: " + clubName + " — Account aktivieren", body);
    }

    /**
     * Sends a notification email (broadcast or targeted).
     */
    @Async
    public void sendNotificationEmail(String recipientEmail, String recipientName,
                                      String title, String message, String actionLink) {
        String body = String.format("""
                Hallo %s,

                Du hast eine neue Benachrichtigung:

                %s
                ─────────────────────────────
                %s

                %s

                ─────────────────────────────
                Du erhältst diese E-Mail, weil du E-Mail-Benachrichtigungen aktiviert hast.
                Einstellungen ändern: %s/portal/profile

                CannaManage — Deine Vereinsverwaltung
                """,
                recipientName,
                title,
                message,
                actionLink != null ? "Zum Beitrag: " + baseUrl + actionLink : "",
                baseUrl);

        sendPlainTextEmail(recipientEmail, "CannaManage: " + title, body);
    }

    /**
     * Sends an event reminder email.
     */
    @Async
    public void sendEventReminderEmail(String recipientEmail, String recipientName,
                                       String eventTitle, String eventDate, String eventLocation) {
        String body = String.format("""
                Hallo %s,

                Erinnerung: Morgen findet folgende Veranstaltung statt:

                📅 %s
                🕐 %s
                📍 %s

                Wir freuen uns auf deine Teilnahme!

                ─────────────────────────────
                Du erhältst diese E-Mail, weil du für diese Veranstaltung zugesagt hast.
                Einstellungen ändern: %s/portal/profile

                CannaManage — Deine Vereinsverwaltung
                """,
                recipientName, eventTitle, eventDate,
                eventLocation != null ? eventLocation : "Wird noch bekanntgegeben",
                baseUrl);

        sendPlainTextEmail(recipientEmail, "Erinnerung: " + eventTitle + " — Morgen!", body);
    }

    /**
     * Sends an info board update email.
     */
    @Async
    public void sendInfoBoardEmail(String recipientEmail, String recipientName,
                                   String postTitle, String category) {
        String body = String.format("""
                Hallo %s,

                Es gibt einen neuen Beitrag im Schwarzen Brett:

                📌 %s
                Kategorie: %s

                Zum Beitrag: %s/portal/info-board

                ─────────────────────────────
                Du erhältst diese E-Mail, weil du E-Mail-Benachrichtigungen für das Schwarze Brett aktiviert hast.
                Einstellungen ändern: %s/portal/profile

                CannaManage — Deine Vereinsverwaltung
                """,
                recipientName, postTitle, category, baseUrl, baseUrl);

        sendPlainTextEmail(recipientEmail, "Schwarzes Brett: " + postTitle, body);
    }

    /**
     * Send a batch of notification emails with rate limiting.
     * Emails are sent up to the rate limit per minute. Excess emails are delayed.
     */
    @Async
    public void sendBatchNotificationEmails(List<EmailRecipient> recipients, String title,
                                            String message, String actionLink) {
        for (int i = 0; i < recipients.size(); i++) {
            checkRateLimit();
            EmailRecipient recipient = recipients.get(i);
            try {
                sendNotificationEmail(recipient.email(), recipient.name(), title, message, actionLink);
            } catch (Exception e) {
                log.warn("Failed to send notification email to {}: {}", recipient.email(), e.getMessage());
            }
        }
    }

    /**
     * Get the configured FROM address. Used by CustomMailDomainService to override for Enterprise clubs.
     */
    public String getFromAddress() {
        return fromAddress;
    }

    /**
     * Send a plain text email with rate limiting.
     */
    private void sendPlainTextEmail(String to, String subject, String body) {
        checkRateLimit();

        SimpleMailMessage message = new SimpleMailMessage();
        message.setFrom(fromAddress);
        message.setReplyTo(replyToAddress);
        message.setTo(to);
        message.setSubject(subject);
        message.setText(body);

        try {
            mailSender.send(message);
            log.debug("Email sent to {} — subject: {}", to, subject);
        } catch (Exception e) {
            log.error("Failed to send email to {}: {}", to, e.getMessage());
            throw new RuntimeException("Failed to send email", e);
        }
    }

    /**
     * Send email with a custom FROM address (for Enterprise tier verified domains).
     */
    public void sendWithCustomFrom(String customFrom, String to, String subject, String body) {
        checkRateLimit();

        try {
            MimeMessage mimeMessage = mailSender.createMimeMessage();
            MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, false, "UTF-8");
            helper.setFrom(customFrom);
            helper.setReplyTo(customFrom);
            helper.setTo(to);
            helper.setSubject(subject);
            helper.setText(body);

            mailSender.send(mimeMessage);
            log.debug("Email sent from {} to {} — subject: {}", customFrom, to, subject);
        } catch (MessagingException e) {
            log.error("Failed to send email with custom FROM {} to {}: {}", customFrom, to, e.getMessage());
            throw new RuntimeException("Failed to send email with custom FROM", e);
        }
    }

    /**
     * Simple rate limiter: max N emails per 60-second window.
     * Blocks the current thread if limit is reached until the window resets.
     */
    private void checkRateLimit() {
        long now = System.currentTimeMillis();
        long windowStartMs = windowStart.get();

        // Reset window if >60 seconds have passed
        if (now - windowStartMs > 60_000) {
            windowStart.set(now);
            sendCount.set(0);
        }

        int currentCount = sendCount.incrementAndGet();
        if (currentCount > rateLimit) {
            long waitMs = 60_000 - (now - windowStart.get());
            if (waitMs > 0) {
                log.info("Email rate limit reached ({}/min), waiting {}ms", rateLimit, waitMs);
                try {
                    Thread.sleep(waitMs);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
                windowStart.set(System.currentTimeMillis());
                sendCount.set(1);
            }
        }
    }

    /**
     * Simple record for batch email recipients.
     */
    public record EmailRecipient(String email, String name) {}
}
