<?php

/** @noinspection PhpUnused */

namespace DefStudio\GameEngine\Decorators\Tasks;

use Illuminate\Support\Str;
use DefStudio\GameEngine\Enums\MediaCollection;
use DefStudio\GameEngine\Http\Livewire\Tasks\Edit;
use Spatie\MediaLibrary\MediaCollections\Models\Media;
use DefStudio\GameEngine\Actions\Tasks\StoreAssetImage;
use DefStudio\GameEngine\Attributes\CallableFromLivewire;

class DragAndDrop extends TaskDecorator
{
    protected array $media_collections = [
        MediaCollection::base_image,
        MediaCollection::tile_placeholders,
    ];

    public static function type_label(): string
    {
        return __('Drag And Drop');
    }

    public static function configuration_component(): string
    {
        return 'game-engine::tasks.drag-and-drop.configuration';
    }

    public static function run_component(): string
    {
        return 'game-engine::tasks.drag-and-drop.run';
    }

    public function saving_from_livewire_editor(Edit $edit): void
    {
        if (!empty($edit->image_assets[MediaCollection::base_image->name])) {
            StoreAssetImage::run($this, $edit->image_assets[MediaCollection::base_image->name], MediaCollection::base_image);
            $edit->image_assets[MediaCollection::base_image->name] = null;
        }

        foreach (array_keys($this->tiles()) as $tile_index) {

            if (empty($edit->image_assets['tile_'.$tile_index])) {
                continue;
            }

            $media = StoreAssetImage::run($this, $edit->image_assets['tile_'.$tile_index], MediaCollection::tile_placeholders);

            $this->configuration['tiles'][$tile_index]['media_id'] = $media->id;

            $edit->image_assets['tile_'.$tile_index] = null;
        }

        $this->getMedia(MediaCollection::tile_placeholders)
            ->reject(fn(Media $media) => collect($this->tiles())->pluck('media_id')->contains($media->id))
            ->each(fn(Media $media) => $media->delete());

        $this->unsetRelation('media');
    }

    public function tiles(): array
    {
        return $this->configuration['tiles'] ?? [];
    }

    public function should_randomize_tiles_order(): bool
    {
        return $this->configuration['randomize_tiles_order'] ?? false;
    }

    public function is_repositioning_allowed(): bool
    {
        return $this->configuration['repositioning_allowed'] ?? false;
    }

    public function is_partial_submit_allowed(): bool
    {
        return $this->configuration['partial_submit_allowed'] ?? false;
    }

    public function has_loose_snaps(): bool
    {
        return $this->configuration['loose_snaps'] ?? false;
    }

    public function snaps(): array
    {
        return collect($this->tiles())->map(fn($tile_data): array => [...$tile_data['anchor'], 'distance' => $tile_data['snap'] ?? 10])->toArray();
    }

    /**
     * @return array{repositioning_allowed: bool, partial_submit_allowed: bool, loose_snaps: bool}
     */
    public function run_options(): array
    {
        return [
            'repositioning_allowed' => $this->is_repositioning_allowed(),
            'partial_submit_allowed' => $this->is_partial_submit_allowed(),
            'loose_snaps' => $this->has_loose_snaps(),
        ];
    }

    public function question(): string
    {
        return $this->configuration['question'] ?? '';
    }

    #[CallableFromLivewire()]
    public function remove_base_image(): self
    {
        $this->getFirstMedia(MediaCollection::base_image)?->delete();
        $this->unsetRelation('media');

        return $this;
    }

    #[CallableFromLivewire()]
    public function add_tile(): self
    {
        $this->configuration['tiles'][] = [
            'id' => Str::uuid(),
            'media_id' => null,
            'anchor' => ['x' => 0, 'y' => 0],
            'snap' => 10,
        ];

        return $this;
    }

    #[CallableFromLivewire()]
    public function delete_tile(int $index): self
    {
        unset($this->configuration['tiles'][$index]);

        return $this;
    }

    #[CallableFromLivewire()]
    public function remove_tile_placeholder(int $tile_index): self
    {
        $media_id = $this->tiles()[$tile_index]['media_id'];

        if (empty($media_id)) {
            return $this;
        }

        $media = $this->media->find($media_id);

        $media?->delete();

        $this->configuration['tiles'][$tile_index]['media_id'] = null;

        $this->save();

        $this->unsetRelation('media');

        return $this;
    }

    #[CallableFromLivewire()]
    public function move_tile_placeholder(int $index, int $offset_x, int $offset_y): self
    {
        $this->configuration['tiles'][$index]['anchor']['x'] += $offset_x;
        $this->configuration['tiles'][$index]['anchor']['y'] += $offset_y;

        return $this;
    }

    public function is_complete(array $state): bool
    {
        return !empty($state['placements']);
    }
}
