package workflow

import (
	"encoding/json"
	"fmt"
	"os"
)

// LoadWorkflowFromFile loads a workflow from a JSON file
func LoadWorkflowFromFile(filename string) (*Workflow, error) {
	data, err := os.ReadFile(filename)
	if err != nil {
		return nil, fmt.Errorf("failed to read file: %w", err)
	}

	var wf Workflow
	if err := json.Unmarshal(data, &wf); err != nil {
		return nil, fmt.Errorf("failed to unmarshal workflow: %w", err)
	}

	return &wf, nil
}

// SaveWorkflowToFile saves a workflow to a JSON file
func SaveWorkflowToFile(wf *Workflow, filename string) error {
	data, err := json.MarshalIndent(wf, "", "  ")
	if err != nil {
		return fmt.Errorf("failed to marshal workflow: %w", err)
	}

	if err := os.WriteFile(filename, data, 0644); err != nil {
		return fmt.Errorf("failed to write file: %w", err)
	}

	return nil
}

// LoadWorkflowFromJSON loads a workflow from a JSON string
func LoadWorkflowFromJSON(jsonStr string) (*Workflow, error) {
	var wf Workflow
	if err := json.Unmarshal([]byte(jsonStr), &wf); err != nil {
		return nil, fmt.Errorf("failed to unmarshal workflow: %w", err)
	}

	return &wf, nil
}

// ToJSON converts a workflow to a JSON string
func (w *Workflow) ToJSON() (string, error) {
	data, err := json.MarshalIndent(w, "", "  ")
	if err != nil {
		return "", fmt.Errorf("failed to marshal workflow: %w", err)
	}
	return string(data), nil
}

// GetStepByID finds a step by its ID
func (w *Workflow) GetStepByID(stepID string) *Step {
	for i := range w.Steps {
		if w.Steps[i].ID == stepID {
			return &w.Steps[i]
		}
	}
	return nil
}

// GetStepsByType returns all steps of a specific type
func (w *Workflow) GetStepsByType(stepType StepType) []Step {
	var steps []Step
	prefix := string(stepType) + "_"

	for _, step := range w.Steps {
		if len(step.ID) > len(prefix) && step.ID[:len(prefix)] == prefix {
			steps = append(steps, step)
		}
	}

	return steps
}

// ValidateStepReferences validates that all step references (next, children, cases) exist
func (w *Workflow) ValidateStepReferences() error {
	stepIDs := make(map[string]bool)
	for _, step := range w.Steps {
		stepIDs[step.ID] = true
	}

	for _, step := range w.Steps {
		// Validate next
		if step.Next != "" && !stepIDs[step.Next] {
			return fmt.Errorf("step %s references non-existent next step: %s", step.ID, step.Next)
		}

		// Validate children
		for _, childID := range step.Children {
			if !stepIDs[childID] {
				return fmt.Errorf("step %s references non-existent child step: %s", step.ID, childID)
			}
		}

		// Validate cases
		for _, c := range step.Cases {
			if len(c) >= 2 && c[1] != "" && !stepIDs[c[1]] {
				return fmt.Errorf("step %s references non-existent case step: %s", step.ID, c[1])
			}
		}

		// Validate onError (v3.10+)
		if step.OnError != "" && !stepIDs[step.OnError] {
			return fmt.Errorf("step %s references non-existent onError step: %s", step.ID, step.OnError)
		}
	}

	return nil
}

// Clone creates a deep copy of the workflow
func (w *Workflow) Clone() (*Workflow, error) {
	data, err := json.Marshal(w)
	if err != nil {
		return nil, fmt.Errorf("failed to marshal workflow: %w", err)
	}

	var clone Workflow
	if err := json.Unmarshal(data, &clone); err != nil {
		return nil, fmt.Errorf("failed to unmarshal workflow: %w", err)
	}

	return &clone, nil
}

// GetVariableNames returns all declared variable names
func (r *Registry) GetVariableNames() ([]string, error) {
	var names []string
	for _, varDecl := range r.Vars {
		parsed, err := ParseVariableDeclaration(varDecl)
		if err != nil {
			return nil, err
		}
		names = append(names, parsed.Name)
	}
	return names, nil
}

// GetServiceNames returns all declared service names
func (r *Registry) GetServiceNames() ([]string, error) {
	var names []string
	for _, sig := range r.Services {
		parsed, err := ParseServiceSignature(sig)
		if err != nil {
			return nil, err
		}
		names = append(names, parsed.Name)
	}
	return names, nil
}

// BuildWorkflow provides a fluent builder for creating workflows
type WorkflowBuilder struct {
	workflow *Workflow
}

// NewWorkflowBuilder creates a new workflow builder
func NewWorkflowBuilder(name string) *WorkflowBuilder {
	return &WorkflowBuilder{
		workflow: &Workflow{
			Version: "3.13",
			Name:    name,
			Registry: Registry{
				Services:   []string{},
				APIs:       []APIDefinition{},
				Components: []string{},
				Vars:       []string{},
				Files: FilesRegistry{
					Inputs:    []string{},
					Artifacts: []string{},
				},
			},
			Steps: []Step{},
		},
	}
}

// AddService adds a service to the registry
func (b *WorkflowBuilder) AddService(signature string) *WorkflowBuilder {
	b.workflow.Registry.Services = append(b.workflow.Registry.Services, signature)
	return b
}

// AddAPI adds an API definition to the registry
func (b *WorkflowBuilder) AddAPI(apiDef APIDefinition) *WorkflowBuilder {
	b.workflow.Registry.APIs = append(b.workflow.Registry.APIs, apiDef)
	return b
}

// AddComponent adds a component to the registry
func (b *WorkflowBuilder) AddComponent(componentID string) *WorkflowBuilder {
	b.workflow.Registry.Components = append(b.workflow.Registry.Components, componentID)
	return b
}

// AddVar adds a variable to the registry
func (b *WorkflowBuilder) AddVar(varDecl string) *WorkflowBuilder {
	b.workflow.Registry.Vars = append(b.workflow.Registry.Vars, varDecl)
	return b
}

// AddInput adds an input file pattern
func (b *WorkflowBuilder) AddInput(pattern string) *WorkflowBuilder {
	b.workflow.Registry.Files.Inputs = append(b.workflow.Registry.Files.Inputs, pattern)
	return b
}

// AddArtifact adds an artifact file pattern
func (b *WorkflowBuilder) AddArtifact(pattern string) *WorkflowBuilder {
	b.workflow.Registry.Files.Artifacts = append(b.workflow.Registry.Files.Artifacts, pattern)
	return b
}

// AddStep adds a step to the workflow
func (b *WorkflowBuilder) AddStep(step Step) *WorkflowBuilder {
	b.workflow.Steps = append(b.workflow.Steps, step)
	return b
}

// Build returns the constructed workflow
func (b *WorkflowBuilder) Build() (*Workflow, error) {
	if err := b.workflow.Validate(); err != nil {
		return nil, err
	}
	return b.workflow, nil
}

// MustBuild returns the workflow or panics on error
func (b *WorkflowBuilder) MustBuild() *Workflow {
	wf, err := b.Build()
	if err != nil {
		panic(err)
	}
	return wf
}
