package startup

import (
	"errors"
	"testing"
)

type fakeValueStore struct {
	values    map[string]string
	setErr    error
	deleteErr error
	getErr    error
}

func (s *fakeValueStore) GetString(name string) (string, error) {
	if s.getErr != nil {
		return "", s.getErr
	}
	v, ok := s.values[name]
	if !ok {
		return "", ErrValueNotFound
	}
	return v, nil
}

func (s *fakeValueStore) SetString(name, value string) error {
	if s.setErr != nil {
		return s.setErr
	}
	if s.values == nil {
		s.values = map[string]string{}
	}
	s.values[name] = value
	return nil
}

func (s *fakeValueStore) Delete(name string) error {
	if s.deleteErr != nil {
		return s.deleteErr
	}
	delete(s.values, name)
	return nil
}

func TestEnabledReturnsTrueWhenRunEntryExists(t *testing.T) {
	store := &fakeValueStore{values: map[string]string{AppName: `"C:\Program Files\Mirage\MirageGUI.exe"`}}
	c := &Controller{Store: store}

	enabled, err := c.Enabled()
	if err != nil {
		t.Fatalf("Enabled() error = %v", err)
	}
	if !enabled {
		t.Fatal("Enabled() = false, want true")
	}
}

func TestEnabledReturnsFalseWhenRunEntryMissing(t *testing.T) {
	c := &Controller{Store: &fakeValueStore{}}

	enabled, err := c.Enabled()
	if err != nil {
		t.Fatalf("Enabled() error = %v", err)
	}
	if enabled {
		t.Fatal("Enabled() = true, want false")
	}
}

func TestSetEnabledWritesQuotedExecutablePath(t *testing.T) {
	store := &fakeValueStore{}
	c := &Controller{
		Store: store,
		ExecutablePath: func() (string, error) {
			return `C:\Program Files\Mirage\MirageGUI.exe`, nil
		},
	}

	if err := c.SetEnabled(true); err != nil {
		t.Fatalf("SetEnabled(true) error = %v", err)
	}

	if got := store.values[AppName]; got != `"C:\Program Files\Mirage\MirageGUI.exe"` {
		t.Fatalf("run entry = %q, want %q", got, `"C:\Program Files\Mirage\MirageGUI.exe"`)
	}
}

func TestSetEnabledDeletesRunEntry(t *testing.T) {
	store := &fakeValueStore{values: map[string]string{AppName: `"C:\Program Files\Mirage\MirageGUI.exe"`}}
	c := &Controller{Store: store}

	if err := c.SetEnabled(false); err != nil {
		t.Fatalf("SetEnabled(false) error = %v", err)
	}
	if _, ok := store.values[AppName]; ok {
		t.Fatal("run entry still exists after disable")
	}
}

func TestSetEnabledPropagatesExecutableLookupError(t *testing.T) {
	wantErr := errors.New("no executable")
	c := &Controller{
		Store: &fakeValueStore{},
		ExecutablePath: func() (string, error) {
			return "", wantErr
		},
	}

	err := c.SetEnabled(true)
	if !errors.Is(err, wantErr) {
		t.Fatalf("SetEnabled(true) error = %v, want %v", err, wantErr)
	}
}

func TestRepairEnabledPathRewritesExistingEntryToCurrentExecutable(t *testing.T) {
	store := &fakeValueStore{values: map[string]string{AppName: `"C:\Program Files\Mirage\Mirage.exe"`}}
	c := &Controller{
		Store: store,
		ExecutablePath: func() (string, error) {
			return `C:\Program Files\Mirage\MirageGUI.exe`, nil
		},
	}

	if err := c.RepairEnabledPath(); err != nil {
		t.Fatalf("RepairEnabledPath() error = %v", err)
	}
	if got, want := store.values[AppName], `"C:\Program Files\Mirage\MirageGUI.exe"`; got != want {
		t.Fatalf("run entry = %q, want %q", got, want)
	}
}

func TestRepairEnabledPathDoesNothingWhenDisabled(t *testing.T) {
	store := &fakeValueStore{}
	c := &Controller{
		Store: store,
		ExecutablePath: func() (string, error) {
			t.Fatal("ExecutablePath should not be called when startup is disabled")
			return "", nil
		},
	}

	if err := c.RepairEnabledPath(); err != nil {
		t.Fatalf("RepairEnabledPath() error = %v", err)
	}
}
