package main

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"syscall"
)

// runPrechecks — все системные проверки на стадии "Проверка системы".
// Возвращает срез результатов, по каждому видно ✓/✗ + объяснение.
//
// Ничего не модифицирует — просто читает /etc/os-release, проверяет
// наличие нужных бинарей, права root, свободное место, артефакты в
// artifactsDir и т.п. UI отрисовывает таблицей.
func runPrechecks(artifactsDir string) []PrecheckResult {
	var out []PrecheckResult

	out = append(out, checkRoot())
	out = append(out, checkArch())
	out = append(out, checkDistro())
	out = append(out, checkAptAvailable())
	out = append(out, checkSystemd())
	out = append(out, checkDiskSpace())
	out = append(out, checkArtifacts(artifactsDir))

	return out
}

func checkRoot() PrecheckResult {
	if os.Geteuid() == 0 {
		return PrecheckResult{ID: "root", Title: "Запуск от root", OK: true}
	}
	return PrecheckResult{ID: "root", Title: "Запуск от root", OK: false, Message: "Требуется sudo"}
}

func checkArch() PrecheckResult {
	if runtime.GOARCH == "amd64" {
		return PrecheckResult{ID: "arch", Title: "Архитектура amd64", OK: true, Message: runtime.GOARCH}
	}
	return PrecheckResult{ID: "arch", Title: "Архитектура amd64", OK: false, Message: "Валидата собрана только под amd64, у вас " + runtime.GOARCH}
}

func checkDistro() PrecheckResult {
	id, pretty := readOSRelease()
	switch id {
	case "debian", "astra":
		return PrecheckResult{ID: "distro", Title: "Поддерживаемая ОС", OK: true, Message: pretty}
	case "ubuntu":
		return PrecheckResult{ID: "distro", Title: "Поддерживаемая ОС", OK: true, Message: pretty + " (поддерживается на свой страх)"}
	default:
		return PrecheckResult{ID: "distro", Title: "Поддерживаемая ОС", OK: false, Message: "ОС не в списке поддерживаемых: " + pretty}
	}
}

func checkAptAvailable() PrecheckResult {
	if _, err := exec.LookPath("apt-get"); err != nil {
		return PrecheckResult{ID: "apt", Title: "Доступен apt-get", OK: false, Message: "apt-get не найден — это не Debian-семейство"}
	}
	return PrecheckResult{ID: "apt", Title: "Доступен apt-get", OK: true}
}

func checkSystemd() PrecheckResult {
	if _, err := os.Stat("/run/systemd/system"); err != nil {
		return PrecheckResult{ID: "systemd", Title: "systemd работает", OK: false, Message: "/run/systemd/system нет"}
	}
	return PrecheckResult{ID: "systemd", Title: "systemd работает", OK: true}
}

func checkDiskSpace() PrecheckResult {
	var fs syscall.Statfs_t
	if err := syscall.Statfs("/var", &fs); err != nil {
		return PrecheckResult{ID: "disk", Title: "Свободное место в /var", OK: false, Message: err.Error()}
	}
	freeBytes := fs.Bavail * uint64(fs.Bsize)
	freeGiB := freeBytes / (1 << 30)
	if freeGiB < 2 {
		return PrecheckResult{ID: "disk", Title: "Свободное место в /var", OK: false, Message: fmt.Sprintf("Свободно %d GiB, нужно ≥ 2", freeGiB)}
	}
	return PrecheckResult{ID: "disk", Title: "Свободное место в /var", OK: true, Message: fmt.Sprintf("%d GiB свободно", freeGiB)}
}

func checkArtifacts(dir string) PrecheckResult {
	required := []struct {
		Glob string
		Name string
	}{
		{filepath.Join(dir, "ClientL_Other", "zpki-*.deb"), "zpki (Валидата)"},
		{filepath.Join(dir, "bj-server"), "bj-server (Go-бинарь)"},
		{filepath.Join(dir, "crypto-service.jar"), "crypto-service.jar"},
	}
	var missing []string
	for _, r := range required {
		matches, _ := filepath.Glob(r.Glob)
		if len(matches) == 0 {
			missing = append(missing, r.Name)
		}
	}
	if len(missing) > 0 {
		return PrecheckResult{
			ID:      "artifacts",
			Title:   "Артефакты дистрибутива",
			OK:      false,
			Message: "Отсутствуют: " + strings.Join(missing, ", ") + " (положите в " + dir + ")",
		}
	}
	return PrecheckResult{ID: "artifacts", Title: "Артефакты дистрибутива", OK: true, Message: "Все на месте в " + dir}
}

func readOSRelease() (id, pretty string) {
	b, err := os.ReadFile("/etc/os-release")
	if err != nil {
		return "", "неизвестно"
	}
	for _, line := range strings.Split(string(b), "\n") {
		k, v, ok := strings.Cut(line, "=")
		if !ok {
			continue
		}
		v = strings.Trim(v, `"`)
		switch k {
		case "ID":
			id = v
		case "PRETTY_NAME":
			pretty = v
		}
	}
	return
}
