package jobs

import (
	"context"
	"fmt"
	"log/slog"

	"qycw/go-server/internal/bootstrap"
	"qycw/go-server/internal/domain/commerce"
	"qycw/go-server/internal/domain/identity"
)

type TaskExecutor struct {
	app      *bootstrap.App
	logger   *slog.Logger
	identity *identity.Service
}

func NewTaskExecutor(app *bootstrap.App, logger *slog.Logger, identityService *identity.Service) *TaskExecutor {
	return &TaskExecutor{app: app, logger: logger, identity: identityService}
}

func (e *TaskExecutor) Definitions() []commerce.TaskDefinition {
	return commerce.DefaultTaskDefinitions()
}

func (e *TaskExecutor) Execute(ctx context.Context, taskKey string) (map[string]any, error) {
	if e == nil || e.app == nil || e.app.DB == nil {
		return nil, fmt.Errorf("database is not configured")
	}
	if err := newWorkerLicenseGate(e.app.LicenseEval).check(); err != nil {
		return nil, err
	}
	service := commerce.NewService(e.app.DB, e.app.Redis, e.logger, e.app.Plugins).WithIdentity(e.identity)
	switch taskKey {
	case "provision":
		worker := NewProvisionWorker(e.app.DB, e.logger, e.app.Config.ProvisionWorkerInterval, e.app.Config.ProvisionWorkerBatchSize, e.app.Config.ProvisionMaxAttempts, e.app.Plugins)
		worker.license = newWorkerLicenseGate(e.app.LicenseEval)
		if err := worker.ProcessOnce(ctx); err != nil {
			return nil, err
		}
		return map[string]any{"processed": true}, nil
	case "settlement":
		summary, err := service.SettleDueRewards(ctx, e.app.Config.SettlementWorkerBatchSize)
		return map[string]any{"orders": summary.Orders, "settlements": summary.Settlements}, err
	case "upstream_actions":
		summary, err := service.SyncPendingUpstreamActions(ctx, e.app.Config.UpstreamActionWorkerBatchSize)
		return intSummaryAny(summary), err
	case "instance_lifecycle":
		summary, err := service.ProcessInstanceLifecycle(ctx, 100)
		return map[string]any{"auto_renewed": summary.AutoRenewed, "auto_renew_failed": summary.AutoRenewFailed, "reminded": summary.Reminded, "suspended": summary.Suspended, "deleted": summary.Deleted, "failed": summary.Failed}, err
	case "agent_lifecycle_evaluate":
		return service.EvaluateAgents(ctx, 200)
	case "zjmf_stock_sync":
		return service.SyncZJMFProductStocks(ctx, 500)
	case "promotion_coupon_refund_expired":
		return service.ProcessExpiredMemberCoupons(ctx, 200)
	case "promotion_coupon_notify_expiring":
		return service.NotifyExpiringCoupons(ctx, 24, 200)
	case "verification_material_cleanup":
		if e.identity == nil {
			return nil, fmt.Errorf("identity service is not configured")
		}
		return e.identity.CleanupExpiredVerificationMaterials(ctx, 200)
	case "instance_real_data_collect":
		return service.CollectInstanceRealData(ctx, 500)
	case "recharge_maintenance":
		return service.ProcessRechargeMaintenance(ctx)
	case "cloud_node_health":
		return service.CheckCloudNodeHealth(ctx, 200)
	default:
		return nil, fmt.Errorf("unknown task: %s", taskKey)
	}
}

func intSummaryAny(summary map[string]int) map[string]any {
	out := make(map[string]any, len(summary))
	for key, value := range summary {
		out[key] = value
	}
	return out
}
