package web

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

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

// R-112 — SCENARIO E: THE SEAM. This is the test whose absence let E-2 ship.
//
// The endpoint was byte-correct the whole time. `resolveBackupTargetState` produced the right state,
// `degradedMessageFor` produced the right Hungarian, and v0.185.1 even added a test proving the route
// dispatched. None of that was ever reachable by a customer, because NOTHING fetched or rendered it:
// the controller's templates fetch 18 distinct /api/storage/* endpoints and backup-target was one of
// only two with zero references (felhom.eu audits/E2D-fresh-vm-2026-07-29.md §5.1).
//
// So these tests deliberately do NOT call the resolver and assert its string — that proves the
// resolver, which was never broken. They drive `backupsHandler` over httptest and assert the RENDERED
// HTML, travelling handler → backupTargetView → resolveBackupTargetState → degradedMessageFor →
// the production "backups" template. Delete the one line in backupsHandler that sets
// data["BackupTarget"] and every assertion below fails, which is precisely the class of regression
// that shipped five times in this project.

// renderBackupsPage drives the REAL page handler and returns the HTML a browser would receive.
func renderBackupsPage(t *testing.T, primary string, disks []agentapi.DiskInfo, registerPath string) string {
	t.Helper()
	s := absentHarness(t, primary, disks, registerPath)
	s.loadTemplates()
	rr := httptest.NewRecorder()
	s.backupsHandler(rr, httptest.NewRequest("GET", "/backups", nil))
	if rr.Code != 200 {
		t.Fatalf("backups page returned %d, want 200", rr.Code)
	}
	return rr.Body.String()
}

// C — configured, drive absent: the truthful copy reaches the page, and no offer does.
func TestBackupsPageRendersTheAbsentDriveCopy(t *testing.T) {
	html := renderBackupsPage(t, "felhom-backup", []agentapi.DiskInfo{theVanishedDrive}, "/mnt/felhom-drives/mentes2")

	if !strings.Contains(html, backupTargetAbsentText) {
		t.Error("the absent-drive copy never reached the page — the customer is told nothing while " +
			"their backup drive is missing (R-112: the state had no consumer at all)")
	}
	if strings.Contains(html, backupTargetDegradedText) {
		t.Error("the page shows the SYSTEM-DISK copy for an absent configured drive (R-114)")
	}
	// Assert the CONTROL's markup, not the bare id: the page script always contains
	// getElementById('backup-target-assign'), so a substring match on the id alone matches the
	// script and reports a control that is not there. (This test caught exactly that on itself.)
	if strings.Contains(html, `id="backup-target-assign"`) {
		t.Error("an offer control rendered while the configured target is absent — the remedy is to " +
			"reconnect that drive, not to pick another")
	}
	if strings.Contains(html, `id="backup-target-offer"`) {
		t.Error("the offer block rendered while the configured target is absent")
	}
}

// A — never configured: the copy AND the offer control both render, and the control carries the
// drive's path so accepting it can only ever assign that one.
func TestBackupsPageRendersTheOfferWhenNeverConfigured(t *testing.T) {
	html := renderBackupsPage(t, builtinLocalTarget, []agentapi.DiskInfo{{
		Name: "hdd1", MountPath: "/mnt/hdd1", GuestPath: "/mnt/felhom-drives/hdd1", Role: "user-data",
	}}, "/mnt/felhom-drives/hdd1")

	if !strings.Contains(html, backupTargetDegradedText) {
		t.Error("the degraded copy never reached the page")
	}
	if !strings.Contains(html, backupTargetOfferText) {
		t.Error("the offer copy never reached the page")
	}
	if !strings.Contains(html, `id="backup-target-assign"`) {
		t.Error("no offer control rendered — the customer is told to attach a drive but given no way " +
			"to assign the one they already have")
	}
	if !strings.Contains(html, `data-path="/mnt/felhom-drives/hdd1"`) {
		t.Error("the offer control does not carry the offered drive's path")
	}
	// It is an OFFER: it must not submit itself.
	if strings.Contains(html, "backup-target-assign.click()") || strings.Contains(html, "autosubmit") {
		t.Error("the offer control auto-submits — declining must be possible by doing nothing")
	}
}

// B — healthy renders NOTHING. Assert the absence of all three strings, not the absence of an error.
func TestBackupsPageRendersNothingWhenHealthy(t *testing.T) {
	html := renderBackupsPage(t, "felhom-backup", []agentapi.DiskInfo{{
		Name: "mentes2", MountPath: "/mnt/mentes2", GuestPath: "/mnt/felhom-drives/mentes2",
		Role: "user-data", BackupTarget: true,
	}}, "/mnt/felhom-drives/mentes2")

	assertNoBackupTargetCopy(t, html, "a HEALTHY box grew a banner — a working configuration must "+
		"look normal, or every dashboard carries a permanent notice and warnings stop being read")
}

// D — unknown renders NOTHING. Not being able to ask the agent is not evidence of degradation.
func TestBackupsPageRendersNothingWhenAgentUnreachable(t *testing.T) {
	s := testServer(t)
	if err := s.settings.AddStoragePath(settings.StoragePath{Path: "/mnt/felhom-drives/hdd1"}); err != nil {
		t.Fatalf("register: %v", err)
	}
	// No tiersFn/disksFn seams and no configured endpoint → agentClient() fails → Known:false.
	s.loadTemplates()
	rr := httptest.NewRecorder()
	s.backupsHandler(rr, httptest.NewRequest("GET", "/backups", nil))

	assertNoBackupTargetCopy(t, rr.Body.String(), "an UNREACHABLE agent produced a customer warning — "+
		"absence of an answer is not evidence of degradation (R-88 Part 2's mistake)")
}

func assertNoBackupTargetCopy(t *testing.T, html, why string) {
	t.Helper()
	for _, s := range []struct{ frag, name string }{
		{backupTargetDegradedText, "the system-disk copy"},
		{backupTargetAbsentText, "the absent-drive copy"},
		{backupTargetOfferText, "the offer copy"},
	} {
		if strings.Contains(html, s.frag) {
			t.Errorf("%s rendered: %s", s.name, why)
		}
	}
	if strings.Contains(html, `id="backup-target-alert"`) {
		t.Errorf("the banner element rendered: %s", why)
	}
}

// The view is nil — not an empty struct — in the two silent states, so a template typo cannot
// accidentally decorate a working box with an empty alert box.
func TestBackupTargetViewIsNilWhenNothingShouldRender(t *testing.T) {
	healthy := absentHarness(t, "felhom-backup", []agentapi.DiskInfo{{
		MountPath: "/mnt/mentes2", GuestPath: "/mnt/felhom-drives/mentes2", Role: "user-data", BackupTarget: true,
	}}, "")
	if v := healthy.backupTargetView(context.Background()); v != nil {
		t.Errorf("healthy returned a non-nil view %+v — nil is what makes the template render nothing", v)
	}
	unknown := testServer(t)
	if v := unknown.backupTargetView(context.Background()); v != nil {
		t.Errorf("unknown returned a non-nil view %+v", v)
	}
}
