package save

import (
	"fmt"
	"os"
	"path/filepath"
	"time"

	"github.com/BurntSushi/toml"
)

const (
	dataFile = "data.toml"
)

// Save file structure

type Data struct {
	Settings  Settings  `toml:"settings"`
	GameState GameState `toml:"game_state"`
}

type Settings struct {
	FPSMonitor       bool   `toml:"fps_monitor"`
	FPSCap           string `toml:"fps_cap"`
	PortalVisibility bool   `toml:"portal_visibility"`
}

type GameState struct {
	HasSave     bool      `toml:"has_save"`
	SavedAt     time.Time `toml:"saved_at"`
	CurrentMap  string    `toml:"current_map"`
	HeroX       float64   `toml:"hero_x"`
	HeroY       float64   `toml:"hero_y"`
	HeroStamina float64   `toml:"hero_stamina"`
	PlayTimeMS  int64     `toml:"play_time_ms"`
}

// Save manager

type Manager struct {
	dataPath string
}

func NewManager() (*Manager, error) {
	exePath, err := os.Executable()
	if err != nil {
		return nil, fmt.Errorf("failed to get executable path: %w", err)
	}

	exeDir := filepath.Dir(exePath)

	return &Manager{
		dataPath: filepath.Join(exeDir, dataFile),
	}, nil
}

// Data operations

func (m *Manager) LoadData() (*Data, error) {
	if _, err := os.Stat(m.dataPath); os.IsNotExist(err) {
		return &Data{
			Settings: Settings{
				FPSMonitor:       false,
				FPSCap:           "60",
				PortalVisibility: false,
			},
			GameState: GameState{
				HasSave: false,
			},
		}, nil
	}

	var data Data
	if _, err := toml.DecodeFile(m.dataPath, &data); err != nil {
		return nil, fmt.Errorf("failed to parse data file: %w", err)
	}

	return &data, nil
}

func (m *Manager) SaveData(data *Data) error {
	file, err := os.Create(m.dataPath)
	if err != nil {
		return fmt.Errorf("failed to create data file: %w", err)
	}
	defer file.Close()

	encoder := toml.NewEncoder(file)
	if err := encoder.Encode(data); err != nil {
		return fmt.Errorf("failed to write data file: %w", err)
	}

	return nil
}

// Settings operations

func (m *Manager) LoadSettings() (*Settings, error) {
	data, err := m.LoadData()
	if err != nil {
		return nil, err
	}
	return &data.Settings, nil
}

func (m *Manager) SaveSettings(settings *Settings) error {
	data, err := m.LoadData()
	if err != nil {
		data = &Data{
			Settings: *settings,
			GameState: GameState{
				HasSave: false,
			},
		}
	} else {
		data.Settings = *settings
	}

	return m.SaveData(data)
}

// Game state operations

func (m *Manager) LoadGameState() (*GameState, error) {
	data, err := m.LoadData()
	if err != nil {
		return nil, err
	}

	if !data.GameState.HasSave {
		return nil, nil
	}

	return &data.GameState, nil
}

func (m *Manager) SaveGameState(state *GameState) error {
	data, err := m.LoadData()
	if err != nil {
		data = &Data{
			Settings: Settings{
				FPSMonitor:       false,
				FPSCap:           "60",
				PortalVisibility: false,
			},
			GameState: *state,
		}
	} else {
		data.GameState = *state
	}

	data.GameState.HasSave = true
	data.GameState.SavedAt = time.Now()

	return m.SaveData(data)
}

func (m *Manager) HasSavedGame() bool {
	data, err := m.LoadData()
	if err != nil {
		return false
	}
	return data.GameState.HasSave
}

func (m *Manager) DeleteGameState() error {
	data, err := m.LoadData()
	if err != nil {
		return err
	}

	data.GameState = GameState{
		HasSave: false,
	}

	return m.SaveData(data)
}

// Utilities

func (m *Manager) GetSaveFilePath() string {
	return m.dataPath
}
