package domain

import "testing"

func TestCertificateStatus_Constants(t *testing.T) {
	tests := map[string]CertificateStatus{
		"Pending":             CertificateStatusPending,
		"Active":              CertificateStatusActive,
		"Expiring":            CertificateStatusExpiring,
		"Expired":             CertificateStatusExpired,
		"RenewalInProgress":   CertificateStatusRenewalInProgress,
		"Failed":              CertificateStatusFailed,
		"Revoked":             CertificateStatusRevoked,
		"Archived":            CertificateStatusArchived,
	}
	for expected, got := range tests {
		if string(got) != expected {
			t.Errorf("expected %q, got %q", expected, string(got))
		}
	}
}

func TestDefaultAlertThresholds(t *testing.T) {
	defaults := DefaultAlertThresholds()
	expected := []int{30, 14, 7, 0}
	if len(defaults) != len(expected) {
		t.Errorf("expected %d thresholds, got %d", len(expected), len(defaults))
	}
	for i, v := range expected {
		if i >= len(defaults) {
			break
		}
		if defaults[i] != v {
			t.Errorf("threshold[%d]: expected %d, got %d", i, v, defaults[i])
		}
	}
}

func TestRenewalPolicy_EffectiveAlertThresholds_Custom(t *testing.T) {
	policy := &RenewalPolicy{
		AlertThresholdsDays: []int{60, 30, 14, 7},
	}
	result := policy.EffectiveAlertThresholds()
	if len(result) != 4 {
		t.Errorf("expected 4 thresholds, got %d", len(result))
	}
	if result[0] != 60 {
		t.Errorf("expected first threshold 60, got %d", result[0])
	}
}

func TestRenewalPolicy_EffectiveAlertThresholds_Default(t *testing.T) {
	policy := &RenewalPolicy{
		AlertThresholdsDays: []int{},
	}
	result := policy.EffectiveAlertThresholds()
	expected := DefaultAlertThresholds()
	if len(result) != len(expected) {
		t.Errorf("expected %d thresholds, got %d", len(expected), len(result))
	}
	for i, v := range expected {
		if i >= len(result) {
			break
		}
		if result[i] != v {
			t.Errorf("threshold[%d]: expected %d, got %d", i, v, result[i])
		}
	}
}

func TestRenewalPolicy_EffectiveAlertThresholds_Nil(t *testing.T) {
	policy := &RenewalPolicy{
		AlertThresholdsDays: nil,
	}
	result := policy.EffectiveAlertThresholds()
	expected := DefaultAlertThresholds()
	if len(result) != len(expected) {
		t.Errorf("expected %d thresholds, got %d", len(expected), len(result))
	}
}

// --- 45-Day / Short-Lived Certificate Renewal Threshold Tests ---
// These tests validate that certctl's renewal logic works correctly with shorter-lived
// certificates as the industry transitions from 90-day to 45-day validity (SC-081v3)
// and Let's Encrypt introduces 6-day "shortlived" profiles.

func TestRenewalThresholds_45DayCert(t *testing.T) {
	// A 45-day cert with default thresholds [30, 14, 7, 0]:
	// - 30-day alert fires when cert is 15 days old (45 - 30 = 15 days remaining)
	// - 14-day alert fires when cert is 31 days old
	// - 7-day alert fires when cert is 38 days old
	// - 0-day alert fires at expiry
	// The 30-day threshold fires at the 1/3 lifetime mark — this is correct
	// (Let's Encrypt recommends renewal at 2/3 through lifetime, i.e. day 30).
	thresholds := DefaultAlertThresholds()

	certLifetimeDays := 45
	for _, threshold := range thresholds {
		daysCertAge := certLifetimeDays - threshold
		if daysCertAge < 0 {
			t.Errorf("threshold %d days exceeds cert lifetime %d days", threshold, certLifetimeDays)
		}
	}

	// Verify the first alert (30 days) fires when 15 days remain
	// This means the cert is 15 days old — at 1/3 of its lifetime
	firstAlertDaysRemaining := certLifetimeDays - (certLifetimeDays - thresholds[0])
	if firstAlertDaysRemaining != 30 {
		t.Errorf("expected first alert at 30 days remaining, got %d", firstAlertDaysRemaining)
	}

	// The renewal window query (31 days ahead) will find 45-day certs
	// when they have 31 or fewer days remaining — at day 14 of a 45-day cert.
	renewalWindowDays := 31
	certAgeAtRenewalCheck := certLifetimeDays - renewalWindowDays
	if certAgeAtRenewalCheck != 14 {
		t.Errorf("expected renewal check to find cert at age %d, got %d", 14, certAgeAtRenewalCheck)
	}
}

func TestRenewalThresholds_6DayCert(t *testing.T) {
	// A 6-day "shortlived" cert with default thresholds [30, 14, 7, 0]:
	// - The 30-day, 14-day, and 7-day thresholds can NEVER fire (cert expires before reaching them)
	// - Only the 0-day threshold fires at expiry
	// For 6-day certs, ARI (RFC 9773) is the expected renewal path — the CA directs timing.
	// Short-lived certs also skip CRL/OCSP (revocation via expiry, per M15b).
	thresholds := DefaultAlertThresholds()
	certLifetimeDays := 6

	firingThresholds := 0
	for _, threshold := range thresholds {
		if threshold < certLifetimeDays {
			firingThresholds++
		}
	}

	// Only the 0-day threshold can fire (0 < 6).
	// The 7-day threshold means "alert when 7 days remain" — a 6-day cert
	// never has 7 days remaining, so it never fires.
	// For 6-day certs, ARI (RFC 9773) is the expected renewal path.
	if firingThresholds != 1 {
		t.Errorf("expected 1 threshold to fire for 6-day cert, got %d", firingThresholds)
	}

	// The renewal window query (31 days ahead) will find 6-day certs immediately
	// (they're always within the 31-day window from the moment they're issued).
	renewalWindowDays := 31
	if certLifetimeDays < renewalWindowDays {
		// This is expected — 6-day certs are always in the renewal window.
		// ARI should override the threshold-based logic for these certs.
	}
}

func TestRenewalThresholds_47DayCert(t *testing.T) {
	// SC-081v3 mandates 47-day max validity by March 2029.
	// Default thresholds [30, 14, 7, 0] should work correctly.
	thresholds := DefaultAlertThresholds()
	certLifetimeDays := 47

	for _, threshold := range thresholds {
		if threshold > certLifetimeDays {
			t.Errorf("threshold %d exceeds cert lifetime %d", threshold, certLifetimeDays)
		}
	}

	// With RenewalWindowDays=30, renewal triggers at day 17 (47-30=17).
	// That's at the 36% mark of the cert's lifetime — reasonable.
	renewalWindowDays := 30
	renewalDay := certLifetimeDays - renewalWindowDays
	if renewalDay != 17 {
		t.Errorf("expected renewal at day 17, got %d", renewalDay)
	}
}

func TestRenewalThresholds_200DayCert(t *testing.T) {
	// SC-081v3 Phase 1: 200-day max validity (March 2026).
	// All default thresholds should fire normally.
	thresholds := DefaultAlertThresholds()
	certLifetimeDays := 200

	for _, threshold := range thresholds {
		if threshold > certLifetimeDays {
			t.Errorf("threshold %d exceeds cert lifetime %d", threshold, certLifetimeDays)
		}
	}
}

func TestRenewalThresholds_100DayCert(t *testing.T) {
	// SC-081v3 Phase 2: 100-day max validity (March 2027).
	thresholds := DefaultAlertThresholds()
	certLifetimeDays := 100

	for _, threshold := range thresholds {
		if threshold > certLifetimeDays {
			t.Errorf("threshold %d exceeds cert lifetime %d", threshold, certLifetimeDays)
		}
	}

	// With default 31-day renewal window, renewal triggers at day 69 — at 69% of lifetime.
	// This is close to Let's Encrypt's recommended 2/3 mark.
	renewalWindowDays := 31
	renewalDay := certLifetimeDays - renewalWindowDays
	if renewalDay != 69 {
		t.Errorf("expected renewal at day 69, got %d", renewalDay)
	}
}
