package main

import (
	"encoding/json"
	"sync"
	"time"
)

// WizardStage — какой странице wizard'а соответствует текущее состояние.
// Переходы: welcome → precheck → config → installing → done.
// Из любого можно вернуться в welcome (полный reset).
type WizardStage string

const (
	StageWelcome    WizardStage = "welcome"
	StagePrecheck   WizardStage = "precheck"
	StageConfig     WizardStage = "config"
	StageInstalling WizardStage = "installing"
	StageDone       WizardStage = "done"
	StageError      WizardStage = "error"
)

// Config — данные, которые wizard собирает на стадии config.
type Config struct {
	OrgINN     string `json:"orgInn"`     // ИНН организации
	OrgName    string `json:"orgName"`    // отображаемое имя
	AdminEmail string `json:"adminEmail"` // куда писать алерты
	LicenseKey string `json:"licenseKey"` // годовой ключ (опционально, можно пропустить)
}

// StepStatus — текущее состояние конкретного шага установки.
type StepStatus string

const (
	StepPending StepStatus = "pending"
	StepRunning StepStatus = "running"
	StepDone    StepStatus = "done"
	StepSkipped StepStatus = "skipped"
	StepFailed  StepStatus = "failed"
)

// StepState — снимок одного шага для отдачи в UI.
type StepState struct {
	ID       string     `json:"id"`
	Title    string     `json:"title"`
	Status   StepStatus `json:"status"`
	Message  string     `json:"message,omitempty"`
	Started  *time.Time `json:"started,omitempty"`
	Finished *time.Time `json:"finished,omitempty"`
}

// PrecheckResult — результат одной системной проверки на стадии precheck.
type PrecheckResult struct {
	ID      string `json:"id"`
	Title   string `json:"title"`
	OK      bool   `json:"ok"`
	Message string `json:"message,omitempty"`
}

// State — потокобезопасное состояние wizard'а. Хранит всё что нужно
// отрисовать на любой из страниц + текущий прогресс установки.
type State struct {
	mu sync.RWMutex

	artifactsDir string

	Stage    WizardStage      `json:"stage"`
	ErrorMsg string           `json:"errorMsg,omitempty"`
	Precheck []PrecheckResult `json:"precheck"`
	Config   Config           `json:"config"`
	Steps    []StepState      `json:"steps"`

	bus *eventBus
}

func newState(artifactsDir string) *State {
	return &State{
		artifactsDir: artifactsDir,
		Stage:        StageWelcome,
		Steps:        buildStepList(),
		bus:          newEventBus(),
	}
}

// Snapshot — потокобезопасная копия для GET /api/state.
func (s *State) Snapshot() State {
	s.mu.RLock()
	defer s.mu.RUnlock()
	cp := *s
	cp.Precheck = append([]PrecheckResult(nil), s.Precheck...)
	cp.Steps = append([]StepState(nil), s.Steps...)
	return cp
}

func (s *State) setStage(st WizardStage) {
	s.mu.Lock()
	s.Stage = st
	s.mu.Unlock()
	s.bus.publish(event{Type: "stage", Data: mustJSON(map[string]string{"stage": string(st)})})
}

func (s *State) setError(msg string) {
	s.mu.Lock()
	s.Stage = StageError
	s.ErrorMsg = msg
	s.mu.Unlock()
	s.bus.publish(event{Type: "error", Data: mustJSON(map[string]string{"message": msg})})
}

func (s *State) setPrecheck(items []PrecheckResult) {
	s.mu.Lock()
	s.Precheck = items
	s.mu.Unlock()
	s.bus.publish(event{Type: "precheck", Data: mustJSON(items)})
}

func (s *State) setConfig(c Config) {
	s.mu.Lock()
	s.Config = c
	s.mu.Unlock()
}

func (s *State) updateStep(id string, fn func(*StepState)) {
	s.mu.Lock()
	var snap StepState
	for i := range s.Steps {
		if s.Steps[i].ID == id {
			fn(&s.Steps[i])
			snap = s.Steps[i]
			break
		}
	}
	s.mu.Unlock()
	s.bus.publish(event{Type: "step", Data: mustJSON(snap)})
}

func mustJSON(v any) string {
	b, _ := json.Marshal(v)
	return string(b)
}
