package runtime

import (
	"context"
	"errors"

	"galaxy/backend/internal/dockerclient"

	"go.uber.org/zap"
)

// publishStartConfigInvalid emits the `runtime.start_config_invalid`
// admin notification for a pre-Run validation failure on the start /
// patch path. The OperationLog supplies the idempotency key so the
// catalog UNIQUE(kind, idempotency_key) constraint deduplicates a
// repeated retry on the same operation row.
func (s *Service) publishStartConfigInvalid(ctx context.Context, op OperationLog, reason string) {
	s.publishRuntimeEvent(ctx, "runtime.start_config_invalid", op, map[string]any{
		"game_id": op.GameID.String(),
		"reason":  reason,
	})
}

// publishStartFailure emits either `runtime.image_pull_failed` or
// `runtime.container_start_failed` depending on whether the Docker
// daemon reported a pull-stage error. The two kinds carry the catalog
// payload from `backend/README.md` §10.
func (s *Service) publishStartFailure(ctx context.Context, op OperationLog, imageRef string, runErr error) {
	if errors.Is(runErr, dockerclient.ErrImagePullFailed) {
		s.publishRuntimeEvent(ctx, "runtime.image_pull_failed", op, map[string]any{
			"game_id":   op.GameID.String(),
			"image_ref": imageRef,
		})
		return
	}
	s.publishRuntimeEvent(ctx, "runtime.container_start_failed", op, map[string]any{
		"game_id": op.GameID.String(),
	})
}

// publishRuntimeEvent threads the publisher call through the package
// logger so a misconfigured publisher cannot silently drop events.
func (s *Service) publishRuntimeEvent(ctx context.Context, kind string, op OperationLog, payload map[string]any) {
	if s.deps.Notification == nil {
		return
	}
	idempotencyKey := kind + ":" + op.GameID.String() + ":" + op.OperationID.String()
	if err := s.deps.Notification.PublishRuntimeEvent(ctx, kind, idempotencyKey, payload); err != nil {
		s.deps.Logger.Warn("runtime notification publish failed",
			zap.String("kind", kind),
			zap.String("idempotency_key", idempotencyKey),
			zap.Error(err),
		)
	}
}
