package main

import (
	"encoding/json"
	"errors"
	"os"
	"path/filepath"
)

// ПРИМЕЧАНИЕ: сохранение реализовано только для этой игры — она
// единственная в коллекции без чёткого конца партии, поэтому жалко
// сбрасывать прогресс при каждом выходе в меню. Остальные 8 игр
// коллекции по-прежнему не сохраняются между запусками — обычно в
// них и не нужно (партия проходится за один присест).

// ErrCorpseStarchNoSave возвращается LoadCorpseStarchGame, если
// файл сохранения не найден (новая партия должна начаться с нуля).
var ErrCorpseStarchNoSave = errors.New("файл сохранения не найден")

// corpseStarchSavePath возвращает путь к файлу сохранения в
// пользовательской конфигурационной директории (например,
// ~/.config/go-games-collection/corpsestarch_save.json на Linux).
func corpseStarchSavePath() (string, error) {
	dir, err := os.UserConfigDir()
	if err != nil {
		return "", err
	}
	return filepath.Join(dir, "go-games-collection", "corpsestarch_save.json"), nil
}

// SaveCorpseStarchGame сохраняет текущее состояние партии на диск,
// создавая директорию сохранения при необходимости.
func SaveCorpseStarchGame(g *CorpseStarchGameState) error {
	path, err := corpseStarchSavePath()
	if err != nil {
		return err
	}
	if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
		return err
	}
	data, err := json.MarshalIndent(g, "", "  ")
	if err != nil {
		return err
	}
	return os.WriteFile(path, data, 0o644)
}

// LoadCorpseStarchGame загружает сохранённую партию с диска.
// Возвращает ErrCorpseStarchNoSave, если файла сохранения нет —
// вызывающий код должен в этом случае начать новую партию.
func LoadCorpseStarchGame() (*CorpseStarchGameState, error) {
	path, err := corpseStarchSavePath()
	if err != nil {
		return nil, err
	}
	data, err := os.ReadFile(path)
	if err != nil {
		if os.IsNotExist(err) {
			return nil, ErrCorpseStarchNoSave
		}
		return nil, err
	}
	var g CorpseStarchGameState
	if err := json.Unmarshal(data, &g); err != nil {
		return nil, err
	}
	if len(g.ServitorCounts) < len(corpseStarchServitorDefs) {
		grown := make([]int, len(corpseStarchServitorDefs))
		copy(grown, g.ServitorCounts)
		g.ServitorCounts = grown
	}
	if len(g.ServitorPurchases) < len(corpseStarchServitorDefs) {
		grown := make([]int, len(corpseStarchServitorDefs))
		copy(grown, g.ServitorPurchases)
		// у старых сохранений без этого поля используем текущие
		// счётчики как разумное начальное приближение — иначе цена
		// следующей покупки внезапно откатилась бы к базовой
		for i := range grown {
			if grown[i] < g.ServitorCounts[i] {
				grown[i] = g.ServitorCounts[i]
			}
		}
		g.ServitorPurchases = grown
	}
	if g.BonusMultiplier == 0 {
		g.BonusMultiplier = 1
	}
	return &g, nil
}

// DeleteCorpseStarchSave удаляет файл сохранения, если он есть
// (используется для явного сброса прогресса). Отсутствие файла не
// считается ошибкой.
func DeleteCorpseStarchSave() error {
	path, err := corpseStarchSavePath()
	if err != nil {
		return err
	}
	err = os.Remove(path)
	if err != nil && !os.IsNotExist(err) {
		return err
	}
	return nil
}
