<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Models\Anime;
use App\Models\Genre;
use App\Models\Episode;
use App\Models\Banner;
use App\Models\ContinueWatching;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;

class AnimeApiController extends Controller
{
    // GET /api/home
    public function home(Request $request)
    {
        $featured = Anime::where('is_featured', true)->where('is_published', true)
            ->with('genres', 'seasons', 'episodes')
            ->latest()->take(5)->get();

        if ($featured->isEmpty()) {
            $featured = Anime::where('is_published', true)->with('genres', 'seasons', 'episodes')
                ->where('rating', '>=', 1)->orderByDesc('rating')->take(5)->get();
        }

        $latest   = Anime::where('is_published', true)->latest()->take(20)->get();
        $topRated = Anime::where('is_published', true)->where('rating', '>=', 7)
            ->orderByDesc('rating')->take(12)->get();

        try {
            $manualTrending = Anime::where('is_trending', true)->where('is_published', true)
                ->orderBy('trending_order')->take(12)->get();

            if ($manualTrending->count() >= 6) {
                $trending = $manualTrending->take(12);
            } else {
                $autoIds  = $manualTrending->pluck('id')->toArray();
                $autoFill = Anime::where('is_published', true)
                    ->whereNotIn('id', $autoIds)
                    ->withSum(['episodes as recent_views' => fn($q) =>
                        $q->where('is_published', true)->where('updated_at', '>=', now()->subDays(30))
                    ], 'view_count')
                    ->orderByDesc('recent_views')
                    ->take(12 - $manualTrending->count())->get();
                $trending = $manualTrending->concat($autoFill);
            }
        } catch (\Throwable) {
            $trending = collect();
        }

        if ($trending->isEmpty()) $trending = $latest->take(12);

        $newEpisodes = Episode::with(['anime', 'season'])
            ->where('is_published', true)->latest()->take(12)->get()
            ->filter(fn($e) => $e->anime && $e->season)->values();

        $genres = Genre::where('is_active', true)->take(16)->get();

        $continueWatching = collect();
        $recommended      = collect();

        $authUser = auth('sanctum')->user();
        if ($authUser) {
            try {
                $continueWatching = ContinueWatching::where('user_id', $authUser->id)
                    ->with('anime:id,title,slug,cover_image')
                    ->where('percent_complete', '>=', 5)
                    ->where('percent_complete', '<', 95)
                    ->orderByDesc('updated_at')->limit(10)->get();

                $watchedIds = ContinueWatching::where('user_id', $authUser->id)->pluck('anime_id');
                if ($watchedIds->isNotEmpty()) {
                    $topGenreIds = DB::table('anime_genre')
                        ->whereIn('anime_id', $watchedIds)
                        ->select('genre_id', DB::raw('count(*) as cnt'))
                        ->groupBy('genre_id')->orderByDesc('cnt')->limit(3)->pluck('genre_id');

                    if ($topGenreIds->isNotEmpty()) {
                        $recommended = Anime::where('is_published', true)
                            ->whereNotIn('id', $watchedIds)
                            ->whereHas('genres', fn($q) => $q->whereIn('genres.id', $topGenreIds))
                            ->where('rating', '>=', 6)->inRandomOrder()->take(12)->get();
                    }
                }
            } catch (\Throwable $e) {}
        }

        return response()->json([
            'featured'         => $featured->map(fn($a) => $this->animeResource($a, true)),
            'trending'         => $trending->values()->map(fn($a) => $this->animeResource($a)),
            'latest'           => $latest->map(fn($a) => $this->animeResource($a)),
            'top_rated'        => $topRated->map(fn($a) => $this->animeResource($a)),
            'new_episodes'     => $newEpisodes->map(fn($e) => $this->episodeCardResource($e)),
            'genres'           => $genres->map(fn($g) => ['id'=>$g->id,'name'=>$g->name,'slug'=>$g->slug]),
            'continue_watching'=> $continueWatching->map(fn($cw) => $this->continueWatchingResource($cw)),
            'recommended'      => $recommended->map(fn($a) => $this->animeResource($a)),
        ]);
    }

    // GET /api/animes
    public function index(Request $request)
    {
        $q      = $request->input('q', '');
        $genre  = $request->input('genre');
        $type   = $request->input('type');
        $status = $request->input('status');
        $year   = $request->input('year');
        $sort   = $request->input('sort', 'latest'); // latest|rating|views

        $query = Anime::where('is_published', true)->with('genres');

        if ($q) {
            $query->where(function ($qb) use ($q) {
                $qb->where('title', 'like', "%$q%")
                   ->orWhere('title_en', 'like', "%$q%")
                   ->orWhere('title_jp', 'like', "%$q%");
            });
        }
        if ($genre) $query->whereHas('genres', fn($qb) => $qb->where('slug', $genre));
        if ($type)   $query->where('type', $type);
        if ($status) $query->where('status', $status);
        if ($year)   $query->where('release_year', $year);

        match ($sort) {
            'rating' => $query->orderByDesc('rating'),
            default  => $query->latest(),
        };

        $results = $query->paginate(24)->withQueryString();

        return response()->json([
            'data'        => collect($results->items())->map(fn($a) => $this->animeResource($a)),
            'total'       => $results->total(),
            'per_page'    => $results->perPage(),
            'current_page'=> $results->currentPage(),
            'last_page'   => $results->lastPage(),
        ]);
    }

    // GET /api/animes/{slug}
    public function show(Request $request, string $slug)
    {
        $anime = Anime::where('slug', $slug)->where('is_published', true)
            ->with(['genres', 'seasons', 'seasons.episodes' => fn($q) => $q->where('is_published', true)->orderBy('episode_number')])
            ->firstOrFail();

        $userId = $request->user()?->id;

        $inWatchlist = false;
        $userRating  = null;
        $isFollowing = false;

        if ($userId) {
            $wl          = \App\Models\Watchlist::where('user_id', $userId)->where('anime_id', $anime->id)->first();
            $inWatchlist = $wl !== null;
            $watchlistStatus = $wl?->status;
            $userRating  = \App\Models\AnimeRating::where('user_id', $userId)->where('anime_id', $anime->id)->value('rating');
            $isFollowing = \App\Models\AnimeFollow::where('user_id', $userId)->where('anime_id', $anime->id)->exists();
        }

        $seasons = $anime->seasons->map(function ($season) {
            return [
                'id'             => $season->id,
                'season_number'  => $season->season_number,
                'title'          => $season->title,
                'episodes'       => $season->episodes->map(fn($ep) => $this->episodeResource($ep)),
            ];
        });

        return response()->json([
            'anime'       => $this->animeResource($anime, true),
            'seasons'     => $seasons,
            'in_watchlist'    => $inWatchlist,
            'watchlist_status'=> $watchlistStatus ?? null,
            'user_rating'     => $userRating,
            'is_following'    => $isFollowing,
        ]);
    }

    // GET /api/genres/{slug}
    public function genre(Request $request, string $slug)
    {
        $genre  = Genre::where('slug', $slug)->where('is_active', true)->firstOrFail();
        $animes = $genre->animes()->where('is_published', true)->latest()->paginate(24);

        return response()->json([
            'genre' => ['id'=>$genre->id,'name'=>$genre->name,'slug'=>$genre->slug],
            'data'  => collect($animes->items())->map(fn($a) => $this->animeResource($a)),
            'total' => $animes->total(),
            'last_page' => $animes->lastPage(),
            'current_page' => $animes->currentPage(),
        ]);
    }

    // GET /api/genres
    public function genres()
    {
        $genres = Genre::where('is_active', true)->orderBy('name')->get();
        return response()->json($genres->map(fn($g) => ['id'=>$g->id,'name'=>$g->name,'slug'=>$g->slug]));
    }

    // GET /api/watch/{slug}/{season}/{episode}
    public function watch(Request $request, string $slug, int $season, int $episode)
    {
        $anime = Anime::where('slug', $slug)->where('is_published', true)->firstOrFail();
        $seasonModel = $anime->seasons()->where('season_number', $season)->firstOrFail();
        $ep = $seasonModel->episodes()->where('episode_number', $episode)->where('is_published', true)->firstOrFail();

        $ep->increment('view_count');

        $prev = $seasonModel->episodes()->where('episode_number', '<', $episode)->where('is_published', true)->orderByDesc('episode_number')->first();
        $next = $seasonModel->episodes()->where('episode_number', '>', $episode)->where('is_published', true)->orderBy('episode_number')->first();

        // Cross-season next
        if (!$next) {
            $nextSeason = $anime->seasons()->where('season_number', $season + 1)->first();
            if ($nextSeason) {
                $next = $nextSeason->episodes()->where('episode_number', 1)->where('is_published', true)->first();
            }
        }

        // Subtitles
        $subtitles = [];
        if (method_exists($ep, 'subtitles')) {
            $subtitles = $ep->subtitles()->get()->map(fn($s) => [
                'label' => $s->label,
                'lang'  => $s->language,
                'url'   => $s->url,
                'is_default' => (bool)($s->is_default ?? false),
            ])->values()->toArray();
        }

        // Dub sources from m3u8 URL
        $dubSources = [];
        if ($ep->m3u8_url) {
            $rawDubs       = $ep->available_dubs ?? null;
            $availableDubs = is_string($rawDubs) ? json_decode($rawDubs, true) : (is_array($rawDubs) ? $rawDubs : null);
            [$dubSources] = \App\Http\Controllers\Frontend\PlayerController::resolveDubSourcesPublic(
                $ep->m3u8_url, $availableDubs
            );
        }

        // Quality sources (legacy — episode.video_url / m3u8_url)
        $sources = collect();
        if ($ep->m3u8_url)      $sources->push(['quality'=>'Auto (HLS)','url'=>$ep->m3u8_url,'type'=>'hls']);
        if ($ep->video_url) {
            $isHls = str_ends_with($ep->video_url, '.m3u8') || str_contains($ep->video_url, 'master.m3u8');
            $type  = $isHls ? 'hls' : 'mp4';
            $sources->push(['quality'=>'Auto','url'=>$ep->video_url,'type'=>$type]);
        }
        if ($ep->video_url_1080 ?? null) $sources->push(['quality'=>'1080p','url'=>$ep->video_url_1080,'type'=>'mp4']);
        if ($ep->video_url_720  ?? null) $sources->push(['quality'=>'720p','url'=>$ep->video_url_720,'type'=>'mp4']);
        if ($ep->video_url_480  ?? null) $sources->push(['quality'=>'480p','url'=>$ep->video_url_480,'type'=>'mp4']);

        // Çok kaynak desteği (video_sources tablosu)
        // Her translator/kaynak bir grup → [{key, label, url, type, quality}]
        $multiSources = \App\Models\VideoSource::where('episode_id', $ep->id)
            ->orderBy('sort_order')
            ->get()
            ->groupBy(fn($vs) => $vs->translator_id ?: $vs->label)
            ->map(function ($group) {
                $default = $group->firstWhere('is_default', true) ?? $group->first();
                // Tüm kaliteler (1080p, 720p, vb.)
                $qualities = $group->map(fn($vs) => [
                    'quality' => $vs->quality ?: 'Auto',
                    'url'     => $vs->url,
                    'type'    => $vs->type ?? 'mp4',
                ])->values()->toArray();

                return [
                    'key'       => $default->translator_id
                                    ?: \Illuminate\Support\Str::slug($default->label ?? 'kaynak'),
                    'label'     => $default->label ?: 'Kaynak',
                    'url'       => $default->url,
                    'type'      => $default->type ?? 'mp4',
                    'quality'   => $default->quality ?: 'Auto',
                    'source'    => $default->source ?? 'animecix',
                    'qualities' => $qualities,
                    'is_default'=> (bool) $default->is_default,
                ];
            })
            ->values()
            ->toArray();

        // Player settings
        $skipSeconds      = (int) \App\Models\Setting::get('main_video_skip_seconds', 10);
        $wmCoverSeconds   = (int) \App\Models\Setting::get('watermark_cover_seconds', 11);
        $introEnabled     = \App\Models\Setting::get('intro_enabled') == '1';
        $introUrl         = $introEnabled ? (\App\Models\Setting::get('intro_video_url') ?: null) : null;
        $introSkipAfter   = (int) \App\Models\Setting::get('intro_skip_after', 5);

        // AniSkip is fetched via separate /api/aniskip endpoint to avoid blocking video load
        $aniSkipData = null;

        // All episodes list for in-player episode switcher
        $allEpisodes = $seasonModel->episodes()->where('is_published', true)->orderBy('episode_number')
            ->get()->map(fn($e) => [
                'id'             => $e->id,
                'episode_number' => $e->episode_number,
                'season_number'  => $season,
                'title'          => $e->title,
                'thumbnail_url'  => $e->thumbnail_url ?? null,
            ]);

        return response()->json([
            'anime'        => ['id'=>$anime->id,'title'=>$anime->title,'slug'=>$anime->slug,'cover_url'=>$anime->coverUrl],
            'season'       => ['id'=>$seasonModel->id,'season_number'=>$seasonModel->season_number,'title'=>$seasonModel->title],
            'episode'      => $this->episodeResource($ep),
            'sources'      => $sources->values(),
            'multi_sources'=> $multiSources,   // Çok kaynak (Anizium "4K" + AnimeCix çevirmenler)
            'dub_sources'  => $dubSources,
            'subtitles'    => $subtitles,
            'episodes'   => $allEpisodes,
            'prev_episode' => $prev ? ['season'=>$prev->season?->season_number ?? $season,'episode'=>$prev->episode_number] : null,
            'next_episode' => $next ? ['season'=>$next->season?->season_number ?? $season,'episode'=>$next->episode_number] : null,
            'settings'   => [
                'skip_seconds'       => $skipSeconds,
                'wm_cover_seconds'   => $wmCoverSeconds,
                'intro_url'          => $introUrl,
                'intro_skip_after'   => $introSkipAfter,
                // AniSkip timestamps (null if not available)
                'aniskip'            => $aniSkipData, // {'op':{'start':X,'end':Y}, 'ed':{'start':X,'end':Y}}
            ],
        ]);
    }

    // ── Resources ─────────────────────────────────────────────────────────────

    private function animeResource(Anime $a, bool $full = false): array
    {
        $base = [
            'id'            => $a->id,
            'title'         => $a->title,
            'title_en'      => $a->title_en,
            'title_jp'      => $a->title_jp,
            'slug'          => $a->slug,
            'cover_url'     => $a->coverUrl,
            'banner_url'    => $a->bannerUrl,
            'type'          => $a->type,
            'status'        => $a->status,
            'rating'        => $a->rating ? (float)$a->rating : null,
            'release_year'  => $a->release_year,
            'episode_count' => $a->episode_count,
            'genres'        => $a->relationLoaded('genres')
                ? $a->genres->map(fn($g) => ['id'=>$g->id,'name'=>$g->name,'slug'=>$g->slug])->values()
                : [],
        ];

        if ($full) {
            $base['description'] = $a->description;
            $base['studio']      = $a->studio ?? null;
            $base['duration']    = $a->duration ?? null;
            $base['is_featured'] = $a->is_featured;

            // First episode for "watch now" button
            if ($a->relationLoaded('seasons') && $a->seasons->isNotEmpty()) {
                $firstSeason = $a->seasons->first();
                $eps = $a->relationLoaded('episodes') ? $a->episodes : $firstSeason->episodes;
                $firstEp = $eps->where('season_id', $firstSeason->id)->where('is_published', true)->sortBy('episode_number')->first();
                $base['first_watch'] = ($firstSeason && $firstEp) ? [
                    'season'  => $firstSeason->season_number,
                    'episode' => $firstEp->episode_number,
                ] : null;
            }
        }

        return $base;
    }

    private function episodeResource(Episode $ep): array
    {
        return [
            'id'             => $ep->id,
            'episode_number' => $ep->episode_number,
            'title'          => $ep->title,
            'thumbnail_url'  => $ep->thumbnailUrl ?? null,
            'duration'       => $ep->duration,
            'view_count'     => $ep->view_count,
            'created_at'     => $ep->created_at?->toISOString(),
        ];
    }

    private function episodeCardResource(Episode $ep): array
    {
        return [
            'id'             => $ep->id,
            'episode_number' => $ep->episode_number,
            'season_number'  => $ep->season?->season_number,
            'title'          => $ep->title,
            'thumbnail_url'  => $ep->thumbnailUrl ?? null,
            'created_at'     => $ep->created_at?->diffForHumans(),
            'anime' => [
                'id'        => $ep->anime->id,
                'title'     => $ep->anime->title,
                'slug'      => $ep->anime->slug,
                'cover_url' => $ep->anime->coverUrl,
                'rating'    => $ep->anime->rating ? (float)$ep->anime->rating : null,
                'description' => $ep->anime->description,
            ],
        ];
    }

    // ── AniSkip endpoint ─────────────────────────────────────────────────────

    // GET /api/aniskip/{slug}/{season}/{episode}
    // Fully automatic: finds MAL ID by title if missing, caches everything
    public function aniSkip(string $slug, int $season, int $episode)
    {
        $anime       = Anime::where('slug', $slug)->first();
        if (!$anime) return response()->json(['aniskip' => null]);

        $seasonModel = $anime->seasons()->where('season_number', $season)->first();
        if (!$seasonModel) return response()->json(['aniskip' => null]);

        $seasonMalId = $seasonModel->mal_id;

        try {
            // anime.mal_id yoksa title search (bir kez, cache'lenir)
            if (!$anime->mal_id) {
                $found = (new \App\Services\JikanService())->searchMalId($anime->title, $anime->title_en, $anime->title_jp);
                if ($found) $anime->update(['mal_id' => $found]);
            }

            if (!$seasonMalId && $anime->mal_id) {
                // S1 için anime.mal_id direkt kullan — Jikan'a gitme
                if ($season === 1) {
                    $seasonMalId = $anime->mal_id;
                    $seasonModel->update(['mal_id' => $seasonMalId]);
                } else {
                    // Diğer sezonlar: sadece cache'ten bak, yoksa null dön (page load bloke olmasın)
                    $chain = \Illuminate\Support\Facades\Cache::get("jikan_chain_{$anime->mal_id}");
                    if ($chain) {
                        $seasonMalId = $chain[$season - 1] ?? $chain[0] ?? null;
                        if ($seasonMalId) $seasonModel->update(['mal_id' => $seasonMalId]);
                    }
                }
            }

            if ($seasonMalId) {
                $data = (new \App\Services\AniSkipService())->getSkipTimes((string)$seasonMalId, $episode);
                return response()->json(['aniskip' => $data]);
            }
        } catch (\Throwable) {}

        return response()->json(['aniskip' => null]);
    }

    // ── Skip segments ─────────────────────────────────────────────────────────

    // POST /api/episodes/{episode}/skip-event  (anonim OK, rate-limited)
    public function recordSkipEvent(Request $request, Episode $episode)
    {
        $from = (int) $request->input('from_sec', 0);
        $to   = (int) $request->input('to_sec',   0);

        // Basic sanity: must skip forward at least 5s, not more than 10 min
        if ($to <= $from + 4 || ($to - $from) > 600) {
            return response()->json(['ok' => false]);
        }

        DB::table('episode_skip_events')->insert([
            'episode_id'  => $episode->id,
            'from_sec'    => $from,
            'to_sec'      => $to,
            'created_at'  => now(),
        ]);

        return response()->json(['ok' => true]);
    }

    // GET /api/episodes/{episode}/skip-segments
    // Returns segments where >= 10 users skipped from within a 30-second window
    public function skipSegments(Episode $episode)
    {
        // İntro tespiti: ilk 3 dakika içinde 45-150sn ileri atlama = intro skip
        // Kümeleme: 20sn bucket, to_sec standart sapması <= 15sn, en az 2 farklı kullanıcı
        $rows = DB::table('episode_skip_events')
            ->where('episode_id', $episode->id)
            ->where('from_sec', '<', 180)
            ->whereRaw('(to_sec - from_sec) BETWEEN 45 AND 150')
            ->selectRaw('
                FLOOR(from_sec / 20) * 20            AS bucket_start,
                AVG(to_sec)                          AS avg_to,
                STDDEV_POP(to_sec)                   AS stddev_to,
                COUNT(*)                             AS cnt
            ')
            ->groupByRaw('FLOOR(from_sec / 20) * 20')
            ->havingRaw('cnt >= 2 AND (STDDEV_POP(to_sec) <= 15 OR cnt = 1)')
            ->orderBy('cnt', 'desc')
            ->limit(1)
            ->get();

        $segments = $rows->map(fn($r) => [
            'from' => (int) $r->bucket_start,
            'to'   => (int) round($r->avg_to),
            'count'=> (int) $r->cnt,
        ])->values();

        return response()->json(['segments' => $segments]);
    }

    private function continueWatchingResource($cw): array
    {
        return [
            'id'               => $cw->id,
            'season_number'    => $cw->season_number,
            'episode_number'   => $cw->episode_number,
            'percent_complete' => $cw->percent_complete,
            'anime' => $cw->anime ? [
                'id'        => $cw->anime->id,
                'title'     => $cw->anime->title,
                'slug'      => $cw->anime->slug,
                'cover_url' => \App\Support\MediaUrl::fromStoragePath($cw->anime->cover_image),
            ] : null,
        ];
    }

    // POST /api/sources/flag-hevc
    // Player tarafından çağrılır: HEVC hatası alınan kaynak URL'sini DB'ye işler
    public function flagHevc(Request $request)
    {
        $url = $request->input('url');
        if (!$url) return response()->json(['ok' => false]);

        \App\Models\VideoSource::where('url', $url)->update([
            'is_hevc'         => true,
            'hevc_checked_at' => now(),
        ]);

        return response()->json(['ok' => true]);
    }
}
