package data

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

	"kra/internal/conf"

	"gopkg.in/yaml.v3"
)

func TestDatabaseConnectionConfigured(t *testing.T) {
	tests := []struct {
		name   string
		config *conf.Data_Database
		want   bool
	}{
		{name: "missing config", config: nil, want: false},
		{name: "empty database", config: &conf.Data_Database{Driver: "mysql"}, want: false},
		{name: "named database", config: &conf.Data_Database{Driver: "mysql", Name: "kra"}, want: true},
		{name: "standalone DSN", config: &conf.Data_Database{Driver: "sqlite", Source: "file:kra.db"}, want: true},
		{name: "generated DSN still requires a name", config: &conf.Data_Database{Driver: "mysql", Source: "root@tcp(localhost)/", Host: "localhost"}, want: false},
	}
	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			if got := databaseConnectionConfigured(test.config); got != test.want {
				t.Fatalf("databaseConnectionConfigured() = %v, want %v", got, test.want)
			}
		})
	}
}

func TestInitializationStateTracksRealDatabaseConnection(t *testing.T) {
	data := &Data{}

	initialized, err := data.IsInitialized(context.Background())
	if err != nil {
		t.Fatalf("IsInitialized() error = %v", err)
	}
	if initialized {
		t.Fatal("bootstrap state must require initialization")
	}

	data.databaseReady.Store(true)
	initialized, err = data.IsInitialized(context.Background())
	if err != nil {
		t.Fatalf("IsInitialized() error = %v", err)
	}
	if !initialized {
		t.Fatal("an active configured database must not require initialization")
	}
}

func TestPersistDatabaseConfigPreservesTemplateAndRotatesJWTKey(t *testing.T) {
	root := t.TempDir()
	configPath := filepath.Join(root, "config.yaml")
	original := `server:
  http:
    addr: 0.0.0.0:8000
data:
  database:
    driver: mysql
    name: old
  redis:
    addr: 127.0.0.1:6379
admin:
  jwt:
    signing_key: old-key
    issuer: kra
  zap:
    director: logs
extension:
  preserved: true
`
	if err := os.WriteFile(configPath, []byte(original), 0o600); err != nil {
		t.Fatal(err)
	}
	runtime := conf.NewRuntime(&conf.Data{}, &conf.AdminBackend{ConfigPath: configPath})
	data := &Data{runtime: runtime}
	if err := data.persistDatabaseConfig(&conf.Data_Database{Driver: "mysql", Host: "db", Port: "3306", User: "root", Password: "secret", Name: "kra", Config: "parseTime=True"}, "new-key"); err != nil {
		t.Fatal(err)
	}
	raw, err := os.ReadFile(configPath)
	if err != nil {
		t.Fatal(err)
	}
	var value map[string]any
	if err = yaml.Unmarshal(raw, &value); err != nil {
		t.Fatal(err)
	}
	admin := value["admin"].(map[string]any)
	jwt := admin["jwt"].(map[string]any)
	if jwt["signing_key"] != "new-key" || jwt["issuer"] != "kra" {
		t.Fatalf("unexpected jwt config: %#v", jwt)
	}
	dataConfig := value["data"].(map[string]any)
	database := dataConfig["database"].(map[string]any)
	if database["name"] != "kra" || database["password"] != "secret" {
		t.Fatalf("unexpected database config: %#v", database)
	}
	if _, ok := dataConfig["redis"]; !ok {
		t.Fatalf("redis config was removed: %#v", dataConfig)
	}
	if _, ok := value["extension"]; !ok || !strings.Contains(string(raw), "preserved: true") {
		t.Fatalf("extension config was removed: %s", raw)
	}
}
