package config

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

func TestSavePersistsRelativePaths(t *testing.T) {
	root := t.TempDir()
	cfg := defaults(root)
	cfg.Initialized = true
	cfg.ConfigPath = filepath.Join(root, "config.json")

	if err := Save(cfg); err != nil {
		t.Fatal(err)
	}
	data, err := os.ReadFile(filepath.Join(root, "config.json"))
	if err != nil {
		t.Fatal(err)
	}
	var saved Config
	if err := json.Unmarshal(data, &saved); err != nil {
		t.Fatal(err)
	}
	if saved.BaseDir != "." {
		t.Fatalf("BaseDir = %q, want relative dot", saved.BaseDir)
	}
	for name, value := range map[string]string{
		"storage_dir":       saved.StorageDir,
		"data_dir":          saved.DataDir,
		"update_public_dir": saved.UpdatePublicDir,
		"update_notice_dir": saved.UpdateNoticeDir,
		"downloads_dir":     saved.DownloadsDir,
		"sqlite_path":       saved.Database.SQLitePath,
	} {
		if filepath.IsAbs(value) || strings.Contains(value, root) {
			t.Fatalf("%s saved as absolute path %q", name, value)
		}
	}
}

func TestPreflightCreatesRuntimeDirectoriesAndNoticeIndex(t *testing.T) {
	root := t.TempDir()
	cfg := defaults(root)
	checks := Preflight(cfg)
	for _, path := range []string{
		cfg.UpdatePublicDir,
		cfg.UpdateNoticeDir,
		cfg.DownloadsDir,
		filepath.Join(cfg.UpdatePublicDir, "update-info.json"),
		filepath.Join(cfg.UpdatePublicDir, "media-types.json"),
		filepath.Join(cfg.UpdateNoticeDir, "total.json"),
	} {
		if _, err := os.Stat(path); err != nil {
			t.Fatalf("expected preflight to create %s: %v", path, err)
		}
	}
	for _, line := range FormatPreflight(cfg, checks) {
		if strings.Contains(line, root) {
			t.Fatalf("preflight line leaked absolute base path: %s", line)
		}
	}
}

func TestLoadRewritesAbsoluteConfigPaths(t *testing.T) {
	root := t.TempDir()
	t.Setenv("YMHUT_BASE_DIR", root)
	configPath := filepath.Join(root, "config.json")
	payload := map[string]any{
		"initialized":       true,
		"listen":            ":33550",
		"storage_dir":       filepath.Join(root, "storage"),
		"data_dir":          filepath.Join(root, "data"),
		"update_public_dir": filepath.Join(root, "data", "update", "public"),
		"update_notice_dir": filepath.Join(root, "data", "update-notice"),
		"downloads_dir":     filepath.Join(root, "data", "update", "public", "downloads"),
		"database": map[string]any{
			"provider":    "sqlite",
			"sqlite_path": filepath.Join(root, "storage", "unified.sqlite"),
		},
	}
	data, err := json.Marshal(payload)
	if err != nil {
		t.Fatal(err)
	}
	if err := os.WriteFile(configPath, data, 0o600); err != nil {
		t.Fatal(err)
	}
	if _, err := Load(); err != nil {
		t.Fatal(err)
	}
	rewritten, err := os.ReadFile(configPath)
	if err != nil {
		t.Fatal(err)
	}
	if strings.Contains(string(rewritten), root) {
		t.Fatalf("config still contains absolute base path: %s", string(rewritten))
	}
}
