package config_test

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

	"workshop.perforce.com/p4lf/internal/config"
)

func writeConfig(t *testing.T, content string) string {
	t.Helper()
	f, err := os.CreateTemp(t.TempDir(), "p4lf-*.cfg")
	if err != nil {
		t.Fatalf("creating temp config: %v", err)
	}
	f.WriteString(content)
	f.Close()
	return f.Name()
}

func TestLoad_Defaults(t *testing.T) {
	path := writeConfig(t, "P4LogFile = /p4/1/logs/log\n")
	cfg, err := config.Load(path)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if cfg.LogTailDelay != 60*time.Second {
		t.Errorf("LogTailDelay: got %v, want 60s", cfg.LogTailDelay)
	}
	if cfg.MaxLogChunks != 5000 {
		t.Errorf("MaxLogChunks: got %d, want 5000", cfg.MaxLogChunks)
	}
	if !cfg.ReadFromStart {
		t.Error("ReadFromStart: want true by default")
	}
	if cfg.Debug != 0 {
		t.Errorf("Debug: got %d, want 0", cfg.Debug)
	}
}

func TestLoad_AllSettings(t *testing.T) {
	path := writeConfig(t, `
P4LogFile = /p4/1/logs/log
LogTailDelay = 30s
MaxLogChunks = 10
MinLogSpace = 5%
MaxLogSize = 50M
MaxRotationRecoverySize = 200M
StateFile = /tmp/p4lf.state
ReadFromStart = false
Debug = 2
`)
	cfg, err := config.Load(path)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if cfg.P4LogFile != "/p4/1/logs/log" {
		t.Errorf("P4LogFile: got %q", cfg.P4LogFile)
	}
	if cfg.LogTailDelay != 30*time.Second {
		t.Errorf("LogTailDelay: got %v, want 30s", cfg.LogTailDelay)
	}
	if cfg.MaxLogChunks != 10 {
		t.Errorf("MaxLogChunks: got %d, want 10", cfg.MaxLogChunks)
	}
	if !cfg.MinLogSpace.IsPercent || cfg.MinLogSpace.Percent != 5 {
		t.Errorf("MinLogSpace: got %+v, want 5%%", cfg.MinLogSpace)
	}
	if cfg.MaxLogSize != 50*1024*1024 {
		t.Errorf("MaxLogSize: got %d, want %d", cfg.MaxLogSize, 50*1024*1024)
	}
	if cfg.MaxRotationRecoverySize != 200*1024*1024 {
		t.Errorf("MaxRotationRecoverySize: got %d, want %d", cfg.MaxRotationRecoverySize, 200*1024*1024)
	}
	if cfg.StateFile != "/tmp/p4lf.state" {
		t.Errorf("StateFile: got %q", cfg.StateFile)
	}
	if cfg.ReadFromStart {
		t.Error("ReadFromStart: want false")
	}
	if cfg.Debug != 2 {
		t.Errorf("Debug: got %d, want 2", cfg.Debug)
	}
}

func TestLoad_DurationFormats(t *testing.T) {
	cases := []struct {
		input string
		want  time.Duration
	}{
		{"60s", 60 * time.Second},
		{"3m", 3 * time.Minute},
		{"1h", 1 * time.Hour},
		{"120", 120 * time.Second},
	}
	for _, tc := range cases {
		path := writeConfig(t, "P4LogFile = /log\nLogTailDelay = "+tc.input+"\n")
		cfg, err := config.Load(path)
		if err != nil {
			t.Errorf("input %q: unexpected error: %v", tc.input, err)
			continue
		}
		if cfg.LogTailDelay != tc.want {
			t.Errorf("input %q: got %v, want %v", tc.input, cfg.LogTailDelay, tc.want)
		}
	}
}

func TestLoad_SizeFormats(t *testing.T) {
	cases := []struct {
		input string
		want  int64
	}{
		{"100M", 100 * 1024 * 1024},
		{"2G", 2 * 1024 * 1024 * 1024},
		{"1T", 1024 * 1024 * 1024 * 1024},
		{"512K", 512 * 1024},
		{"0", 0},
		{"None", 0},
	}
	for _, tc := range cases {
		path := writeConfig(t, "P4LogFile = /log\nMaxLogSize = "+tc.input+"\n")
		cfg, err := config.Load(path)
		if err != nil {
			t.Errorf("input %q: unexpected error: %v", tc.input, err)
			continue
		}
		if cfg.MaxLogSize != tc.want {
			t.Errorf("input %q: got %d, want %d", tc.input, cfg.MaxLogSize, tc.want)
		}
	}
}

func TestLoad_SpaceSpecAbsolute(t *testing.T) {
	path := writeConfig(t, "P4LogFile = /log\nMinLogSpace = 3G\n")
	cfg, err := config.Load(path)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if cfg.MinLogSpace.IsPercent {
		t.Error("expected absolute size, got percent")
	}
	if cfg.MinLogSpace.Bytes != 3*1024*1024*1024 {
		t.Errorf("Bytes: got %d, want %d", cfg.MinLogSpace.Bytes, 3*1024*1024*1024)
	}
}

func TestLoad_MissingP4LogFile(t *testing.T) {
	// Temporarily unset P4LOG if set.
	old := os.Getenv("P4LOG")
	os.Unsetenv("P4LOG")
	defer os.Setenv("P4LOG", old)

	path := writeConfig(t, "# no P4LogFile set\n")
	_, err := config.Load(path)
	if err == nil {
		t.Error("expected error for missing P4LogFile, got nil")
	}
}

func TestLoad_UnknownKey(t *testing.T) {
	path := writeConfig(t, "P4LogFile = /log\nUnknownKey = value\n")
	_, err := config.Load(path)
	if err == nil {
		t.Error("expected error for unknown key, got nil")
	}
}

func TestLoad_Comments(t *testing.T) {
	path := writeConfig(t, `# This is a comment
P4LogFile = /p4/1/logs/log
# LogTailDelay = 999s
`)
	cfg, err := config.Load(path)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	// LogTailDelay should be default (60s), not 999s.
	if cfg.LogTailDelay != 60*time.Second {
		t.Errorf("commented-out key was applied: LogTailDelay = %v", cfg.LogTailDelay)
	}
}

func TestLoad_MissingFile(t *testing.T) {
	_, err := config.Load(filepath.Join(t.TempDir(), "nonexistent.cfg"))
	if err == nil {
		t.Error("expected error for missing config file, got nil")
	}
}
