package authoring

import (
	"fmt"

	"github.com/nomadcode/nomadcode-core/internal/projectsync"
	"github.com/nomadcode/nomadcode-core/internal/roadmapsync"
)

// DecisionInput contains the outputs and signals from the authoring process,
// used to determine the final authoring run state.
type DecisionInput struct {
	BridgeSuccess  bool
	DevelopMatch   roadmapsync.ProjectionCandidate
	ExitCode       *int
	PushFailed     bool
	DirtyWorkspace bool
	Conflict       bool
}

// Decision represents the state, reason, and failure category determined by the result helper.
type Decision struct {
	State           string // "in_progress", "succeeded", "failed"
	Reason          string
	FailureCategory string // "bridge_failed", "exit_code", "push_failed", "dirty_workspace", "conflict"
}

// DecideAuthoringResult evaluates the authoring run inputs and signals to classify
// the task outcome as succeeded, failed (with specific category), or in_progress.
func DecideAuthoringResult(in DecisionInput) Decision {
	if !in.BridgeSuccess {
		return Decision{
			State:           "failed",
			Reason:          "model bridge response failed",
			FailureCategory: "bridge_failed",
		}
	}

	if in.ExitCode != nil && *in.ExitCode != 0 {
		return Decision{
			State:           "failed",
			Reason:          fmt.Sprintf("agent process exited with non-zero code %d", *in.ExitCode),
			FailureCategory: "exit_code",
		}
	}

	if in.PushFailed {
		return Decision{
			State:           "failed",
			Reason:          "git push to develop branch failed",
			FailureCategory: "push_failed",
		}
	}

	if in.DirtyWorkspace {
		return Decision{
			State:           "failed",
			Reason:          "workspace contains dirty changes",
			FailureCategory: "dirty_workspace",
		}
	}

	if in.Conflict {
		return Decision{
			State:           "failed",
			Reason:          "git merge conflict detected",
			FailureCategory: "conflict",
		}
	}

	if in.DevelopMatch.Ready {
		reason := in.DevelopMatch.Reason
		if reason == "" {
			reason = "pushed develop milestone matched expected identity"
		}
		return Decision{
			State:  "succeeded",
			Reason: reason,
		}
	}

	reason := in.DevelopMatch.Reason
	if reason == "" {
		reason = "waiting for pushed develop milestone match"
	}
	return Decision{
		State:  "in_progress",
		Reason: reason,
	}
}

// SlotStateForAuthoringOutcome maps terminal authoring outcomes to the slot
// state the scheduler should persist. Non-terminal decisions are not applied.
func SlotStateForAuthoringOutcome(decision Decision) (projectsync.SlotState, bool) {
	switch decision.State {
	case "succeeded":
		return projectsync.SlotStateAvailable, true
	case "failed":
		switch decision.FailureCategory {
		case "dirty_workspace", "conflict", "push_failed":
			return projectsync.SlotStateDirty, true
		default:
			return projectsync.SlotStateError, true
		}
	default:
		return "", false
	}
}
