<?php

declare (strict_types=1);
namespace CelerSearch\Vendor\Meilisearch\Contracts;

use CelerSearch\Vendor\Meilisearch\Contracts\TaskDetails\DocumentAdditionOrUpdateDetails;
use CelerSearch\Vendor\Meilisearch\Contracts\TaskDetails\DocumentDeletionDetails;
use CelerSearch\Vendor\Meilisearch\Contracts\TaskDetails\DocumentEditionDetails;
use CelerSearch\Vendor\Meilisearch\Contracts\TaskDetails\DumpCreationDetails;
use CelerSearch\Vendor\Meilisearch\Contracts\TaskDetails\IndexCreationDetails;
use CelerSearch\Vendor\Meilisearch\Contracts\TaskDetails\IndexDeletionDetails;
use CelerSearch\Vendor\Meilisearch\Contracts\TaskDetails\IndexSwapDetails;
use CelerSearch\Vendor\Meilisearch\Contracts\TaskDetails\IndexUpdateDetails;
use CelerSearch\Vendor\Meilisearch\Contracts\TaskDetails\SettingsUpdateDetails;
use CelerSearch\Vendor\Meilisearch\Contracts\TaskDetails\TaskCancelationDetails;
use CelerSearch\Vendor\Meilisearch\Contracts\TaskDetails\TaskDeletionDetails;
use CelerSearch\Vendor\Meilisearch\Contracts\TaskDetails\UnknownTaskDetails;
use CelerSearch\Vendor\Meilisearch\Exceptions\LogicException;
/** @internal */
final class Task implements \ArrayAccess
{
    /**
     * @param non-negative-int                   $taskUid
     * @param non-empty-string|null              $indexUid
     * @param non-empty-string|null              $duration
     * @param \Closure(int, int, int): Task|null $await
     */
    public function __construct(private readonly int $taskUid, private readonly ?string $indexUid, private readonly TaskStatus $status, private readonly TaskType $type, private readonly \DateTimeImmutable $enqueuedAt, private readonly ?\DateTimeImmutable $startedAt = null, private readonly ?\DateTimeImmutable $finishedAt = null, private readonly ?string $duration = null, private readonly ?int $canceledBy = null, private readonly ?int $batchUid = null, private readonly ?TaskDetails $details = null, private readonly ?TaskError $error = null, private readonly array $raw = [], private readonly ?\Closure $await = null)
    {
    }
    /**
     * @return non-negative-int
     */
    public function getTaskUid() : int
    {
        return $this->taskUid;
    }
    /**
     * @return non-empty-string|null
     */
    public function getIndexUid() : ?string
    {
        return $this->indexUid;
    }
    public function getStatus() : TaskStatus
    {
        return $this->status;
    }
    public function getType() : TaskType
    {
        return $this->type;
    }
    public function getEnqueuedAt() : \DateTimeImmutable
    {
        return $this->enqueuedAt;
    }
    public function getStartedAt() : ?\DateTimeImmutable
    {
        return $this->startedAt;
    }
    public function getFinishedAt() : ?\DateTimeImmutable
    {
        return $this->finishedAt;
    }
    /**
     * @return non-empty-string|null
     */
    public function getDuration() : ?string
    {
        return $this->duration;
    }
    public function getCanceledBy() : ?int
    {
        return $this->canceledBy;
    }
    public function getBatchUid() : ?int
    {
        return $this->batchUid;
    }
    public function getDetails() : ?TaskDetails
    {
        return $this->details;
    }
    public function getError() : ?TaskError
    {
        return $this->error;
    }
    public function isFinished() : bool
    {
        return TaskStatus::Enqueued !== $this->status && TaskStatus::Processing !== $this->status;
    }
    public function wait(int $timeoutInMs = 5000, int $intervalInMs = 50) : Task
    {
        if ($this->isFinished()) {
            return $this;
        }
        if (null !== $this->await) {
            return ($this->await)($this->taskUid, $timeoutInMs, $intervalInMs);
        }
        throw new LogicException(\sprintf('Cannot wait for task because wait function is not provided.'));
    }
    /**
     * @return array<mixed>
     */
    public function toArray() : array
    {
        return $this->raw;
    }
    public function offsetSet(mixed $offset, mixed $value) : void
    {
        throw new LogicException('The Task object is immutable.');
    }
    public function offsetExists(mixed $offset) : bool
    {
        return isset($this->raw[$offset]);
    }
    public function offsetUnset(mixed $offset) : void
    {
        throw new LogicException('The Task object is immutable.');
    }
    public function offsetGet(mixed $offset) : mixed
    {
        return $this->raw[$offset] ?? null;
    }
    /**
     * @param array{
     *     taskUid?: int,
     *     uid?: int,
     *     indexUid?: non-empty-string,
     *     status: non-empty-string,
     *     type: non-empty-string,
     *     enqueuedAt: non-empty-string,
     *     startedAt?: non-empty-string|null,
     *     finishedAt?: non-empty-string|null,
     *     duration?: non-empty-string|null,
     *     canceledBy?: int,
     *     batchUid?: int,
     *     details?: array<mixed>|null,
     *     error?: array<mixed>|null
     * } $data
     * @param \Closure(int, int, int): Task|null $await
     */
    public static function fromArray(array $data, ?\Closure $await = null) : Task
    {
        $details = $data['details'] ?? null;
        $type = TaskType::tryFrom($data['type']) ?? TaskType::Unknown;
        return new self($data['taskUid'] ?? $data['uid'], $data['indexUid'] ?? null, TaskStatus::tryFrom($data['status']) ?? TaskStatus::Unknown, $type, new \DateTimeImmutable($data['enqueuedAt']), \array_key_exists('startedAt', $data) && null !== $data['startedAt'] ? new \DateTimeImmutable($data['startedAt']) : null, \array_key_exists('finishedAt', $data) && null !== $data['finishedAt'] ? new \DateTimeImmutable($data['finishedAt']) : null, $data['duration'] ?? null, $data['canceledBy'] ?? null, $data['batchUid'] ?? null, match ($type) {
            TaskType::IndexCreation => null !== $details ? IndexCreationDetails::fromArray($details) : null,
            TaskType::IndexUpdate => null !== $details ? IndexUpdateDetails::fromArray($details) : null,
            TaskType::IndexDeletion => null !== $details ? IndexDeletionDetails::fromArray($details) : null,
            TaskType::IndexSwap => null !== $details ? IndexSwapDetails::fromArray($details) : null,
            TaskType::DocumentAdditionOrUpdate => null !== $details ? DocumentAdditionOrUpdateDetails::fromArray($details) : null,
            TaskType::DocumentDeletion => null !== $details ? DocumentDeletionDetails::fromArray($details) : null,
            TaskType::DocumentEdition => null !== $details ? DocumentEditionDetails::fromArray($details) : null,
            TaskType::SettingsUpdate => null !== $details ? SettingsUpdateDetails::fromArray($details) : null,
            TaskType::DumpCreation => null !== $details ? DumpCreationDetails::fromArray($details) : null,
            TaskType::TaskCancelation => null !== $details ? TaskCancelationDetails::fromArray($details) : null,
            TaskType::TaskDeletion => null !== $details ? TaskDeletionDetails::fromArray($details) : null,
            // It’s intentional that SnapshotCreation tasks don’t have a details object
            // (no SnapshotCreationDetails exists and tests don’t exercise any details)
            TaskType::SnapshotCreation => null,
            TaskType::NetworkTopologyChange => null,
            TaskType::Unknown => UnknownTaskDetails::fromArray($details ?? []),
        }, \array_key_exists('error', $data) && null !== $data['error'] ? TaskError::fromArray($data['error']) : null, $data, $await);
    }
}
