<?php

namespace PHPNative\Async;

use parallel\Runtime;
use parallel\Future;

class AsyncTask
{
    private ?Future $future = null;
    private mixed $result = null;
    private bool $completed = false;
    private bool $failed = false;
    private mixed $error = null;
    private mixed $onComplete = null;
    private mixed $onError = null;
    private mixed $task = null;

    public function __construct(
        callable $task
    ) {
        $this->task = $task;
    }

    /**
     * Start the async task execution
     */
    public function start(): void
    {
        if ($this->future !== null) {
            return; // Already started
        }

        try {
            // Create runtime with bootstrap file to load autoloader
            $bootstrapPath = __DIR__ . '/bootstrap.php';
            $runtime = new Runtime($bootstrapPath);
            $this->future = $runtime->run($this->task);
        } catch (\Throwable $e) {
            $this->failed = true;
            $this->error = $e;
            $this->completed = true;
        }
    }

    /**
     * Check if task is completed and process result
     */
    public function update(): void
    {
        if ($this->completed || $this->future === null) {
            return;
        }

        // Check if future is done without blocking
        if ($this->future->done()) {
            try {
                $this->result = $this->future->value();
                $this->completed = true;

                if ($this->onComplete !== null) {
                    ($this->onComplete)($this->result);
                }
            } catch (\Throwable $e) {
                $this->failed = true;
                $this->error = $e;
                $this->completed = true;

                if ($this->onError !== null) {
                    ($this->onError)($this->error);
                }
            }
        }
    }

    /**
     * Set callback for successful completion
     */
    public function onComplete(callable $callback): self
    {
        $this->onComplete = $callback;
        return $this;
    }

    /**
     * Set callback for errors
     */
    public function onError(callable $callback): self
    {
        $this->onError = $callback;
        return $this;
    }

    /**
     * Check if task is completed
     */
    public function isCompleted(): bool
    {
        return $this->completed;
    }

    /**
     * Check if task failed
     */
    public function isFailed(): bool
    {
        return $this->failed;
    }

    /**
     * Get the result (only available after completion)
     */
    public function getResult(): mixed
    {
        return $this->result;
    }

    /**
     * Get the error (only available after failure)
     */
    public function getError(): mixed
    {
        return $this->error;
    }
}
