package main

import (
	"fmt"
	"time"
)

// Step — описание одного шага установки. Run выполняет шаг, может
// проверить idempotency и вернуть Skipped. Логи прокидываются через
// log-функцию, которая публикует event в SSE.
type Step struct {
	ID    string
	Title string
	Run   func(s *State, log func(string)) (StepStatus, error)
}

// buildStepList — фиксированный порядок шагов установки. Соответствует
// install-validata.sh + установка bj-server/crypto-service/ИШ. Меняется
// атомарно (если что-то добавляется — добавляем сюда).
func buildStepList() []StepState {
	steps := allSteps()
	out := make([]StepState, len(steps))
	for i, s := range steps {
		out[i] = StepState{ID: s.ID, Title: s.Title, Status: StepPending}
	}
	return out
}

func allSteps() []Step {
	return []Step{
		{ID: "deps", Title: "Установка системных зависимостей", Run: stepInstallDeps},
		{ID: "validata-deb", Title: "Установка пакетов Валидаты (zpki + zsdk)", Run: stepInstallValidataDebs},
		{ID: "execstack", Title: "execstack -c libvdcsp.so", Run: stepExecstack},
		{ID: "bj-user", Title: "Создание пользователя bj и каталогов", Run: stepCreateBJUser},
		{ID: "pcscd-dropin", Title: "Настройка pcscd (always-on)", Run: stepPcscdDropin},
		{ID: "bj-crypto-dropins", Title: "Drop-ins для bj-crypto sandbox", Run: stepBJCryptoDropins},
		{ID: "bj-server-dropin", Title: "Drop-in для bj-server", Run: stepBJServerDropin},
		{ID: "spki-ini", Title: "Создание spki.ini", Run: stepSPKIIni},
		{ID: "pki1-prep", Title: "Подготовка pki1.conf для bj", Run: stepPKI1Prep},
		{ID: "usb-mount", Title: "Авто-mount USB через udev + systemd", Run: stepUSBMount},
		{ID: "bj-server-binary", Title: "Установка bj-server бинаря в /opt/bj/", Run: stepInstallBJServer},
		{ID: "crypto-jar", Title: "Установка crypto-service.jar", Run: stepInstallCryptoJar},
		{ID: "systemd-units", Title: "systemd unit bj-crypto.service + bj-server.service", Run: stepSystemdUnits},
		{ID: "ish-install", Title: "Установка ИШ НРД (если есть .deb)", Run: stepInstallISH},
		{ID: "save-config", Title: "Сохранение setup.json", Run: stepSaveConfig},
		{ID: "systemd-start", Title: "Запуск сервисов (pcscd, bj-crypto, bj-server)", Run: stepStartServices},
		{ID: "health", Title: "Финальный health-check", Run: stepHealthCheck},
	}
}

// runInstallation — основной цикл установки. Перебирает шаги, обновляет
// статусы через State, прокидывает логи в SSE. Останавливается при первой
// ошибке (UI покажет какой шаг + сообщение).
func runInstallation(s *State) error {
	steps := allSteps()
	for _, step := range steps {
		now := time.Now()
		s.updateStep(step.ID, func(ss *StepState) {
			ss.Status = StepRunning
			ss.Started = &now
			ss.Message = ""
		})

		logFn := func(line string) {
			s.updateStep(step.ID, func(ss *StepState) {
				ss.Message = line
			})
		}

		status, err := step.Run(s, logFn)
		finished := time.Now()
		s.updateStep(step.ID, func(ss *StepState) {
			ss.Status = status
			ss.Finished = &finished
			if err != nil {
				ss.Message = err.Error()
			}
		})
		if err != nil {
			return fmt.Errorf("шаг %q: %w", step.Title, err)
		}
	}
	return nil
}
