package routing

import (
	"fmt"

	"github.com/rockliang/poimen/workflows/pkg/db"
)

// CanvasConverter converts visual canvas to executable WorkflowSpec
type CanvasConverter struct {
	validator *CanvasValidator
}

// NewCanvasConverter creates a converter
func NewCanvasConverter() *CanvasConverter {
	return &CanvasConverter{
		validator: NewCanvasValidator(),
	}
}

// CanvasToWorkflowSpec converts canvas to WorkflowSpec
func (cc *CanvasConverter) CanvasToWorkflowSpec(canvas *db.Canvas) (*WorkflowSpec, error) {
	// Validate first
	if err := cc.validator.ValidateCanvas(canvas); err != nil {
		return nil, fmt.Errorf("canvas validation failed: %w", err)
	}

	// Get topological order
	sortedNodes, err := cc.validator.TopoSort(canvas.Nodes, canvas.Edges)
	if err != nil {
		return nil, fmt.Errorf("topological sort failed: %w", err)
	}

	// Build states from sorted nodes
	states := []State{}
	nodeToState := make(map[string]int) // node ID to state index

	for i, node := range sortedNodes {
		state := cc.nodeToState(node, canvas.Edges)
		states = append(states, state)
		nodeToState[node.ID] = i
	}

	// Wire up transitions
	for i, node := range sortedNodes {
		outgoing := cc.getOutgoingEdges(node.ID, canvas.Edges)

		if len(outgoing) == 0 {
			// Last state - no transitions
			continue
		}

		if len(outgoing) == 1 {
			// Single outgoing edge
			targetNode := outgoing[0]
			targetIdx := nodeToState[targetNode]
			if targetIdx > i {
				states[i].Next = states[targetIdx].Name
			}
		} else {
			// Multiple outgoing edges - parallel
			states[i].Type = "Parallel"
			branches := []interface{}{}
			for _, targetNode := range outgoing {
				branches = append(branches, map[string]string{
					"state": states[nodeToState[targetNode]].Name,
				})
			}
			if states[i].Branches == nil {
				states[i].Branches = branches
			}
		}
	}

	spec := &WorkflowSpec{
		Name:   canvas.Name,
		Input:  map[string]interface{}{},
		States: states,
	}

	return spec, nil
}

// nodeToState converts a canvas node to a workflow state
func (cc *CanvasConverter) nodeToState(node db.WorkflowNode, edges []db.WorkflowEdge) State {
	// Map node type to activity name
	activityName := cc.mapActivityType(node.Type)

	state := State{
		Name:       node.ID,
		Type:       TaskActivity,
		Activity:   activityName,
		Retry:      &RetryPolicy{MaxAttempts: 3, BackoffSeconds: 2},
		Timeout:    "300s",
		Parameters: node.Data,
	}

	return state
}

// mapActivityType maps canvas activity type to Poimen activity
func (cc *CanvasConverter) mapActivityType(canvasType string) string {
	typeMap := map[string]string{
		"clone-repo":          "CloneRepoActivity",
		"analyze-code":        "AnalyzeCodeActivity",
		"security-scan":       "SecurityScanActivity",
		"generate-report":     "GenerateReportActivity",
		"deployment-precheck": "DeploymentPreCheckActivity",
		"notify-status":       "NotifyStatusActivity",
		"approve-workflow":    "ApproveWorkflowActivity",
		"archive-results":     "ArchiveResultsActivity",
		"retrieve-memory":     "RetrieveMemoryActivity",
		"assume-role":         "AssumeRoleActivity",
		"llm-inference":       "LLMInferenceActivity",
		"llm-batch-inference": "LLMBatchInferenceActivity",
		"canvas-reasoner":     "CanvasReasonerActivity",
	}

	if mapped, ok := typeMap[canvasType]; ok {
		return mapped
	}

	return canvasType // fallback to type as-is
}

// getOutgoingEdges returns target node IDs for a given source node
func (cc *CanvasConverter) getOutgoingEdges(nodeID string, edges []db.WorkflowEdge) []string {
	targets := []string{}
	seen := make(map[string]bool)

	for _, edge := range edges {
		if edge.Source == nodeID && !seen[edge.Target] {
			targets = append(targets, edge.Target)
			seen[edge.Target] = true
		}
	}

	return targets
}

// CanvasToExecutionPlan converts canvas to sequential activity list
func (cc *CanvasConverter) CanvasToExecutionPlan(canvas *db.Canvas) ([]ExecutionStep, error) {
	// Validate first
	if err := cc.validator.ValidateCanvas(canvas); err != nil {
		return nil, fmt.Errorf("canvas validation failed: %w", err)
	}

	// Get topological order
	sortedNodes, err := cc.validator.TopoSort(canvas.Nodes, canvas.Edges)
	if err != nil {
		return nil, fmt.Errorf("topological sort failed: %w", err)
	}

	steps := []ExecutionStep{}
	for i, node := range sortedNodes {
		step := ExecutionStep{
			Index:        i,
			NodeID:       node.ID,
			ActivityName: cc.mapActivityType(node.Type),
			Label:        node.Label,
			Parameters:   node.Data,
			Timeout:      "300s",
		}
		steps = append(steps, step)
	}

	return steps, nil
}

// ExecutionStep represents one activity in execution plan
type ExecutionStep struct {
	Index        int                   `json:"index"`
	NodeID       string                `json:"node_id"`
	ActivityName string                `json:"activity_name"`
	Label        string                `json:"label"`
	Parameters   map[string]interface{} `json:"parameters"`
	Timeout      string                `json:"timeout"`
	DependsOn    []int                 `json:"depends_on,omitempty"` // Indices of predecessor steps
}
