package mailrelay

import (
	"log"
	"sync"
)

// Lifecycle owns the shim's start/stop so the global app-email toggle can take effect
// at runtime without a controller restart. The shim listens ONLY when app-email is
// globally ON (Part 1: "start listeners only when hub.enabled and global app-email ON").
// Apply is idempotent: enabling when already up (or disabling when already down) is a
// no-op.
type Lifecycle struct {
	mu      sync.Mutex
	opts    Options
	srv     *Server
	logger  *log.Logger
	stopped bool // Close was called; further Apply(true) is refused (shutdown)
}

// NewLifecycle prepares (but does not start) a shim from the given options.
func NewLifecycle(opts Options) *Lifecycle {
	lg := opts.Logger
	if lg == nil {
		lg = log.Default()
	}
	return &Lifecycle{opts: opts, logger: lg}
}

// Apply reconciles the shim's running state with the desired toggle value. It returns
// an error only if a requested START failed (a stop never errors meaningfully).
func (l *Lifecycle) Apply(enabled bool) error {
	l.mu.Lock()
	defer l.mu.Unlock()
	if l.stopped {
		return nil
	}
	if enabled {
		if l.srv != nil {
			return nil // already running
		}
		srv, err := New(l.opts)
		if err != nil {
			return err
		}
		if err := srv.Start(); err != nil {
			return err
		}
		l.srv = srv
		l.logger.Printf("[INFO] [mailrelay] app-email shim ON (host=%s plain=%s tls=%s)",
			l.opts.ServiceName, srv.PlainAddr(), srv.TLSAddr())
		return nil
	}
	// disabled → stop if running
	if l.srv != nil {
		_ = l.srv.Close()
		l.srv = nil
		l.logger.Printf("[INFO] [mailrelay] app-email shim OFF")
	}
	return nil
}

// Running reports whether the shim is currently listening.
func (l *Lifecycle) Running() bool {
	l.mu.Lock()
	defer l.mu.Unlock()
	return l.srv != nil
}

// Close stops the shim permanently (shutdown). Idempotent.
func (l *Lifecycle) Close() {
	l.mu.Lock()
	defer l.mu.Unlock()
	l.stopped = true
	if l.srv != nil {
		_ = l.srv.Close()
		l.srv = nil
	}
}
