<?php

declare(strict_types=1);

namespace App\Framework\Scheduler\ValueObjects;

use App\Framework\Core\ValueObjects\Timestamp;
use App\Framework\Scheduler\Contracts\ScheduleInterface;

/**
 * Value Object representing a scheduled task
 */
final readonly class ScheduledTask
{
    public function __construct(
        public string $id,
        public ScheduleInterface $schedule,
        public mixed $task,
        public ?Timestamp $nextExecution = null,
        public ?Timestamp $lastExecution = null,
        public int $executionCount = 0
    ) {
        if (! is_callable($this->task)) {
            throw new \InvalidArgumentException('Task must be callable');
        }
    }

    public function isDue(?Timestamp $at = null): bool
    {
        $at = $at ?? Timestamp::now();

        if (! $this->nextExecution) {
            return false;
        }

        return $at->isAfter($this->nextExecution) || $at->equals($this->nextExecution);
    }

    public function withNextExecution(?Timestamp $nextExecution): self
    {
        return new self(
            id: $this->id,
            schedule: $this->schedule,
            task: $this->task,
            nextExecution: $nextExecution,
            lastExecution: $this->lastExecution,
            executionCount: $this->executionCount
        );
    }

    public function withLastExecution(Timestamp $lastExecution): self
    {
        return new self(
            id: $this->id,
            schedule: $this->schedule,
            task: $this->task,
            nextExecution: $this->nextExecution,
            lastExecution: $lastExecution,
            executionCount: $this->executionCount + 1
        );
    }

    public function toArray(): array
    {
        return [
            'id' => $this->id,
            'schedule' => $this->schedule->toArray(),
            'next_execution' => $this->nextExecution?->toRfc3339(),
            'last_execution' => $this->lastExecution?->toRfc3339(),
            'execution_count' => $this->executionCount,
        ];
    }
}
