package main

import (
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"testing"

	"pentagi/cmd/installer/files"
	"pentagi/pkg/version"
)

func TestMain_ParseFlags_ReadsTheEnvPathAndVersionFlags(t *testing.T) {
	tests := []struct {
		name            string
		args            []string
		expectedEnv     string
		expectedVersion bool
	}{
		{name: "default values", args: []string{}, expectedEnv: ".env"},
		{name: "custom env path", args: []string{"-e", "config/.env"}, expectedEnv: "config/.env"},
		{name: "version flag", args: []string{"-v"}, expectedEnv: ".env", expectedVersion: true},
		{name: "both flags", args: []string{"-e", "test.env", "-v"}, expectedEnv: "test.env", expectedVersion: true},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			config := parseFlags(append([]string{"test"}, tt.args...))

			if config.envPath != tt.expectedEnv {
				t.Errorf("envPath = %q, want %q", config.envPath, tt.expectedEnv)
			}
			if config.showVersion != tt.expectedVersion {
				t.Errorf("showVersion = %v, want %v", config.showVersion, tt.expectedVersion)
			}
		})
	}
}

func TestMain_ValidateEnvPath_CreatesAMissingFileAndRefusesADirectory(t *testing.T) {
	template, err := files.NewFiles().GetContent(".env")
	if err != nil {
		t.Fatalf("read the .env template: %v", err)
	}
	header := "# PentAGI Environment Configuration\n# Generated by PentAGI Installer v" + version.GetBinaryVersion() + "\n"

	tmpDir := t.TempDir()
	tests := []struct {
		name    string
		path    string
		setup   func(path string) error
		created bool
		wantErr string
	}{
		{
			name:  "an existing file is kept as it is",
			path:  "existing.env",
			setup: func(path string) error { return os.WriteFile(path, []byte("VAR=value"), 0o600) },
		},
		{name: "a missing file is created from the template", path: "new.env", created: true},
		{name: "a missing directory is created with it", path: "nonexistent/file.env", created: true},
		{
			name:    "a directory in place of the file is refused",
			path:    "dir",
			setup:   func(path string) error { return os.Mkdir(path, 0o755) },
			wantErr: "is a directory",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			path := filepath.Join(tmpDir, filepath.FromSlash(tt.path))
			if tt.setup != nil {
				if err := tt.setup(path); err != nil {
					t.Fatalf("setup: %v", err)
				}
			}

			got, err := validateEnvPath(path)
			if tt.wantErr != "" {
				if err == nil || !strings.Contains(err.Error(), tt.wantErr) {
					t.Fatalf("validateEnvPath() error = %v, want it to mention %q", err, tt.wantErr)
				}
				return
			}
			if err != nil || got != path {
				t.Fatalf("validateEnvPath() = %q, %v; want %q", got, err, path)
			}

			content, err := os.ReadFile(path)
			if err != nil {
				t.Fatalf("read env file: %v", err)
			}
			if !tt.created {
				if string(content) != "VAR=value" {
					t.Errorf("existing env file was rewritten: %q", content)
				}
				return
			}
			if !strings.HasPrefix(string(content), header) || !strings.HasSuffix(string(content), string(template)) {
				t.Errorf("created env file is not the header followed by the template:\n%.200s", content)
			}
			info, err := os.Stat(path)
			if err != nil {
				t.Fatalf("stat env file: %v", err)
			}
			if runtime.GOOS != "windows" && info.Mode().Perm() != 0o600 {
				t.Errorf("created env file mode = %v, want -rw-------", info.Mode().Perm())
			}
		})
	}
}

func TestMain_InitializeState_LoadsTheEnvFile(t *testing.T) {
	envPath := filepath.Join(t.TempDir(), "test.env")
	if err := os.WriteFile(envPath, []byte("VAR1=value1"), 0o600); err != nil {
		t.Fatalf("write env file: %v", err)
	}

	state, err := initializeState(envPath)
	if err != nil || state == nil {
		t.Fatalf("initializeState() = %v, %v", state, err)
	}
	if envVar, exists := state.GetVar("VAR1"); !exists || envVar.Value != "value1" {
		t.Errorf("GetVar(VAR1) = %q, %v; want %q, true", envVar.Value, exists, "value1")
	}
}
