package notices

import (
	"context"
	"encoding/json"
	"os"
	"path/filepath"
	"testing"

	"ymhut-box/server/unified-management/internal/config"
	"ymhut-box/server/unified-management/internal/db"
)

func TestSaveNoticeSyncsFilesAndLegacyUpdateInfo(t *testing.T) {
	root := t.TempDir()
	public := filepath.Join(root, "public")
	noticeDir := filepath.Join(root, "update-notice")
	if err := os.MkdirAll(public, 0o755); err != nil {
		t.Fatal(err)
	}
	if err := os.MkdirAll(noticeDir, 0o755); err != nil {
		t.Fatal(err)
	}
	writeJSON(t, filepath.Join(public, "update-info.json"), map[string]any{"app_version": "1.0.0"})
	writeJSON(t, filepath.Join(noticeDir, "total.json"), map[string]any{"schema_version": 1, "versions": []any{}})

	store, err := db.Open(&config.Config{
		StorageDir:      filepath.Join(root, "storage"),
		UpdatePublicDir: public,
		UpdateNoticeDir: noticeDir,
		Database: config.DatabaseConfig{
			Provider:               "sqlite",
			SQLitePath:             filepath.Join(root, "storage", "unified.sqlite"),
			FailoverEnabled:        true,
			HealthIntervalSec:      3600,
			MaxOpenConns:           1,
			MaxIdleConns:           1,
			ConnMaxLifetimeSeconds: 60,
		},
	})
	if err != nil {
		t.Fatal(err)
	}
	defer store.Close()

	service := NewService(&config.Config{UpdatePublicDir: public, UpdateNoticeDir: noticeDir}, store)
	raw := `{"app_version":"2.0.1","title":"YMhut Box 2.0.1","message":"hello","release_notes":"notes","release_notes_md":"## Notes","download_url":"https://update.ymhut.cn/downloads/app.exe","update_notes":{"发布":"说明"}}`
	doc, err := service.Save(context.Background(), "2.0.1", SaveRequest{Raw: raw, Note: "test"}, "admin")
	if err != nil {
		t.Fatal(err)
	}
	if doc.Notice.Version != "2.0.1" {
		t.Fatalf("unexpected version %q", doc.Notice.Version)
	}
	if _, err := os.Stat(filepath.Join(noticeDir, "2.0.1.json")); err != nil {
		t.Fatal(err)
	}
	updateInfo := readJSONFile(t, filepath.Join(public, "update-info.json"))
	if updateInfo["app_version"] != "2.0.1" || updateInfo["release_notes"] != "notes" {
		t.Fatalf("legacy update-info not synced: %#v", updateInfo)
	}
	total := readJSONFile(t, filepath.Join(noticeDir, "total.json"))
	if total["latest_version"] != "2.0.1" {
		t.Fatalf("total index not synced: %#v", total)
	}
	revisions, err := store.ListReleaseNoticeRevisions("2.0.1", 10)
	if err != nil || len(revisions) == 0 {
		t.Fatalf("expected revision, got %d, %v", len(revisions), err)
	}
}

func TestSyncFromLegacyUpdateInfoUpdatesNoticeIndex(t *testing.T) {
	root := t.TempDir()
	public := filepath.Join(root, "public")
	noticeDir := filepath.Join(root, "update-notice")
	if err := os.MkdirAll(public, 0o755); err != nil {
		t.Fatal(err)
	}
	if err := os.MkdirAll(noticeDir, 0o755); err != nil {
		t.Fatal(err)
	}
	writeJSON(t, filepath.Join(noticeDir, "total.json"), map[string]any{"schema_version": 1, "versions": []any{}})

	cfg := &config.Config{
		StorageDir:      filepath.Join(root, "storage"),
		UpdatePublicDir: public,
		UpdateNoticeDir: noticeDir,
		Database: config.DatabaseConfig{
			Provider:               "sqlite",
			SQLitePath:             filepath.Join(root, "storage", "unified.sqlite"),
			FailoverEnabled:        true,
			HealthIntervalSec:      3600,
			MaxOpenConns:           1,
			MaxIdleConns:           1,
			ConnMaxLifetimeSeconds: 60,
		},
	}
	store, err := db.Open(cfg)
	if err != nil {
		t.Fatal(err)
	}
	defer store.Close()

	service := NewService(cfg, store)
	raw := `{"app_version":"2.0.7.5","title":"YMhut Box 2.0.7.5","message":"随机放映室优化","release_notes":"修复图片源和全屏预览","download_url":"https://update.ymhut.cn/downloads/app.exe"}`
	if err := service.SyncFromLegacyUpdateInfo(context.Background(), raw, "admin"); err != nil {
		t.Fatal(err)
	}
	items, err := service.List(10)
	if err != nil {
		t.Fatal(err)
	}
	if len(items) != 1 || items[0].Version != "2.0.7.5" || items[0].Title != "YMhut Box 2.0.7.5" {
		t.Fatalf("notice list not synced: %#v", items)
	}
	total := readJSONFile(t, filepath.Join(noticeDir, "total.json"))
	if total["latest_version"] != "2.0.7.5" {
		t.Fatalf("total index not updated: %#v", total)
	}
}

func writeJSON(t *testing.T, path string, payload any) {
	t.Helper()
	data, err := json.Marshal(payload)
	if err != nil {
		t.Fatal(err)
	}
	if err := os.WriteFile(path, data, 0o644); err != nil {
		t.Fatal(err)
	}
}

func readJSONFile(t *testing.T, path string) map[string]any {
	t.Helper()
	data, err := os.ReadFile(path)
	if err != nil {
		t.Fatal(err)
	}
	var payload map[string]any
	if err := json.Unmarshal(data, &payload); err != nil {
		t.Fatal(err)
	}
	return payload
}
