package jobs

import (
	"context"
	"log/slog"
	"time"

	"gorm.io/gorm"

	"qycw/go-server/internal/domain/commerce"
	licenseclient "qycw/go-server/internal/license"
	"qycw/go-server/internal/plugins"
)

type InstanceLifecycleWorker struct {
	db        *gorm.DB
	logger    *slog.Logger
	interval  time.Duration
	batchSize int
	plugins   *plugins.Service
	license   workerLicenseGate
}

func NewInstanceLifecycleWorker(db *gorm.DB, logger *slog.Logger, interval time.Duration, batchSize int, pluginSvc ...*plugins.Service) *InstanceLifecycleWorker {
	if interval <= 0 {
		interval = 10 * time.Minute
	}
	if batchSize <= 0 {
		batchSize = 50
	}
	var pluginsService *plugins.Service
	if len(pluginSvc) > 0 {
		pluginsService = pluginSvc[0]
	}
	return &InstanceLifecycleWorker{db: db, logger: logger, interval: interval, batchSize: batchSize, plugins: pluginsService}
}

func (w *InstanceLifecycleWorker) Run(ctx context.Context) error {
	if w.db == nil {
		if w.logger != nil {
			w.logger.Warn("instance lifecycle worker disabled: database is not configured")
		}
		<-ctx.Done()
		return nil
	}
	if w.logger != nil {
		w.logger.Info("instance lifecycle worker started", "interval", w.interval, "batch_size", w.batchSize)
	}
	if err := w.ProcessOnce(ctx); err != nil && w.logger != nil {
		w.logger.Warn("instance lifecycle worker initial scan failed", "error", err)
	}
	ticker := time.NewTicker(w.interval)
	defer ticker.Stop()
	for {
		select {
		case <-ctx.Done():
			return nil
		case <-ticker.C:
			if err := w.ProcessOnce(ctx); err != nil && w.logger != nil {
				w.logger.Warn("instance lifecycle worker scan failed", "error", err)
			}
		}
	}
}

func (w *InstanceLifecycleWorker) ProcessOnce(ctx context.Context) error {
	if err := w.license.check(); err != nil {
		return err
	}
	if w.plugins != nil {
		if err := w.license.checkFeature(licenseclient.FeaturePlugins); err != nil {
			return err
		}
	}
	if w.db == nil {
		return nil
	}
	summary, err := commerce.NewService(w.db, nil, w.logger, w.plugins).ProcessInstanceLifecycle(ctx, w.batchSize)
	if err != nil {
		return err
	}
	if w.logger != nil && (summary.AutoRenewed > 0 || summary.AutoRenewFailed > 0 || summary.Reminded > 0 || summary.Suspended > 0 || summary.Deleted > 0 || summary.Failed > 0) {
		w.logger.Info("instance lifecycle worker processed",
			"auto_renewed", summary.AutoRenewed,
			"auto_renew_failed", summary.AutoRenewFailed,
			"reminded", summary.Reminded,
			"suspended", summary.Suspended,
			"deleted", summary.Deleted,
			"failed", summary.Failed,
		)
	}
	return nil
}
