package web

import (
	"net/http/httptest"
	"strings"
	"testing"

	"gitea.dooplex.hu/admin/felhom-controller/internal/backup"
	"gitea.dooplex.hu/admin/felhom-controller/internal/settings"
)

// v0.124.0 IA split (§10 nav/state): each backups sub-page renders ONLY its mapped sections —
// a marker string per section, asserted present on its page and absent on every other page.

func splitTestData() map[string]interface{} {
	return map[string]interface{}{
		"Page": "backups", "Title": "Biztonsági mentés",
		"Backup": &backup.FullBackupStatus{
			AppDataInfo: []backup.AppBackupInfo{{StackName: "calibre-web", DisplayName: "Calibre-Web"}},
		},
		"AppBackupRows": []AppBackupRow{
			{StackName: "calibre-web", DisplayName: "Calibre-Web", OffboxEnabled: true, Tier3State: "active"},
		},
		"DBSectionState": "dumps",
		"Offbox": &settings.OffboxTarget{
			Enabled: true, Host: "nas.local", LastStatus: "ok", EscrowState: "escrowed",
		},
		"OffboxConfigured":   true,
		"OffboxApps":         []OffboxAppRow{{Name: "calibre-web", DisplayName: "Calibre-Web", Enabled: true}},
		"OffboxToggledCount": 1,
		"OffboxQuotaPct":     0,
		"GuestBackup":        map[string]interface{}{"Available": false, "Note": "n/a"},
	}
}

func TestBackupsSplit_SectionsOnExactlyOnePage(t *testing.T) {
	pages := map[string]string{
		"backups":         renderBackupPage(t, "backups", splitTestData()),
		"backups_remote":  renderBackupPage(t, "backups_remote", splitTestData()),
		"backups_apps":    renderBackupPage(t, "backups_apps", splitTestData()),
		"backups_restore": renderBackupPage(t, "backups_restore", splitTestData()),
	}

	// marker → the ONE page it belongs to
	markers := map[string]string{
		"Tárhely áttekintés":                        "backups",         // Section 0
		"Rendszermentés (teljes mentés)":            "backups",         // whole-guest
		">Adatmentés<":                              "backups",         // stat cards (neutral branch)
		`id="offbox-section"`:                       "backups_remote",  // the offbox anchor target
		"Távoli mentési cél beállítása":             "backups_remote",  // manual-target form
		"Mely alkalmazások mentődnek":               "backups_remote",  // toggle list
		"<h3>Ütemezés</h3>":                         "backups_apps",    // schedule
		"<h3>Adatbázisok</h3>":                      "backups_apps",    // databases
		"Alkalmazások mentési állapota":             "backups_apps",    // per-app rows
		`id="restore-app"`:                          "backups_restore", // restore panel
		"Ellenőrző visszaállítás a távoli tárolóból": "backups_restore", // moved restore-to-verify
		`action="/backup/offbox/restore"`:           "backups_restore", // the MOVED form itself
	}
	for marker, home := range markers {
		for page, html := range pages {
			has := strings.Contains(html, marker)
			if page == home && !has {
				t.Errorf("%s: missing its own section marker %q", page, marker)
			}
			if page != home && has {
				t.Errorf("%s: renders %q which belongs to %s only", page, marker, home)
			}
		}
	}
}

// The tier-3 row actions must deep-link cross-page to the offbox section (the pre-split
// #offbox-section anchors would be orphaned on the apps page).
func TestBackupsSplit_CrossPageAnchors(t *testing.T) {
	data := splitTestData()
	data["AppBackupRows"] = []AppBackupRow{
		{StackName: "radarr", DisplayName: "Radarr", Tier3State: "off"},
	}
	html := renderBackupPage(t, "backups_apps", data)
	if !strings.Contains(html, `href="/backups/remote#offbox-section"`) {
		t.Error("tier-3 'Bekapcsolás' must link cross-page to /backups/remote#offbox-section")
	}
	if strings.Contains(html, `href="#offbox-section"`) {
		t.Error("orphaned same-page #offbox-section anchor survives on the apps page")
	}
}

// Felhom-offsite status card (v0.124.0, decision 2): three honest states, display-only —
// the card itself must never carry a form or button (no state change from the card, ever).
func TestBackupsRemote_OffsiteStatusCardStates(t *testing.T) {
	cardOf := func(html string) string {
		i := strings.Index(html, `id="felhom-offsite-card"`)
		if i < 0 {
			return ""
		}
		j := strings.Index(html[i:], "</div>")
		return html[i : i+j]
	}

	// State 1: no target configured → the opt-in pitch (and no "Aktív" headline).
	data := splitTestData()
	data["OffboxConfigured"] = false
	data["Offbox"] = nil
	data["OffboxToggledCount"] = 0
	html := renderBackupPage(t, "backups_remote", data)
	if !strings.Contains(html, "Felhom offsite tárhely — igényelhető szolgáltatás. Titkosított, házon kívüli másolat a mentéseidről. Érdeklődj az üzemeltetőnél.") {
		t.Error("state 1: the opt-in pitch is missing")
	}
	if strings.Contains(html, "Aktív — nincs kijelölt alkalmazás") {
		t.Error("state 1 must not render the state-2 headline")
	}
	if card := cardOf(html); strings.Contains(card, "<form") || strings.Contains(card, "<button") {
		t.Error("the status card must be display-only (no form/button)")
	}

	// State 2: applied, zero apps toggled → the honest active-but-empty headline.
	data = splitTestData()
	data["OffboxToggledCount"] = 0
	data["OffboxApps"] = []OffboxAppRow{{Name: "calibre-web", DisplayName: "Calibre-Web", Enabled: false}}
	html = renderBackupPage(t, "backups_remote", data)
	if !strings.Contains(html, "Aktív — nincs kijelölt alkalmazás") {
		t.Error("state 2: 'Aktív — nincs kijelölt alkalmazás' missing")
	}
	if strings.Contains(html, "igényelhető szolgáltatás") {
		t.Error("state 2 must not render the state-1 pitch")
	}
	if card := cardOf(html); strings.Contains(card, "<form") || strings.Contains(card, "<button") {
		t.Error("the status card must be display-only (no form/button)")
	}

	// State 3: applied + toggled → NO card; the regular status block carries the state.
	html = renderBackupPage(t, "backups_remote", splitTestData())
	if strings.Contains(html, `id="felhom-offsite-card"`) {
		t.Error("state 3 must not render the status card (the status block is the state)")
	}
	if !strings.Contains(html, "Utolsó távoli mentés") {
		t.Error("state 3: the regular status block is missing")
	}
}

// Route → handler wiring: each sub-route sets its own .Page id, so the sidebar child renders
// active on the right page (backupMgr nil → the empty state renders, the nav still does).
func TestBackupsSplit_RoutesSetPageIDs(t *testing.T) {
	s := testServer(t)
	s.loadTemplates()

	cases := []struct {
		path   string
		active string
	}{
		{"/backups/remote", `href="/backups/remote" class="active"`},
		{"/backups/apps", `href="/backups/apps" class="active"`},
		{"/backups/restore", `href="/backups/restore" class="active"`},
	}
	for _, c := range cases {
		rr := httptest.NewRecorder()
		req := httptest.NewRequest("GET", c.path, nil)
		switch c.path {
		case "/backups/remote":
			s.backupsRemoteHandler(rr, req)
		case "/backups/apps":
			s.backupsAppsHandler(rr, req)
		case "/backups/restore":
			s.backupsRestoreHandler(rr, req)
		}
		if rr.Code != 200 {
			t.Fatalf("%s: status %d", c.path, rr.Code)
		}
		if !strings.Contains(rr.Body.String(), c.active) {
			t.Errorf("%s: sidebar child not active (want %q)", c.path, c.active)
		}
	}
}
