<?php

declare(strict_types=1);

namespace App\Domain\PreSave;

use App\Domain\PreSave\ValueObjects\RegistrationStatus;
use App\Domain\PreSave\ValueObjects\StreamingPlatform;
use App\Framework\Core\ValueObjects\Timestamp;

/**
 * Pre-Save Registration Entity
 *
 * Represents a user's registration for a pre-save campaign
 */
final readonly class PreSaveRegistration
{
    public function __construct(
        public ?int $id,
        public int $campaignId,
        public string $userId,
        public StreamingPlatform $platform,
        public RegistrationStatus $status,
        public Timestamp $registeredAt,
        public ?Timestamp $processedAt = null,
        public ?string $errorMessage = null,
        public int $retryCount = 0,
    ) {
    }

    /**
     * Create new registration
     */
    public static function create(
        int $campaignId,
        string $userId,
        StreamingPlatform $platform,
    ): self {
        return new self(
            id: null,
            campaignId: $campaignId,
            userId: $userId,
            platform: $platform,
            status: RegistrationStatus::PENDING,
            registeredAt: Timestamp::now(),
        );
    }

    /**
     * Mark as completed
     */
    public function markAsCompleted(): self
    {
        return new self(
            id: $this->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<string, mixed>
     */
    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<string, mixed> $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),
        );
    }
}
