package runmanage

import (
	"fmt"
	"strings"

	"github.com/tidbcloud/AgentTeam/internal/store/workflow/run"
)

const (
	defaultPageLimit     = 50
	maxPageLimit         = 100
	maxCancelReasonBytes = 2048
	ActorTypeHuman       = "human"
	ActorTypeAgent       = "agent"
)

func requiredID(name, value string) (string, error) {
	value = strings.TrimSpace(value)
	if value == "" {
		return "", invalidRequest(name + " is required")
	}
	return value, nil
}

func normalizeLimit(limit int) (int, error) {
	if limit == 0 {
		return defaultPageLimit, nil
	}
	if limit < 1 || limit > maxPageLimit {
		return 0, invalidRequest(fmt.Sprintf("limit must be between 1 and %d", maxPageLimit))
	}
	return limit, nil
}

func normalizeRunList(input ListRunsInput) (ListRunsInput, error) {
	var err error
	input.WorkspaceID, err = requiredID("workspaceId", input.WorkspaceID)
	if err != nil {
		return ListRunsInput{}, err
	}
	input.PlanID = strings.TrimSpace(input.PlanID)
	input.Status = strings.TrimSpace(input.Status)
	if input.Status != "" && !validRunStatus(input.Status) {
		return ListRunsInput{}, invalidRequest("status is not a valid Workflow Run status")
	}
	input.Limit, err = normalizeLimit(input.Limit)
	if err != nil {
		return ListRunsInput{}, err
	}
	input.Cursor = strings.TrimSpace(input.Cursor)
	return input, nil
}

func normalizeChildList(input ListChildrenInput, validStatus func(string) bool) (ListChildrenInput, error) {
	var err error
	input.WorkspaceID, err = requiredID("workspaceId", input.WorkspaceID)
	if err != nil {
		return ListChildrenInput{}, err
	}
	input.RunID, err = requiredID("runId", input.RunID)
	if err != nil {
		return ListChildrenInput{}, err
	}
	input.Status = strings.TrimSpace(input.Status)
	if input.Status != "" && !validStatus(input.Status) {
		return ListChildrenInput{}, invalidRequest("status is not valid for this Workflow Run resource")
	}
	input.Limit, err = normalizeLimit(input.Limit)
	if err != nil {
		return ListChildrenInput{}, err
	}
	input.Cursor = strings.TrimSpace(input.Cursor)
	return input, nil
}

func normalizeEventList(input ListEventsInput) (ListEventsInput, error) {
	var err error
	input.WorkspaceID, err = requiredID("workspaceId", input.WorkspaceID)
	if err != nil {
		return ListEventsInput{}, err
	}
	input.RunID, err = requiredID("runId", input.RunID)
	if err != nil {
		return ListEventsInput{}, err
	}
	input.Limit, err = normalizeLimit(input.Limit)
	if err != nil {
		return ListEventsInput{}, err
	}
	input.Cursor = strings.TrimSpace(input.Cursor)
	return input, nil
}

func normalizeCancel(input CancelInput) (CancelInput, error) {
	var err error
	input.WorkspaceID, err = requiredID("workspaceId", input.WorkspaceID)
	if err != nil {
		return CancelInput{}, err
	}
	input.RunID, err = requiredID("runId", input.RunID)
	if err != nil {
		return CancelInput{}, err
	}
	input.Reason = strings.TrimSpace(input.Reason)
	if input.Reason == "" {
		input.Reason = "canceled"
	}
	if len([]byte(input.Reason)) > maxCancelReasonBytes {
		return CancelInput{}, invalidRequest(fmt.Sprintf("reason must not exceed %d bytes", maxCancelReasonBytes))
	}
	input.Actor.Type = strings.TrimSpace(input.Actor.Type)
	input.Actor.ID = strings.TrimSpace(input.Actor.ID)
	input.Actor.MemberID = strings.TrimSpace(input.Actor.MemberID)
	if (input.Actor.Type != ActorTypeHuman && input.Actor.Type != ActorTypeAgent) ||
		input.Actor.ID == "" || input.Actor.MemberID == "" {
		return CancelInput{}, invalidRequest("authenticated actor type, id, and memberId are required")
	}
	return input, nil
}

func validRunStatus(status string) bool {
	switch status {
	case run.RunStatusQueued, run.RunStatusRunning, run.RunStatusWaiting,
		run.RunStatusSucceeded, run.RunStatusFailed, run.RunStatusCanceled:
		return true
	default:
		return false
	}
}

func validActivationStatus(status string) bool {
	switch status {
	case run.ActivationStatusReady, run.ActivationStatusWaiting,
		run.ActivationStatusSucceeded, run.ActivationStatusFailed,
		run.ActivationStatusCanceled:
		return true
	default:
		return false
	}
}

func validEffectStatus(status string) bool {
	switch status {
	case run.EffectStatusPending, run.EffectStatusDispatching,
		run.EffectStatusDelivered, run.EffectStatusAwaiting,
		run.EffectStatusQueuedForAgent, run.EffectStatusWaitingForResponder,
		run.EffectStatusCompleted, run.EffectStatusFailed,
		run.EffectStatusCanceled:
		return true
	default:
		return false
	}
}
