<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Models\Episode;
use App\Models\VideoEngagement;
use App\Models\Watched;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\RateLimiter;

class StreamApiController extends Controller
{
    /**
     * Get Data used by the Video Player.
     */
    public function getStream(Request $request)
    {
        $validated = $request->validate([
            'episode_id' => 'required',
        ]);

        $episode = Episode::where('id', $request->input('episode_id'))->firstOrFail();

        $subtitles = $episode->subtitles
            ->mapWithKeys(fn ($sub) => [$sub->subtitle->slug => $sub->subtitle->name])
            ->toArray();

        return response()->json([
            'title' => $episode->title.' - '.$episode->episode,
            'poster' => $episode->gallery()->first()->image_url,
            'interpolated' => $episode->interpolated,
            'interpolated_uhd' => $episode->interpolated_uhd,
            'stream_url' => $episode->dmca_takedown ? 'stuff/dmca' : $episode->url,
            'stream_domains' => config('hstream.stream_domain'),
            'asia_stream_domains' => config('hstream.asia_stream_domain'),
            'extra_subtitles' => $subtitles,
        ], 200);
    }

    /**
     * Track that the authenticated user has watched the episode.
     * Called client-side after 10 seconds of playback.
     */
    public function trackWatched(Request $request): JsonResponse
    {
        $validated = $request->validate([
            'episode_id' => 'required|integer|exists:episodes,id',
        ]);

        $user = Auth::user();
        if (! $user) {
            return response()->json(['watched' => false], 401);
        }

        $episodeId = $request->input('episode_id');

        // 1-hour cooldown to prevent duplicate entries
        $time = Carbon::now()->subHour(1);
        $alreadyWatched = Watched::where('user_id', $user->id)
            ->where('episode_id', $episodeId)
            ->where('created_at', '>=', $time)
            ->exists();

        if (! $alreadyWatched) {
            Watched::create(['user_id' => $user->id, 'episode_id' => $episodeId]);
            cache()->forget('user'.$user->id.'watched'.$episodeId);
        }

        return response()->json(['watched' => true], 200);
    }

    /**
     * Track engagement segments that the authenticated user has watched.
     * Called periodically client-side while the video is playing.
     * Segments are 10-second chunks; segment 0 (0-10s) is excluded.
     */
    public function trackEngagement(Request $request): JsonResponse
    {
        $validated = $request->validate([
            'episode_id' => 'required|integer|exists:episodes,id',
            'segments' => 'required|array',
            'segments.*' => 'integer|min:1',
        ]);

        $user = Auth::user();
        if (! $user) {
            return response()->json(['tracked' => 0], 401);
        }

        $rateLimitKey = 'engagement:'.$user->id;
        if (RateLimiter::tooManyAttempts($rateLimitKey, 10)) {
            $seconds = RateLimiter::availableIn($rateLimitKey);

            return response()->json([
                'tracked' => 0,
                'message' => 'Rate limit exceeded. Try again in '.$seconds.' seconds.',
            ], 429);
        }
        RateLimiter::hit($rateLimitKey, 60);

        $episodeId = $request->input('episode_id');
        $segments = $request->input('segments');
        $tracked = 0;

        foreach ($segments as $segment) {
            // upsert: insert if not exists, otherwise ignore (unique constraint prevents dupes)
            VideoEngagement::firstOrCreate([
                'episode_id' => $episodeId,
                'user_id' => $user->id,
                'segment' => $segment,
            ]);
            $tracked++;
        }

        return response()->json(['tracked' => $tracked], 200);
    }

    /**
     * Get engagement heatmap data for an episode.
     * Returns watch counts per segment, aggregated across all users.
     */
    public function getEngagement(int $episodeId): JsonResponse
    {
        $episode = Episode::findOrFail($episodeId);

        $data = cache()->remember(
            "engagement:{$episodeId}",
            600, // 10-minute cache
            fn () => VideoEngagement::where('episode_id', $episodeId)
                ->select('segment', DB::raw('count(*) as watch_count'))
                ->groupBy('segment')
                ->pluck('watch_count', 'segment')
                ->toArray()
        );

        return response()->json($data, 200);
    }
}
