package cloud.nstart.terravault.ordinis.notifications.channel;

import cloud.nstart.terravault.ordinis.notifications.config.NotificationsProperties;
import cloud.nstart.terravault.ordinis.notifications.event.NotificationEvent;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;
import jakarta.mail.MessagingException;
import jakarta.mail.internet.MimeMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.mail.MailException;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Component;

import java.nio.charset.StandardCharsets;
import java.time.Duration;

/**
 * SMTP-based email channel. Phase A delivery target.
 *
 * <p>Multipart text+HTML send (RFC 2387) — plain text fallback для accessibility,
 * HTML version с link styling. Per design § 8.6.
 *
 * <p>Sanitization happens upstream в {@code MessageRenderer.render()} —
 * {@code Sanitizer.forEmailHeader()} применяется ко всем dynamic params в subject.
 * Body тоже sanitized (CRLF strip preserves layout).
 *
 * <p>Per design § 5 EmailChannel:
 * <ul>
 *   <li>SMTP timeouts через {@code spring.mail.properties.mail.smtp.timeout=10000}.</li>
 *   <li>Hang >10s → {@code MailSendException} → channel returns failed.</li>
 *   <li>FAILED row не освобождает idempotency lock (conscious choice — failed =
 *       "tried, gave up", не долбим SMTP бесконечно).</li>
 * </ul>
 */
@Component
@ConditionalOnProperty(name = "ordinis.notifications.enabled", havingValue = "true", matchIfMissing = false)
// Без JavaMailSender bean (т.е. spring.mail.host не задан) ChannelKind.EMAIL
// не активируется. Это позволяет включить notifications.enabled=true для
// Express-only deploy без обязательной SMTP-конфигурации, и не вешает Spring
// boot на UnsatisfiedDependencyException когда mail starter в classpath, но
// инфра почты не подведена.
@ConditionalOnBean(JavaMailSender.class)
public class EmailChannel implements NotificationChannel {

  private static final Logger log = LoggerFactory.getLogger(EmailChannel.class);

  private final JavaMailSender mailSender;
  private final NotificationsProperties props;
  private final Timer dispatchTimer;

  public EmailChannel(
      JavaMailSender mailSender,
      NotificationsProperties props,
      MeterRegistry meterRegistry) {
    this.mailSender = mailSender;
    this.props = props;
    this.dispatchTimer = Timer.builder("nsi_notification_dispatch_seconds")
        .description("Per-channel dispatch latency")
        .tag("channel", "email")
        .publishPercentileHistogram()
        .register(meterRegistry);
  }

  @Override
  public ChannelKind kind() {
    return ChannelKind.EMAIL;
  }

  @Override
  public boolean isEnabled() {
    String from = props.getEmail().getFromAddress();
    return from != null && !from.isBlank();
  }

  @Override
  public DispatchResult dispatch(NotificationEvent event, UserRef recipient, RenderedMessage msg) {
    if (recipient.email() == null || recipient.email().isBlank()) {
      return DispatchResult.failure("recipient has no email address");
    }
    long start = System.nanoTime();
    try {
      MimeMessage mime = mailSender.createMimeMessage();
      MimeMessageHelper helper = new MimeMessageHelper(mime, true, StandardCharsets.UTF_8.name());
      helper.setFrom(props.getEmail().getFromAddress());
      helper.setTo(recipient.email());
      helper.setSubject(msg.subject());
      // For Phase A: plain text body. HTML multipart можно добавить позже
      // через помощник setText(text, html) в MimeMessageHelper.
      helper.setText(msg.body(), false);

      mailSender.send(mime);
      return DispatchResult.success();
    } catch (MailException e) {
      log.warn("Email send failed для {}: {}", recipient.email(), e.getMessage());
      return DispatchResult.failure("MailException: " + e.getMessage());
    } catch (MessagingException e) {
      log.warn("Email build failed для {}: {}", recipient.email(), e.getMessage());
      return DispatchResult.failure("MessagingException: " + e.getMessage());
    } finally {
      dispatchTimer.record(Duration.ofNanos(System.nanoTime() - start));
    }
  }
}
