package android

import (
	"os"
	"path/filepath"
	"testing"
)

func TestProfileAccountPathFor(t *testing.T) {
	tests := []struct {
		name       string
		configPath string
		want       string
		wantErr    bool
	}{
		{
			name:       "default profile",
			configPath: "/data/data/io.netbird.client/files/netbird.cfg",
			want:       filepath.FromSlash("/data/data/io.netbird.client/files/netbird.account.json"),
		},
		{
			name:       "id profile",
			configPath: "/data/data/io.netbird.client/files/profiles/4c5f5c8198c3989cffb5b5394f5a7ae0.json",
			want:       filepath.FromSlash("/data/data/io.netbird.client/files/profiles/4c5f5c8198c3989cffb5b5394f5a7ae0.account.json"),
		},
		{
			name:       "legacy name-keyed profile is handled the same way",
			configPath: "/data/data/io.netbird.client/files/profiles/work.json",
			want:       filepath.FromSlash("/data/data/io.netbird.client/files/profiles/work.account.json"),
		},
		{
			name:       "empty path is rejected",
			configPath: "",
			wantErr:    true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got, err := profileAccountPathFor(tt.configPath)
			if tt.wantErr {
				if err == nil {
					t.Fatalf("expected an error, got path %q", got)
				}
				return
			}
			if err != nil {
				t.Fatalf("unexpected error: %v", err)
			}
			if got != tt.want {
				t.Errorf("got %q, want %q", got, tt.want)
			}
		})
	}
}

func TestProfileAccountPathForDefaultDoesNotCollide(t *testing.T) {
	root := "/data/data/io.netbird.client/files"

	defaultAccount, err := profileAccountPathFor(filepath.Join(root, defaultConfigFilename))
	if err != nil {
		t.Fatalf("default profile: %v", err)
	}

	idAccount, err := profileAccountPathFor(filepath.Join(root, profilesSubdir, "abc123.json"))
	if err != nil {
		t.Fatalf("id profile: %v", err)
	}

	if defaultAccount == idAccount {
		t.Fatalf("default and id profile share an account file: %q", defaultAccount)
	}
}

// The account file must never land on the engine state file: on Android both
// resolve under files/, and the state manager rewrites the whole file from its
// own keys, so sharing a path would have the two overwrite each other. The
// expected names here mirror ProfileManager.GetStateFilePath.
func TestProfileAccountPathAvoidsEngineStateFile(t *testing.T) {
	root := "/data/data/io.netbird.client/files"

	cases := []struct {
		configPath  string
		engineState string
	}{
		{
			configPath:  filepath.Join(root, defaultConfigFilename),
			engineState: filepath.Join(root, "state.json"),
		},
		{
			configPath:  filepath.Join(root, profilesSubdir, "abc123.json"),
			engineState: filepath.Join(root, profilesSubdir, "abc123.state.json"),
		},
	}

	for _, c := range cases {
		account, err := profileAccountPathFor(c.configPath)
		if err != nil {
			t.Fatalf("%s: %v", c.configPath, err)
		}
		if account == c.engineState {
			t.Errorf("account file collides with the engine state file: %q", account)
		}
	}
}

func TestWriteThenReadProfileEmail(t *testing.T) {
	configPath := filepath.Join(t.TempDir(), "profiles", "abc123.json")
	if err := ensureDirFor(t, configPath); err != nil {
		t.Fatalf("prepare dir: %v", err)
	}

	if got := readProfileEmail(configPath); got != "" {
		t.Errorf("expected no email before a login, got %q", got)
	}

	const email = "user@example.com"
	if err := writeProfileEmail(configPath, email); err != nil {
		t.Fatalf("write: %v", err)
	}

	if got := readProfileEmail(configPath); got != email {
		t.Errorf("got %q, want %q", got, email)
	}

	if err := removeProfileEmail(configPath); err != nil {
		t.Fatalf("remove: %v", err)
	}
	if got := readProfileEmail(configPath); got != "" {
		t.Errorf("expected no email after logout, got %q", got)
	}

	// Logout may run on a never-logged-in profile, so a second remove must pass.
	if err := removeProfileEmail(configPath); err != nil {
		t.Fatalf("second remove should be a no-op: %v", err)
	}
}

func TestWriteProfileEmailIgnoresEmpty(t *testing.T) {
	configPath := filepath.Join(t.TempDir(), "profiles", "abc123.json")
	if err := ensureDirFor(t, configPath); err != nil {
		t.Fatalf("prepare dir: %v", err)
	}

	const email = "user@example.com"
	if err := writeProfileEmail(configPath, email); err != nil {
		t.Fatalf("write: %v", err)
	}
	if err := writeProfileEmail(configPath, ""); err != nil {
		t.Fatalf("write empty: %v", err)
	}

	if got := readProfileEmail(configPath); got != email {
		t.Errorf("empty write clobbered the stored email: got %q, want %q", got, email)
	}
}

func ensureDirFor(t *testing.T, path string) error {
	t.Helper()
	return os.MkdirAll(filepath.Dir(path), 0o700)
}
