package bootstrap

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

	"iop/apps/edge/internal/configrefresh"
)

const legacyCredentialModeYAML = `
server:
  listen: "127.0.0.1:9090"
credential_plane:
  enabled: false
`

const managedCredentialModeYAML = `
server:
  listen: "127.0.0.1:9090"
tls:
  enabled: true
  cert: "/cert"
  key: "/key"
  ca: "/ca"
  peer_role: "node"
control_plane:
  enabled: true
  wire_addr: "control-plane:19081"
  tls:
    enabled: true
    cert: "/cert"
    key: "/key"
    ca: "/ca"
    server_name: "control-plane"
    peer_role: "control-plane"
credential_plane:
  enabled: true
  lease_ttl_seconds: 30
  lease_cache_size: 256
`

func writeCredentialModeConfig(t *testing.T, name, body string) string {
	t.Helper()
	path := filepath.Join(t.TempDir(), name)
	if err := os.WriteFile(path, []byte(body), 0o600); err != nil {
		t.Fatal(err)
	}
	return path
}

func TestCredentialModeRefreshAndRollbackRequireRestartWithoutPartialApply(t *testing.T) {
	managedEdgeKeyChanged := strings.Replace(managedCredentialModeYAML, "  key: \"/key\"\n  ca: \"/ca\"\n  peer_role: \"node\"", "  key: \"/rotated-edge-key\"\n  ca: \"/ca\"\n  peer_role: \"node\"", 1)
	managedControlPlaneKeyChanged := strings.Replace(managedCredentialModeYAML, "    key: \"/key\"\n    ca: \"/ca\"\n    server_name:", "    key: \"/rotated-control-plane-key\"\n    ca: \"/ca\"\n    server_name:", 1)
	managedOpenAI := managedCredentialModeYAML + `
openai:
  enabled: true
  provider_id: "provider-fixture"
  tls:
    enabled: true
    cert: "/openai-cert"
    key: "/openai-key"
`
	for _, tc := range []struct {
		name          string
		currentBody   string
		candidateBody string
		expectedPath  string
	}{
		{name: "legacy to managed", currentBody: legacyCredentialModeYAML, candidateBody: managedCredentialModeYAML, expectedPath: "credential_plane"},
		{name: "managed rollback to legacy", currentBody: managedCredentialModeYAML, candidateBody: legacyCredentialModeYAML, expectedPath: "credential_plane"},
		{name: "legacy source change", currentBody: legacyCredentialModeYAML, candidateBody: legacyCredentialModeYAML + "\nopenai:\n  bearer_token: legacy-fixture\n", expectedPath: "openai"},
		{name: "managed lease setting change", currentBody: managedCredentialModeYAML, candidateBody: strings.Replace(managedCredentialModeYAML, "lease_ttl_seconds: 30", "lease_ttl_seconds: 31", 1), expectedPath: "credential_plane"},
		{name: "managed edge TLS key rotation", currentBody: managedCredentialModeYAML, candidateBody: managedEdgeKeyChanged, expectedPath: "tls"},
		{name: "managed Control Plane TLS key rotation", currentBody: managedCredentialModeYAML, candidateBody: managedControlPlaneKeyChanged, expectedPath: "control_plane"},
		{name: "managed OpenAI TLS key rotation", currentBody: managedOpenAI, candidateBody: strings.Replace(managedOpenAI, "/openai-key", "/rotated-openai-key", 1), expectedPath: "openai"},
	} {
		t.Run(tc.name, func(t *testing.T) {
			currentPath := writeCredentialModeConfig(t, "current.yaml", tc.currentBody)
			candidatePath := writeCredentialModeConfig(t, "candidate.yaml", tc.candidateBody)
			current, err := configrefresh.LoadCandidate(currentPath)
			if err != nil {
				t.Fatalf("load current: %v", err)
			}
			runtime := &Runtime{Cfg: current}
			result, err := runtime.RefreshConfig(context.Background(), configrefresh.Request{
				Mode: configrefresh.ModeApply, ConfigPath: candidatePath, RequestID: "credential-mode-transition",
			})
			if err != nil {
				t.Fatalf("RefreshConfig: %v", err)
			}
			if result.Status != configrefresh.StatusRestartRequired {
				t.Fatalf("status = %q, want restart_required: %+v", result.Status, result.Changes)
			}
			found := false
			for _, change := range result.Changes {
				if change.Path == tc.expectedPath && change.Class == configrefresh.StatusRestartRequired {
					found = true
				}
			}
			if !found {
				t.Fatalf("restart path %q missing: %+v", tc.expectedPath, result.Changes)
			}
			if runtime.Cfg != current {
				t.Fatal("restart-required credential mode was partially applied")
			}
		})
	}
}
