package sdlc

import (
	"fmt"
	"os"
	"time"

	"gopkg.in/yaml.v3"
)

// State represents the global SDLC state stored in .sdlc/state.yaml.
type State struct {
	Version     int            `yaml:"version" json:"version"`
	Project     ProjectState   `yaml:"project" json:"project"`
	ActiveWork  ActiveWork     `yaml:"active_work" json:"active_work"`
	Blocked     []BlockedItem  `yaml:"blocked" json:"blocked"`
	LastUpdated *time.Time     `yaml:"last_updated,omitempty" json:"last_updated,omitempty"`
	LastAction  string         `yaml:"last_action,omitempty" json:"last_action,omitempty"`
	LastActor   string         `yaml:"last_actor,omitempty" json:"last_actor,omitempty"`
	History     []HistoryEntry `yaml:"history,omitempty" json:"history,omitempty"`
}

// LoadState reads and parses .sdlc/state.yaml from the given project root.
func LoadState(root string) (*State, error) {
	path := StatePath(root)
	data, err := os.ReadFile(path)
	if err != nil {
		if os.IsNotExist(err) {
			return nil, ErrNotInitialized
		}
		return nil, fmt.Errorf("read state file: %w", err)
	}

	var s State
	if err := yaml.Unmarshal(data, &s); err != nil {
		return nil, fmt.Errorf("parse state file: %w", err)
	}
	return &s, nil
}

// Save writes the state to .sdlc/state.yaml.
func (s *State) Save(root string) error {
	now := time.Now().UTC()
	s.LastUpdated = &now

	data, err := yaml.Marshal(s)
	if err != nil {
		return fmt.Errorf("marshal state: %w", err)
	}

	path := StatePath(root)
	if err := os.WriteFile(path, data, 0o644); err != nil {
		return fmt.Errorf("write state file: %w", err)
	}
	return nil
}

// RecordAction appends a history entry and updates the last-action fields.
// The result parameter allows recording success or failure status.
func (s *State) RecordAction(action, feature, actor, result string) {
	if result == "" {
		result = "success"
	}
	entry := HistoryEntry{
		Timestamp: time.Now().UTC(),
		Action:    action,
		Feature:   feature,
		Actor:     actor,
		Result:    result,
	}
	s.History = append(s.History, entry)
	s.LastAction = action
	s.LastActor = actor
}

// AddActiveFeature adds a feature to active work if not already present.
func (s *State) AddActiveFeature(slug string, phase FeaturePhase) {
	for _, f := range s.ActiveWork.Features {
		if f.Slug == slug {
			return
		}
	}
	s.ActiveWork.Features = append(s.ActiveWork.Features, ActiveFeature{
		Slug:  slug,
		Phase: phase,
	})
}

// UpdateActiveFeature updates the phase of an active feature.
func (s *State) UpdateActiveFeature(slug string, phase FeaturePhase, branch string) {
	for i, f := range s.ActiveWork.Features {
		if f.Slug == slug {
			s.ActiveWork.Features[i].Phase = phase
			if branch != "" {
				s.ActiveWork.Features[i].Branch = branch
			}
			return
		}
	}
}

// RemoveActiveFeature removes a feature from active work.
func (s *State) RemoveActiveFeature(slug string) {
	for i, f := range s.ActiveWork.Features {
		if f.Slug == slug {
			s.ActiveWork.Features = append(s.ActiveWork.Features[:i], s.ActiveWork.Features[i+1:]...)
			return
		}
	}
}

// DefaultState returns a new State with version 1 and empty fields.
func DefaultState(projectName string) *State {
	return &State{
		Version: 1,
		Project: ProjectState{
			Name: projectName,
		},
		ActiveWork: ActiveWork{
			Features: []ActiveFeature{},
		},
		Blocked: []BlockedItem{},
		History: []HistoryEntry{},
	}
}
