<?php

namespace App\Services;

use App\Models\Episode;
use App\Models\Hentai;
use App\Models\Studios;
use App\Models\ModLog;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Intervention\Image\Encoders\WebpEncoder;
use Intervention\Image\Laravel\Facades\Image;

class EpisodeService
{
    public function generateSlug(string $title): string
    {
        $slug = Str::slug($title);
        $slugParts = explode('-', $slug);
        $lastPart = $slugParts[array_key_last($slugParts)];

        if (is_numeric($lastPart) && $lastPart < 1000) {
            $slugParts[array_key_last($slugParts)] = 's'.$lastPart;

            return implode('-', $slugParts);
        }

        return $slug;
    }

    public function createEpisode(
        Request $request,
        Hentai $hentai,
        int $episodeNumber,
        ?Studios $studio = null,
        ?Episode $referenceEpisode = null
    ): Episode {
        $episode = new Episode;
        $episode->title = $referenceEpisode->title ?? $request->input('title');
        $episode->title_search = preg_replace('/[^A-Za-z0-9 ]/', '', $episode->title);
        $episode->title_jpn = $referenceEpisode->title_jpn ?? $request->input('title_jpn');
        $episode->slug = "{$hentai->slug}-{$episodeNumber}";
        $episode->hentai_id = $hentai->id;
        $episode->studios_id = $referenceEpisode->studio->id ?? $studio->id;
        $episode->episode = $episodeNumber;
        $episode->description = $referenceEpisode ? $request->input('description') : $request->input("description{$episodeNumber}");
        $episode->url = $referenceEpisode ? $request->input('baseurl') : rtrim($request->input('baseurl'), '/').'/E'.str_pad($episodeNumber, 2, '0', STR_PAD_LEFT);
        $episode->view_count = 0;
        $episode->interpolated = true;
        $episode->is_dvd_aspect = false;
        $episode->release_date = $referenceEpisode->release_date ?? Carbon::parse($request->input('releasedate'))->format('Y-m-d');
        $episode->cover_url = "/images/hentai/{$hentai->slug}/cover-ep-{$episodeNumber}.webp";
        $episode->save();

        // Tagging
        $tags = $referenceEpisode ? $referenceEpisode->tags : json_decode($request->input('tags'));
        foreach ($tags as $t) {
            $episode->tag($referenceEpisode ? $t->name : $t->value);
        }

        return $episode;
    }

    private function applyTags(Request $request, Episode $episode): void
    {
        $tags = json_decode($request->input('tags'));
        $newtags = [];
        foreach ($tags as $t) {
            $newtags[] = $t->value;
        }

        $newTagsTemp = $newtags;
        $oldTagsTemp = $episode->tagNames();

        sort($newTagsTemp);
        sort($oldTagsTemp);

        if ($newTagsTemp !== $oldTagsTemp) {
            ModLog::create([
                'moderator' => $request->user()->name,
                'data' => sprintf(
                    'Updated Episode tags from %s to %s',
                    implode(', ', $oldTagsTemp),
                    implode(', ', $newTagsTemp),
                ),
            ]);
        }

        $episode->retag($newtags);
    }

    private function updateTitle(Request $request, Episode $episode): void
    {
        $updates = [];

        if ($episode->title !== $request->input('title')) {
            $updates['title'] = $request->input('title');
            $updates['title_search'] = preg_replace(
                '/[^A-Za-z0-9 ]/',
                '',
                $request->input('title')
            );

            // Log to ModLog
            ModLog::create([
                'moderator' => $request->user()->name,
                'data' => "Updating Hentai Title from {$episode->title} to {$request->input('title')}",
            ]);
        }

        if ($episode->title_jpn !== $request->input('title_jpn')) {
            $updates['title_jpn'] = $request->input('title_jpn');

            // Log to ModLog
            ModLog::create([
                'moderator' => $request->user()->name,
                'data' => "Updating Hentai Title from {$episode->title_jpn} to {$request->input('title_jpn')}",
            ]);
        }

        if (! empty($updates)) {
            $episode->hentai->episodes()->update($updates);
        }
    }

    public function updateEpisode(Request $request, Studios $studio, int $episodeId): Episode
    {
        $episode = Episode::where('id', $episodeId)->firstOrFail();
        $episode->studios_id = $studio->id;
        $episode->description = $request->input('description');
        $episode->url = $request->input('baseurl');
        $episode->release_date = Carbon::parse($request->input('releasedate'))->format('Y-m-d');
        $episode->interpolated = $request->input('interpolated') == 'yes';
        $episode->interpolated_uhd = $request->input('downloadUHDi1') ? true : false;
        $episode->is_dvd_aspect = $request->input('dvd') == 'yes';
        $episode->dmca_takedown = $request->input('dmca_takedown') == 'true';
        $episode->save();

        $this->applyTags($request, $episode);
        $this->updateTitle($request, $episode);

        return $episode;
    }

    public function updateEpisodeModerator(Request $request, int $episodeId): void
    {
        $episode = Episode::where('id', $episodeId)->firstOrFail();
        $oldDescription = $episode->description;
        $episode->description = $request->input('description');
        $episode->save();

        if ($episode->description !== $oldDescription) {
            // Log to ModLog
            ModLog::create([
                'moderator' => $request->user()->name,
                'data' => "Updated Episode description from {$oldDescription} to {$episode->description}",
            ]);
        }

        $this->applyTags($request, $episode);
        $this->updateTitle($request, $episode);
    }

    public function getOrCreateStudio(string $studioName): Studios
    {
        return Studios::firstOrCreate(
            ['name' => $studioName],
            ['slug' => Str::slug($studioName)]
        );
    }

    public function createOrUpdateCover(Request $request, Episode $episode, string $slug, int $episodeNumber): void
    {
        if (! $request->hasFile("episodecover{$episodeNumber}")) {
            return;
        }

        // Create Folder for Image Upload
        if (! Storage::disk('public')->exists("/images/hentai/{$slug}")) {
            Storage::disk('public')->makeDirectory("/images/hentai/{$slug}");
        }

        // Encode and save cover image
        Image::read($request->file("episodecover{$episodeNumber}")->getRealPath())
            ->cover(268, 394)
            ->encode(new WebpEncoder)
            ->save(Storage::disk('public')->path($episode->cover_url));
    }
}
