package taskdebug

import (
	"context"
	"devops/agent/script"
	"devops/agent/tasks"
	"devops/server/apps/task"
	"fmt"
	"strings"
	"time"
)

const (
	TASK_NAME = "task_debug"
)

func init() {
	tasks.RegisterTaskRunner(TASK_NAME, &TaskDebugRunner{})
}

// 实现一个 task_debug 任务
type TaskDebugRunner struct{}

func (t *TaskDebugRunner) Run(ctx context.Context, spec *tasks.RunTaskRequest) (*script.ExecutionResult, error) {
	// 直接使用单元测试的上下文, 方便取消
	req := script.NewExecuteScriptRequest("task_debug.sh", []string{})
	req.SetWorkDir(spec.WorkDir)
	req.SetTimeout(spec.GetTimeout())
	req.SetDebugScript(true)
	req.SetLogFile("stdout.txt")

	// Task的日志，后面会通过Websocket 实时上报给Api Server 右API Server进行日志的实时展示
	// req.SetLogCallback(func(s string) {
	// 	fmt.Print(s)
	// })

	// 添加输入参数
	for k, v := range spec.InputParams {
		req.SetEnv(k, v)
	}
	return script.ExecuteScript(ctx, req)
}

// MapExecutionResultToTask updates a Task with execution results
func MapExecutionResultToTask(task *task.Task, result *script.ExecutionResult) {
	if task == nil || result == nil {
		return
	}

	// Update TaskStatus fields from ExecutionResult
	task.TaskStatus = convertExecutionResultToStatus(result)

	// Optionally update some TaskSpec fields if needed
	// For example, if you want to store output params in the task spec extras
	if len(result.OutputParams) > 0 && task.TaskSpec.Extras == nil {
		task.TaskSpec.Extras = make(map[string]string)
	}
	for k, v := range result.OutputParams {
		task.TaskSpec.Extras["output_"+k] = v
	}
}

// convertExecutionResultToStatus converts ExecutionResult to TaskStatus
func convertExecutionResultToStatus(result *script.ExecutionResult) *task.TaskStatus {
	status := &task.TaskStatus{
		Status:   mapSuccessToStatus(result.Success, result.Skipped),
		Message:  getMessage(result),
		Detail:   getDetail(result),
		StartAt:  &result.StartTime,
		EndAt:    getEndTime(result),
		UpdateAt: time.Now(),
		Output:   result.OutputParams,
		Extras:   make(map[string]string),
	}

	// Add file contents to extras if present
	if len(result.FileContents) > 0 {
		for k, v := range result.FileContents {
			status.Extras["file_"+k] = v
		}
	}

	// Add command execution details
	if result.Command != "" {
		status.Extras["executed_command"] = result.Command
	}

	if result.ExitCode != 0 {
		status.Extras["exit_code"] = fmt.Sprintf("%d", result.ExitCode)
	}

	if result.Duration > 0 {
		status.Extras["duration"] = result.Duration.String()
	}

	return status
}

// mapSuccessToStatus maps execution result success/skipped to task status
func mapSuccessToStatus(success bool, skipped bool) task.STATUS {
	if skipped {
		return task.STATUS_SKIP
	}
	if success {
		return task.STATUS_SUCCESS
	}
	return task.STATUS_FAILED
}

// getMessage combines error and message from execution result
func getMessage(result *script.ExecutionResult) string {
	if result.Error != "" {
		return result.Error
	}
	return result.Message
}

// getDetail creates a detailed message from execution result
func getDetail(result *script.ExecutionResult) string {
	var details []string

	if result.Command != "" {
		details = append(details, fmt.Sprintf("Command: %s", result.Command))
	}

	if result.ExitCode != 0 {
		details = append(details, fmt.Sprintf("Exit Code: %d", result.ExitCode))
	}

	if result.Duration > 0 {
		details = append(details, fmt.Sprintf("Duration: %v", result.Duration))
	}

	if result.Error != "" && result.Error != result.Message {
		details = append(details, fmt.Sprintf("Error: %s", result.Error))
	}

	if result.Message != "" && result.Message != result.Error {
		details = append(details, fmt.Sprintf("Message: %s", result.Message))
	}

	return strings.Join(details, "\n")
}

// getEndTime returns the end time or current time if nil
func getEndTime(result *script.ExecutionResult) time.Time {
	if result.EndTime != nil {
		return *result.EndTime
	}
	return time.Now()
}
