package runtimedeploy

import (
	"context"
	"encoding/json"
	"fmt"
	"strings"
	"time"

	runtimedeploytaskrepo "github.com/codex-k8s/kodex/services/internal/control-plane/internal/domain/repository/runtimedeploytask"
	querytypes "github.com/codex-k8s/kodex/services/internal/control-plane/internal/domain/types/query"
)

const maxRuntimeDeployTaskLogMessageLength = 4000

func (s *Service) appendTaskLogBestEffort(ctx context.Context, runID string, stage string, level string, message string) {
	if s == nil || s.tasks == nil {
		return
	}
	runID = strings.TrimSpace(runID)
	if runID == "" {
		return
	}
	message = strings.TrimSpace(message)
	if message == "" {
		return
	}
	if len(message) > maxRuntimeDeployTaskLogMessageLength {
		message = message[:maxRuntimeDeployTaskLogMessageLength]
	}
	if err := s.tasks.AppendLog(ctx, runtimedeploytaskrepo.AppendLogParams{
		RunID:    runID,
		Stage:    strings.TrimSpace(stage),
		Level:    strings.TrimSpace(level),
		Message:  message,
		MaxLines: 300,
	}); err != nil {
		s.logger.Warn("append runtime deploy task log failed", "run_id", runID, "stage", stage, "level", level, "err", err)
	}
	if strings.EqualFold(strings.TrimSpace(level), "error") && s.runtimeErr != nil {
		source := "control-plane.runtime-deploy"
		if stageToken := strings.TrimSpace(stage); stageToken != "" {
			source += "." + stageToken
		}
		details, _ := json.Marshal(map[string]string{
			"channel": "runtime_deploy_task_log",
			"stage":   strings.TrimSpace(stage),
		})
		s.runtimeErr.RecordBestEffort(ctx, querytypes.RuntimeErrorRecordParams{
			Source:      source,
			Level:       "error",
			Message:     message,
			DetailsJSON: details,
			RunID:       runID,
		})
	}
}

func (s *Service) waitForJobCompletionWithFailureLogs(
	ctx context.Context,
	namespace string,
	jobName string,
	timeout time.Duration,
	runID string,
	stage string,
	waitErrorPrefix string,
	failureLogsPrefix string,
) error {
	if err := s.k8s.WaitForJobComplete(ctx, namespace, jobName, timeout); err != nil {
		jobLogs, logsErr := s.k8s.GetJobLogs(ctx, namespace, jobName, s.cfg.KanikoJobLogTailLines)
		if logsErr == nil && strings.TrimSpace(jobLogs) != "" {
			s.appendTaskLogBestEffort(ctx, runID, stage, "error", failureLogsPrefix+"\n"+jobLogs)
			return fmt.Errorf("%s %s: %w; logs: %s", waitErrorPrefix, jobName, err, trimLogForError(jobLogs))
		}
		return fmt.Errorf("%s %s: %w", waitErrorPrefix, jobName, err)
	}
	return nil
}
