id, campaignId: $this->campaignId, userId: $this->userId, platform: $this->platform, status: RegistrationStatus::COMPLETED, registeredAt: $this->registeredAt, processedAt: Timestamp::now(), errorMessage: null, retryCount: $this->retryCount, ); } /** * Mark as failed with error message */ public function markAsFailed(string $errorMessage): self { return new self( id: $this->id, campaignId: $this->campaignId, userId: $this->userId, platform: $this->platform, status: RegistrationStatus::FAILED, registeredAt: $this->registeredAt, processedAt: Timestamp::now(), errorMessage: $errorMessage, retryCount: $this->retryCount + 1, ); } /** * Mark as revoked (user disconnected OAuth) */ public function markAsRevoked(): self { return new self( id: $this->id, campaignId: $this->campaignId, userId: $this->userId, platform: $this->platform, status: RegistrationStatus::REVOKED, registeredAt: $this->registeredAt, processedAt: Timestamp::now(), errorMessage: 'OAuth token revoked by user', retryCount: $this->retryCount, ); } /** * Reset for retry */ public function resetForRetry(): self { if (! $this->status->canRetry()) { throw new \RuntimeException('Cannot retry registration in status: ' . $this->status->value); } return new self( id: $this->id, campaignId: $this->campaignId, userId: $this->userId, platform: $this->platform, status: RegistrationStatus::PENDING, registeredAt: $this->registeredAt, processedAt: null, errorMessage: null, retryCount: $this->retryCount, ); } /** * Check if should be processed */ public function shouldProcess(): bool { return $this->status->shouldProcess(); } /** * Check if max retries exceeded */ public function hasExceededMaxRetries(int $maxRetries = 3): bool { return $this->retryCount >= $maxRetries; } /** * Convert to array for storage/API * * @return array */ public function toArray(): array { return [ 'id' => $this->id, 'campaign_id' => $this->campaignId, 'user_id' => $this->userId, 'platform' => $this->platform->value, 'status' => $this->status->value, 'registered_at' => $this->registeredAt->toTimestamp(), 'processed_at' => $this->processedAt?->toTimestamp(), 'error_message' => $this->errorMessage, 'retry_count' => $this->retryCount, ]; } /** * Create from database row * * @param array $row */ public static function fromArray(array $row): self { return new self( id: isset($row['id']) ? (int) $row['id'] : null, campaignId: (int) $row['campaign_id'], userId: (string) $row['user_id'], platform: StreamingPlatform::from($row['platform']), status: RegistrationStatus::from($row['status']), registeredAt: Timestamp::fromFloat((float) $row['registered_at']), processedAt: isset($row['processed_at']) ? Timestamp::fromFloat((float) $row['processed_at']) : null, errorMessage: $row['error_message'] ?? null, retryCount: (int) ($row['retry_count'] ?? 0), ); } }