package infra

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

func TestSSHConfigWrite_CreatesFileAndDir(t *testing.T) {
	home := t.TempDir()
	t.Setenv("HOME", home)
	entries := []SSHConfigEntry{{Alias: "prod", HostName: "10.0.0.1", User: "admin", Port: 22}}
	if err := SSHConfigWrite(entries); err != nil {
		t.Fatalf("write: %v", err)
	}
	configPath := filepath.Join(home, ".ssh", "config")
	data, err := os.ReadFile(configPath)
	if err != nil {
		t.Fatalf("read back: %v", err)
	}
	content := string(data)
	if !strings.Contains(content, "Host prod") || !strings.Contains(content, "HostName 10.0.0.1") {
		t.Errorf("unexpected content: %q", content)
	}
	info, err := os.Stat(configPath)
	if err != nil {
		t.Fatal(err)
	}
	if perm := info.Mode().Perm(); perm != 0600 {
		t.Errorf("expected 0600, got %o", perm)
	}
	dirInfo, err := os.Stat(filepath.Join(home, ".ssh"))
	if err != nil {
		t.Fatal(err)
	}
	if perm := dirInfo.Mode().Perm(); perm != 0700 {
		t.Errorf("expected dir 0700, got %o", perm)
	}
}

func TestSSHConfigWrite_BackupExisting(t *testing.T) {
	home := t.TempDir()
	t.Setenv("HOME", home)
	sshDir := filepath.Join(home, ".ssh")
	if err := os.MkdirAll(sshDir, 0700); err != nil {
		t.Fatal(err)
	}
	configPath := filepath.Join(sshDir, "config")
	original := []byte("Host old\n    HostName 1.1.1.1\n")
	if err := os.WriteFile(configPath, original, 0600); err != nil {
		t.Fatal(err)
	}
	entries := []SSHConfigEntry{{Alias: "new", HostName: "2.2.2.2"}}
	if err := SSHConfigWrite(entries); err != nil {
		t.Fatalf("write: %v", err)
	}
	backup, err := os.ReadFile(filepath.Join(sshDir, "config.bak"))
	if err != nil {
		t.Fatalf("backup not found: %v", err)
	}
	if string(backup) != string(original) {
		t.Errorf("backup mismatch: got %q", backup)
	}
	current, err := os.ReadFile(configPath)
	if err != nil {
		t.Fatal(err)
	}
	if !strings.Contains(string(current), "Host new") {
		t.Errorf("config not overwritten: %q", current)
	}
}

func TestSSHConfigWrite_NoBackupWhenAbsent(t *testing.T) {
	home := t.TempDir()
	t.Setenv("HOME", home)
	if err := SSHConfigWrite([]SSHConfigEntry{{Alias: "a"}}); err != nil {
		t.Fatal(err)
	}
	if _, err := os.Stat(filepath.Join(home, ".ssh", "config.bak")); !os.IsNotExist(err) {
		t.Errorf("expected no backup when config did not exist, stat err=%v", err)
	}
}

func TestSSHConfigWriteRead_Roundtrip(t *testing.T) {
	home := t.TempDir()
	t.Setenv("HOME", home)
	original := []SSHConfigEntry{
		{Alias: "prod", HostName: "10.0.0.1", User: "admin", Port: 22, IdentityFile: "~/.ssh/id_prod"},
		{Alias: "staging", HostName: "10.0.0.2", User: "deploy", Port: 2222},
	}
	if err := SSHConfigWrite(original); err != nil {
		t.Fatal(err)
	}
	parsed, err := SSHConfigRead()
	if err != nil {
		t.Fatal(err)
	}
	if len(parsed) != len(original) {
		t.Fatalf("expected %d entries, got %d", len(original), len(parsed))
	}
	for i := range original {
		if parsed[i].Alias != original[i].Alias || parsed[i].HostName != original[i].HostName ||
			parsed[i].User != original[i].User || parsed[i].Port != original[i].Port {
			t.Errorf("roundtrip[%d] mismatch: %+v vs %+v", i, parsed[i], original[i])
		}
	}
}
