<?php

namespace App\Livewire;

use App\Models\Episode;
use App\Models\Playlist;
use App\Models\PlaylistEpisode;
use App\Services\PlaylistService;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Support\Facades\Auth;
use Livewire\Attributes\Url;
use Livewire\Component;
use Livewire\WithPagination;

class PlaylistOverview extends Component
{
    use WithPagination;

    protected PlaylistService $playlistService;

    #[Url(history: true)]
    public string $search = '';

    #[Url(history: true)]
    public int $perPage = 25;

    public Playlist $playlist;

    public bool $editingName = false;

    public string $editingPlaylistName = '';

    public function boot(PlaylistService $playlistService)
    {
        $this->playlistService = $playlistService;
    }

    public function mount($playlist_id)
    {
        $this->playlist = Playlist::withCount('episodes')->with('user')->findOrFail($playlist_id);

        $this->sanitizePerPage();

        $this->repairNullPositions();
    }

    public function updatingSearch(): void
    {
        $this->resetPage();
    }

    public function updatingPerPage(): void
    {
        $this->resetPage();
    }

    public function getEpisodesProperty(): LengthAwarePaginator
    {
        $this->sanitizePerPage();

        return PlaylistEpisode::query()
            ->where('playlist_id', $this->playlist->id)
            ->when($this->search !== '', fn ($query) => $query->whereHas('episode', fn ($episode) => $episode
                ->where('title', 'like', '%'.$this->search.'%')
                ->orWhere('title_jpn', 'like', '%'.$this->search.'%')))
            ->orderBy('position')
            ->with(['episode.gallery' => fn ($gallery) => $gallery->orderBy('id')->limit(1)])
            ->paginate($this->perPage);
    }

    public function getFirstEpisodeProperty(): ?Episode
    {
        return PlaylistEpisode::where('playlist_id', $this->playlist->id)
            ->orderBy('position')
            ->first()?->episode;
    }

    public function moveUp($episodeId)
    {
        if (! $this->isOwner()) {
            return;
        }

        $episode = PlaylistEpisode::find($episodeId);

        if (! $episode) {
            return;
        }

        $above = PlaylistEpisode::where('playlist_id', $episode->playlist_id)
            ->where('position', '<', $episode->position)
            ->orderBy('position', 'desc')
            ->first();

        if ($above) {
            $this->playlistService->swapPositions($episode, $above);
        }
    }

    public function moveDown($episodeId)
    {
        if (! $this->isOwner()) {
            return;
        }

        $episode = PlaylistEpisode::find($episodeId);

        if (! $episode) {
            return;
        }

        $below = PlaylistEpisode::where('playlist_id', $episode->playlist_id)
            ->where('position', '>', $episode->position)
            ->orderBy('position')
            ->first();

        if ($below) {
            $this->playlistService->swapPositions($episode, $below);
        }
    }

    public function remove($episodeId)
    {
        if (! $this->isOwner()) {
            return;
        }

        PlaylistEpisode::find($episodeId)?->delete();
        $this->playlistService->reorderPositions($this->playlist);
        $this->playlist->loadCount('episodes');

        $lastPage = max(1, (int) ceil(PlaylistEpisode::where('playlist_id', $this->playlist->id)->count() / $this->perPage));

        if ($this->getPage() > $lastPage) {
            $this->setPage($lastPage);
        }
    }

    public function editName()
    {
        if (! $this->isOwner()) {
            return;
        }

        $this->editingPlaylistName = $this->playlist->name;
        $this->editingName = true;
    }

    public function cancelEditName()
    {
        $this->editingName = false;
        $this->editingPlaylistName = '';
    }

    public function updateName()
    {
        if (! $this->isOwner()) {
            return;
        }

        $this->validate([
            'editingPlaylistName' => 'required|max:30',
        ]);

        $this->playlist->update([
            'name' => $this->editingPlaylistName,
        ]);

        $this->editingName = false;
        $this->editingPlaylistName = '';
    }

    public function toggleVisibility()
    {
        if (! $this->isOwner()) {
            return;
        }

        $this->playlist->update([
            'is_private' => ! $this->playlist->is_private,
        ]);

        $this->playlist->loadCount('episodes');
    }

    public function render()
    {
        return view('livewire.playlist-overview', [
            'episodes' => $this->episodes,
            'firstEpisode' => $this->firstEpisode,
            'isOwner' => $this->isOwner(),
        ]);
    }

    private function isOwner(): bool
    {
        return Auth::check() && Auth::user()->id === $this->playlist->user_id;
    }

    private function sanitizePerPage(): void
    {
        if (! in_array($this->perPage, [25, 50, 100], true)) {
            $this->perPage = 25;
        }
    }

    private function repairNullPositions(): void
    {
        if (! PlaylistEpisode::where('playlist_id', $this->playlist->id)->whereNull('position')->exists()) {
            return;
        }

        PlaylistEpisode::where('playlist_id', $this->playlist->id)
            ->orderBy('position')->orderBy('id')
            ->get()
            ->each(fn ($playlistEpisode, $index) => $playlistEpisode->update(['position' => $index + 1]));
    }
}
