package worker

import "fmt"

// DurabilityClass states what a successful producer acknowledgement promises.
// It is a design and conformance classification, not proof that an
// implementation satisfies the promise.
type DurabilityClass string

const (
	DurabilityDurableCritical     DurabilityClass = "durable-critical"
	DurabilityDerivedReconcilable DurabilityClass = "derived-reconcilable"
	DurabilityBestEffort          DurabilityClass = "best-effort"
)

func (c DurabilityClass) Validate() error {
	switch c {
	case DurabilityDurableCritical, DurabilityDerivedReconcilable, DurabilityBestEffort:
		return nil
	default:
		return fmt.Errorf("worker: unknown durability class %q", c)
	}
}

// EffectSemantics states the replay proof owned by a work family.
type EffectSemantics string

const (
	// EffectTransactional means effect and terminal disposition commit in one
	// domain-owned transaction.
	EffectTransactional EffectSemantics = "transactional"
	// EffectIdempotent means replay uses a stable idempotency key or observes a
	// queryable downstream outcome before another effect attempt.
	EffectIdempotent EffectSemantics = "idempotent-or-observable"
	// EffectOutcomeUncertain means an ambiguous remote outcome is durably
	// quarantined instead of blindly replayed.
	EffectOutcomeUncertain EffectSemantics = "outcome-uncertain"
	// EffectConvergent means the effect is derived from a canonical source and
	// repeated execution converges to that source.
	EffectConvergent EffectSemantics = "convergent"
	// EffectLossTolerant means loss is part of the explicitly documented
	// best-effort contract.
	EffectLossTolerant EffectSemantics = "loss-tolerant"
)

func (s EffectSemantics) Validate() error {
	switch s {
	case EffectTransactional, EffectIdempotent, EffectOutcomeUncertain, EffectConvergent, EffectLossTolerant:
		return nil
	default:
		return fmt.Errorf("worker: unknown effect semantics %q", s)
	}
}

// FamilyClass is the minimum reliability declaration for one work family.
// Validate checks only that the declaration is coherent; behavioral
// conformance must still be exercised against the real domain store.
type FamilyClass struct {
	Durability DurabilityClass
	Effect     EffectSemantics
}

func (c FamilyClass) Validate() error {
	if err := c.Durability.Validate(); err != nil {
		return err
	}
	if err := c.Effect.Validate(); err != nil {
		return err
	}
	switch c.Durability {
	case DurabilityDurableCritical:
		if c.Effect == EffectConvergent || c.Effect == EffectLossTolerant {
			return fmt.Errorf("worker: durable-critical work requires transactional, idempotent, or uncertain-outcome effect semantics")
		}
	case DurabilityDerivedReconcilable:
		if c.Effect != EffectConvergent {
			return fmt.Errorf("worker: derived-reconcilable work requires convergent effect semantics")
		}
	case DurabilityBestEffort:
		if c.Effect != EffectLossTolerant {
			return fmt.Errorf("worker: best-effort work requires loss-tolerant effect semantics")
		}
	}
	return nil
}
