package domain

import (
	"testing"
	"time"
)

func TestNotificationType_Constants(t *testing.T) {
	tests := map[string]NotificationType{
		"ExpirationWarning": NotificationTypeExpirationWarning,
		"RenewalSuccess":    NotificationTypeRenewalSuccess,
		"RenewalFailure":    NotificationTypeRenewalFailure,
		"DeploymentSuccess": NotificationTypeDeploymentSuccess,
		"DeploymentFailure": NotificationTypeDeploymentFailure,
		"PolicyViolation":   NotificationTypePolicyViolation,
		"Revocation":        NotificationTypeRevocation,
	}
	for expected, got := range tests {
		if string(got) != expected {
			t.Errorf("expected %q, got %q", expected, string(got))
		}
	}
}

func TestNotificationChannel_Constants(t *testing.T) {
	tests := map[string]NotificationChannel{
		"Email":     NotificationChannelEmail,
		"Webhook":   NotificationChannelWebhook,
		"Slack":     NotificationChannelSlack,
		"Teams":     NotificationChannelTeams,
		"PagerDuty": NotificationChannelPagerDuty,
		"OpsGenie":  NotificationChannelOpsGenie,
	}
	for expected, got := range tests {
		if string(got) != expected {
			t.Errorf("expected %q, got %q", expected, string(got))
		}
	}
}

func TestNotificationEvent_Fields(t *testing.T) {
	// This test verifies the NotificationEvent struct can be instantiated
	// with all expected fields.
	certID := "mc-123"
	errorMsg := "failed to send"
	event := &NotificationEvent{
		ID:            "notif-1",
		Type:          NotificationTypeExpirationWarning,
		CertificateID: &certID,
		Channel:       NotificationChannelSlack,
		Recipient:     "alerts@example.com",
		Message:       "Certificate expiring in 30 days",
		Status:        "sent",
		Error:         &errorMsg,
	}

	if event.ID != "notif-1" {
		t.Errorf("expected ID 'notif-1', got %s", event.ID)
	}

	if event.Type != NotificationTypeExpirationWarning {
		t.Errorf("expected type ExpirationWarning, got %s", string(event.Type))
	}

	if event.Channel != NotificationChannelSlack {
		t.Errorf("expected channel Slack, got %s", string(event.Channel))
	}

	if event.CertificateID == nil || *event.CertificateID != "mc-123" {
		t.Errorf("expected CertificateID mc-123, got %v", event.CertificateID)
	}

	if event.Error == nil || *event.Error != "failed to send" {
		t.Errorf("expected error 'failed to send', got %v", event.Error)
	}
}

// TestNotificationStatus_Constants verifies that I-005 introduces a typed
// NotificationStatus alongside canonical lowercase string constants covering
// the pending → sent, pending → failed → dead, and pending → read transitions.
// The Red signal here is a compile error: the type and the NotificationStatusDead
// constant do not exist before Phase 2 Green.
func TestNotificationStatus_Constants(t *testing.T) {
	tests := map[string]NotificationStatus{
		"pending": NotificationStatusPending,
		"sent":    NotificationStatusSent,
		"failed":  NotificationStatusFailed,
		"dead":    NotificationStatusDead,
		"read":    NotificationStatusRead,
	}
	for expected, got := range tests {
		if string(got) != expected {
			t.Errorf("expected %q, got %q", expected, string(got))
		}
	}
}

// TestNotificationEvent_RetryFields verifies the I-005 retry/DLQ columns are
// surfaced on the domain model: a RetryCount counter, a nullable NextRetryAt
// timestamp used by the retry-sweep partial index, and a nullable LastError
// string preserving the most recent transient failure for operator triage.
// The Red signal is a compile error — these fields do not exist yet.
func TestNotificationEvent_RetryFields(t *testing.T) {
	next := time.Now().Add(2 * time.Minute)
	lastErr := "connection refused"
	event := &NotificationEvent{
		ID:           "notif-retry-001",
		Type:         NotificationTypeExpirationWarning,
		Channel:      NotificationChannelWebhook,
		Recipient:    "https://hooks.example.com/certs",
		Message:      "retry me",
		Status:       string(NotificationStatusFailed),
		RetryCount:   3,
		NextRetryAt:  &next,
		LastError:    &lastErr,
	}

	if event.RetryCount != 3 {
		t.Errorf("expected RetryCount 3, got %d", event.RetryCount)
	}
	if event.NextRetryAt == nil || !event.NextRetryAt.Equal(next) {
		t.Errorf("expected NextRetryAt %v, got %v", next, event.NextRetryAt)
	}
	if event.LastError == nil || *event.LastError != "connection refused" {
		t.Errorf("expected LastError 'connection refused', got %v", event.LastError)
	}
}
