<?php

/** @noinspection PhpUnhandledExceptionInspection */

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

use DefStudio\GameEngine\Enums\StorytellingType;
use DefStudio\GameEngine\Decorators\ModelDecorator;
use DefStudio\GameEngine\Exceptions\RunnerException;
use DefStudio\GameEngine\Decorators\Runs\PlayableMap;
use DefStudio\GameEngine\Models\Contracts\WithStorytelling;

/**
 * @property-read PlayableMap $map
 */
trait RunsMaps
{
    public function getMapProperty(): PlayableMap
    {
        throw_if(!$this->is_map_active(), RunnerException::no_active_map());

        $map = $this->run->story->maps->sortBy('order')->values()->get($this->current_map_index());

        return PlayableMap::build($map)->setup($this->run);
    }

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

    protected function is_map_active(): bool
    {
        return $this->current_map_index() >= 0;
    }

    protected function start_runs_maps(): void
    {
        if (!$this->is_map_active()) {
            return;
        }

        if ($this->show_storytelling($this->map, StorytellingType::activation, StorytellingType::prologue)) {
            return;
        }

        if ($this->is_mission_active()) {
            return;
        }

        $this->next_mission();
    }

    protected function next_map(): void
    {
        if ($this->is_map_active()) {
            throw_unless($this->map->completed(), RunnerException::incomplete_map($this->map));

            if ($this->current_map_index() >= $this->run->story->maps->count() - 1) {
                $this->complete_story();

                return;
            }
        }

        $this->activate_map($this->run->get_state('map.index', -1) + 1);

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

        $this->reset_mission_state();

        $this->save();

        $this->reload_page();
    }

    protected function activate_map(int $index): void
    {
        $this->run->set_state('map.index', $index);
        $this->forgetComputed('map');
        $this->emit('map:activated');
    }

    protected function complete_storytelling_runs_maps(string|ModelDecorator|WithStorytelling $scope, StorytellingType|string $type): void
    {
        $type = StorytellingType::build_from($type);
        $scope = $this->get_storytelling_scope($scope);

        if ($scope !== 'map') {
            return;
        }

        if ($type === StorytellingType::activation && !$this->show_storytelling($scope, StorytellingType::prologue)) {
            $this->next_mission();

            return;
        }

        if ($type === StorytellingType::prologue) {
            $this->next_mission();

            return;
        }

        if ($type === StorytellingType::epilogue) {
            $this->next_map();
        }
    }

    protected function complete_map(): void
    {
        if (!$this->show_storytelling($this->map, StorytellingType::epilogue)) {
            $this->next_map();
        }
    }
}
