package file

import (
	"context"
	"encoding/json"
	"errors"
	"os"
	"path/filepath"
	"sync"

	"github.com/Eriyc/rules_wails/pkg/wails3kit/updates"
)

type Store struct {
	path string
	mu   sync.Mutex
}

func New(path string) *Store {
	return &Store{path: path}
}

func (store *Store) Path() string {
	return store.path
}

func (store *Store) Load(_ context.Context) (updates.Snapshot, error) {
	store.mu.Lock()
	defer store.mu.Unlock()

	bytes, err := os.ReadFile(store.path)
	if errors.Is(err, os.ErrNotExist) {
		return updates.Snapshot{}, nil
	}
	if err != nil {
		return updates.Snapshot{}, err
	}

	var snapshot updates.Snapshot
	if err := json.Unmarshal(bytes, &snapshot); err != nil {
		return updates.Snapshot{}, err
	}
	return snapshot, nil
}

func (store *Store) Save(_ context.Context, snapshot updates.Snapshot) error {
	store.mu.Lock()
	defer store.mu.Unlock()

	if err := os.MkdirAll(filepath.Dir(store.path), 0o755); err != nil {
		return err
	}

	bytes, err := json.MarshalIndent(snapshot, "", "  ")
	if err != nil {
		return err
	}

	tempFile, err := os.CreateTemp(filepath.Dir(store.path), "snapshot-*.json")
	if err != nil {
		return err
	}
	tempPath := tempFile.Name()
	defer func() {
		_ = os.Remove(tempPath)
	}()

	if _, err := tempFile.Write(bytes); err != nil {
		_ = tempFile.Close()
		return err
	}
	if err := tempFile.Close(); err != nil {
		return err
	}

	return os.Rename(tempPath, store.path)
}

func (store *Store) ClearStaged(ctx context.Context) error {
	snapshot, err := store.Load(ctx)
	if err != nil {
		return err
	}
	snapshot.Staged = nil
	snapshot.Candidate = nil
	snapshot.LastError = nil
	if snapshot.State == updates.StateRestarting {
		snapshot.State = updates.StateUpToDate
	}
	return store.Save(ctx, snapshot)
}
