package processor

import (
	"fmt"
)

// PhaseDefinition defines a phase in the execution chain.
type PhaseDefinition struct {
	Name         string
	Dependencies []string // Names of phases that must complete before this one
}

// Orchestrator manages phase progression for any Record type.
// It is completely generic and works with any Record implementation.
type Orchestrator struct {
	phases map[string]*PhaseDefinition
	order  []string
	store  Store
}

// New creates a new phase orchestrator.
func New(store Store) *Orchestrator {
	return &Orchestrator{
		phases: make(map[string]*PhaseDefinition),
		store:  store,
	}
}

// RegisterPhase registers a phase in the orchestrator.
func (o *Orchestrator) RegisterPhase(def PhaseDefinition) error {
	if _, exists := o.phases[def.Name]; exists {
		return fmt.Errorf("phase %s already registered", def.Name)
	}
	o.phases[def.Name] = &def
	return nil
}

// SetOrder sets the execution order of phases.
func (o *Orchestrator) SetOrder(order []string) error {
	for _, phase := range order {
		if _, exists := o.phases[phase]; !exists {
			return fmt.Errorf("phase %s not registered", phase)
		}
	}
	o.order = order
	return nil
}

// CanRun checks if a phase can execute.
func (o *Orchestrator) CanRun(recordID, phaseName string) (bool, error) {
	record, err := o.store.Get(recordID)
	if err != nil {
		return false, fmt.Errorf("record not found: %w", err)
	}

	// Check if phase exists
	phaseDef, exists := o.phases[phaseName]
	if !exists {
		return false, fmt.Errorf("phase %s not registered", phaseName)
	}

	// Check if already completed
	for _, completed := range record.GetCompletedPhases() {
		if completed == phaseName {
			return false, fmt.Errorf("phase %s already completed", phaseName)
		}
	}

	// Check dependencies
	for _, dep := range phaseDef.Dependencies {
		found := false
		for _, completed := range record.GetCompletedPhases() {
			if completed == dep {
				found = true
				break
			}
		}
		if !found {
			return false, fmt.Errorf("dependency %s not completed", dep)
		}
	}

	return true, nil
}

// UpdateState atomically updates record state after phase completion.
func (o *Orchestrator) UpdateState(recordID, completedPhase string, results map[string]interface{}) error {
	record, err := o.store.Get(recordID)
	if err != nil {
		return fmt.Errorf("record not found: %w", err)
	}

	// Add to completed phases
	record.AddCompletedPhase(completedPhase)

	// Store results
	existingResults := record.GetPhaseResults()
	if existingResults == nil {
		existingResults = make(map[string]interface{})
	}
	for k, v := range results {
		existingResults[k] = v
	}
	record.SetPhaseResults(existingResults)

	// Advance to next phase
	nextPhase := o.getNextPhase(completedPhase)
	record.SetCurrentPhase(nextPhase)

	// Check if record is complete
	if nextPhase == nil && len(record.GetCompletedPhases()) == len(o.order) {
		record.SetStatus("completed")
	} else {
		record.SetStatus("processing")
	}

	return o.store.Save(record)
}

// MarkFailed marks a record as failed.
func (o *Orchestrator) MarkFailed(recordID, errorMsg string) error {
	record, err := o.store.Get(recordID)
	if err != nil {
		return fmt.Errorf("record not found: %w", err)
	}

	record.SetStatus("failed")
	record.SetErrorMessage(errorMsg)

	return o.store.Save(record)
}

// getNextPhase returns the next phase after the given one.
func (o *Orchestrator) getNextPhase(currentPhase string) *string {
	for i, phase := range o.order {
		if phase == currentPhase {
			if i+1 < len(o.order) {
				nextPhase := o.order[i+1]
				return &nextPhase
			}
			return nil
		}
	}
	return nil
}

// Get retrieves record state (read-only).
func (o *Orchestrator) Get(recordID string) (Record, error) {
	return o.store.Get(recordID)
}
