<?php

/** @noinspection PhpUnhandledExceptionInspection */

namespace DefStudio\GameEngine\Http\Livewire\Runs\Concerns;

use DefStudio\GameEngine\Enums\StorytellingType;
use DefStudio\GameEngine\Exceptions\RunnerException;
use DefStudio\GameEngine\Decorators\Runs\PlayableTask;

/**
 * @property-read PlayableTask $task
 */
trait RunsTasks
{
    protected function is_task_active(): bool
    {
        return $this->current_task_index() >= 0;
    }

    protected function current_task_index(): int
    {
        return $this->run->get_state('task.index', -1);
    }

    public function getTaskProperty(): PlayableTask
    {
        $task = $this->mission->extracted_tasks
            ->values()
            ->get($this->current_task_index());

        throw_if($task === null, RunnerException::no_active_task());

        return PlayableTask::build($task)->setup($this->run);
    }

    protected function next_task(): void
    {
        if ($this->is_task_active()) {
            throw_unless($this->task->completed(), RunnerException::incomplete_task($this->task));

            if ($this->current_task_index() >= $this->mission->extracted_tasks->count() - 1) {
                $this->complete_mission();

                return;
            }
        }

        $this->activate_task($this->current_task_index() + 1);

        $this->run->save();
    }

    protected function activate_task(int $index): void
    {
        $this->reset_task_state();

        $this->run->set_state('task.index', $index);

        $this->forgetComputed('task');

        $this->setup_storytellings($this->task, true);

        $this->show_storytelling($this->task, StorytellingType::activation);

        $this->run->save();
    }

    protected function reset_task_state(): void
    {
        $this->run->set_state('task', ['index' => -1]);
        $this->reset_storytellings('task');
        $this->forgetComputed('task');
    }

    public function get_task_state(string $key, mixed $default = null): mixed
    {
        return $this->run->get_state("tasks.{$this->task->id}.$key", $default);
    }

    public function set_task_state(string $key, mixed $value, bool $save = true): void
    {
        $this->run->set_state("tasks.{$this->task->id}.$key", $value);

        if ($save) {
            $this->run->save();
        }
    }

    public function complete_task_with_result(array $result): void
    {
        $this->set_task_state('result', $result);
        $this->next_task();
    }
}
