trashed()) { return self::forLifecycle(TenantLifecycle::Archived); } return self::fromValue($tenant->status); } public static function fromValue(mixed $value): self { $lifecycle = TenantLifecycle::tryFromValue($value); if ($lifecycle instanceof TenantLifecycle) { return self::forLifecycle($lifecycle); } return self::invalid(TenantLifecycle::normalize($value)); } public static function forLifecycle(TenantLifecycle $lifecycle): self { return match ($lifecycle) { TenantLifecycle::Draft => new self( value: $lifecycle->value, label: $lifecycle->label(), badgeColor: 'gray', badgeIcon: 'heroicon-m-document', badgeIconColor: null, shortDescription: 'Draft tenant awaiting onboarding completion.', longDescription: 'This tenant is still in draft and remains available for setup and review, but it is not selectable as active context until onboarding progresses.', isInvalidFallback: false, lifecycle: $lifecycle, ), TenantLifecycle::Onboarding => new self( value: $lifecycle->value, label: $lifecycle->label(), badgeColor: 'warning', badgeIcon: 'heroicon-m-arrow-path', badgeIconColor: null, shortDescription: 'Onboarding is in progress.', longDescription: 'This tenant is still onboarding. It remains visible on management and review surfaces, but it is not selectable as active context until onboarding completes.', isInvalidFallback: false, lifecycle: $lifecycle, ), TenantLifecycle::Active => new self( value: $lifecycle->value, label: $lifecycle->label(), badgeColor: 'success', badgeIcon: 'heroicon-m-check-circle', badgeIconColor: null, shortDescription: 'Active tenant available for normal operations.', longDescription: 'This tenant is active and available across normal management, tenant selection, and operational follow-up flows.', isInvalidFallback: false, lifecycle: $lifecycle, ), TenantLifecycle::Archived => new self( value: $lifecycle->value, label: $lifecycle->label(), badgeColor: 'gray', badgeIcon: 'heroicon-m-archive-box', badgeIconColor: null, shortDescription: 'Archived tenant retained for inspection only.', longDescription: 'This tenant remains available for inspection and audit history, but it is not selectable as active context until you restore it.', isInvalidFallback: false, lifecycle: $lifecycle, ), }; } public static function invalid(?string $normalizedValue = null): self { return new self( value: $normalizedValue ?? 'invalid', label: 'Invalid lifecycle', badgeColor: 'danger', badgeIcon: 'heroicon-m-exclamation-triangle', badgeIconColor: 'danger', shortDescription: 'Lifecycle data is invalid and requires review.', longDescription: 'The stored tenant lifecycle value is not canonical. Review the source data before treating this tenant as draft, onboarding, active, or archived.', isInvalidFallback: true, lifecycle: null, ); } public function badge(): BadgeSpec { return new BadgeSpec( label: $this->label, color: $this->badgeColor, icon: $this->badgeIcon, iconColor: $this->badgeIconColor, ); } public function isSelectableAsContext(): bool { return $this->lifecycle?->canSelectAsContext() ?? false; } public function lowercaseLabel(): string { return strtolower($this->label); } }