package store

import "testing"

func TestHostRecoveryCredential_RoundTripUpsertAndAbsent(t *testing.T) {
	s := newTestStore(t)
	if err := s.UpsertHost(&Host{HostID: "h1", CustomerID: "c1", APIKey: "k1"}); err != nil {
		t.Fatalf("UpsertHost: %v", err)
	}

	// absent → (nil, nil) + Has=false
	got, err := s.GetHostRecoveryCredential("h1")
	if err != nil || got != nil {
		t.Fatalf("absent cred: got %+v / %v (want nil,nil)", got, err)
	}
	has, _ := s.HasHostRecoveryCredential("h1")
	if has {
		t.Fatal("HasHostRecoveryCredential must be false before any vault")
	}

	// vault → round-trips
	if err := s.SaveHostRecoveryCredential("h1", "root@pam", "s3cret-Aa1"); err != nil {
		t.Fatalf("SaveHostRecoveryCredential: %v", err)
	}
	got, err = s.GetHostRecoveryCredential("h1")
	if err != nil || got == nil {
		t.Fatalf("GetHostRecoveryCredential: %+v / %v", got, err)
	}
	if got.Username != "root@pam" || got.Secret != "s3cret-Aa1" {
		t.Fatalf("round-trip mismatch: %+v", got)
	}
	if has, _ := s.HasHostRecoveryCredential("h1"); !has {
		t.Fatal("HasHostRecoveryCredential must be true after vault")
	}

	// upsert (rotate) → overwrites last-write-wins
	if err := s.SaveHostRecoveryCredential("h1", "root@pam", "rotated-Bb2"); err != nil {
		t.Fatalf("re-vault: %v", err)
	}
	got, _ = s.GetHostRecoveryCredential("h1")
	if got.Secret != "rotated-Bb2" {
		t.Fatalf("rotate did not overwrite: %+v", got)
	}
}

// GetHostRecoveryMeta is the render path's accessor (hub v0.84.0). It returns username + set_at
// and, by CONSTRUCTION, cannot return the secret: neither HostRecoveryMeta nor the SELECT names the
// `secret` column, so there is no runtime assertion to write for that half — adding a Secret field
// would not fail this test, it would fail to compile at every call site that never asked for one.
// The runtime half asserted here is the metadata round-trip and the absent case.
func TestGetHostRecoveryMeta_MetadataOnly(t *testing.T) {
	s := newTestStore(t)
	if err := s.UpsertHost(&Host{HostID: "h1", CustomerID: "c1", APIKey: "k1"}); err != nil {
		t.Fatalf("UpsertHost: %v", err)
	}

	// absent → (nil, nil), never an error the page has to special-case
	m, err := s.GetHostRecoveryMeta("h1")
	if err != nil || m != nil {
		t.Fatalf("absent meta: got %+v / %v (want nil,nil)", m, err)
	}

	if err := s.SaveHostRecoveryCredential("h1", "root@pam", "s3cret-Aa1"); err != nil {
		t.Fatalf("SaveHostRecoveryCredential: %v", err)
	}
	m, err = s.GetHostRecoveryMeta("h1")
	if err != nil || m == nil {
		t.Fatalf("GetHostRecoveryMeta: %+v / %v", m, err)
	}
	if m.HostID != "h1" || m.Username != "root@pam" {
		t.Fatalf("meta mismatch: %+v", m)
	}
	if m.SetAt.IsZero() {
		t.Fatal("SetAt did not parse — the card cannot render staleness without it")
	}

	// an unknown host is the absent case too, not an error
	if m, err := s.GetHostRecoveryMeta("nope"); err != nil || m != nil {
		t.Fatalf("unknown host: got %+v / %v (want nil,nil)", m, err)
	}
}

func TestGetHostMgmtPlaneStates_ParsesHealMarker(t *testing.T) {
	s := newTestStore(t)
	if err := s.UpsertHost(&Host{HostID: "h1", CustomerID: "c1", APIKey: "k1"}); err != nil {
		t.Fatalf("UpsertHost: %v", err)
	}
	// a report WITH a heal marker
	report := `{"host_id":"h1","mgmt_plane":{"privsep_dir_ok":true,"sshd_reachable":true,"healed_recently":true,"privsep_healed_at":"2026-07-05T16:42:17Z"}}`
	if err := s.SaveHostReport("h1", "c1", []byte(report), HostReportDenorm{}); err != nil {
		t.Fatalf("SaveHostReport: %v", err)
	}
	rows, err := s.GetHostMgmtPlaneStates()
	if err != nil {
		t.Fatalf("GetHostMgmtPlaneStates: %v", err)
	}
	var found bool
	for _, r := range rows {
		if r.HostID == "h1" {
			found = true
			if !r.PrivsepDirOK || r.PrivsepHealedAt != "2026-07-05T16:42:17Z" {
				t.Fatalf("parsed row wrong: %+v", r)
			}
		}
	}
	if !found {
		t.Fatal("h1 not in mgmt-plane states")
	}

	// a report WITHOUT the stanza (old agent) → zero values, no crash
	if err := s.SaveHostReport("h1", "c1", []byte(`{"host_id":"h1"}`), HostReportDenorm{}); err != nil {
		t.Fatalf("SaveHostReport2: %v", err)
	}
	rows, _ = s.GetHostMgmtPlaneStates()
	for _, r := range rows {
		if r.HostID == "h1" && r.PrivsepHealedAt != "" {
			t.Fatalf("old-agent report should yield empty healed_at, got %+v", r)
		}
	}
}
