<?php

namespace App\Repositories\Website;

use App\Models\Ads;
use App\Repositories\Interfaces\Website\HomeRepositoryInterface;
use App\Models\Blog;
use App\Models\Country;
use App\Models\Faq;
use App\Models\Genre;
use App\Models\LiveTv;
use App\Models\Movie;
use App\Models\MovieFile;
use App\Models\MovieLanguage;
use App\Models\Star;
use App\Models\TvShow;
use App\Models\WatchHistory;
use Carbon\Carbon;
use Illuminate\Support\Facades\Auth;
use Exception;
use Illuminate\Support\Facades\Log;
use App\Models\Episode;

class HomeRepository implements HomeRepositoryInterface
{
    public function index($request)
    {
        try {
            if(isset($request['search'])) {
                return $this->all_movies($request, 'search');
            }
            return [
                'top_rated' => Movie::whereNotNull('imdb_rating')->where('imdb_rating', '!=', '')->where('status', 1)->orderByRaw('CAST(imdb_rating AS DECIMAL(3,1)) DESC')->limit(10)->get(),
                'latest' => Movie::where('status', 1)->orderByDesc('created_at')->limit(10)->get(),
                'trending' => Movie::where('status', 1)->where('is_trending', 1)->orderByDesc('id')->limit(10)->get(),
                'featured' => Movie::where('status', 1)->where('is_featured', 1)->orderByDesc('id')->limit(10)->get(),

                'blockbuster' => Movie::where('status', 1)->where('is_blockbuster', 1)->orderByDesc('id')->limit(10)->get(),

                'popular' => Movie::where('status', 1)->orderByDesc('total_view')->limit(10)->get(),
                'real_life_story' => Movie::where('status', 1)->where('is_real_life_story', 1)->orderByDesc('id')->limit(10)->get(),
                'recommended' => Movie::where('status', 1)->where('is_recommended', 1)->orderByDesc('id')->limit(10)->get(),
            ];
        } catch (Exception $e) {
            Log::error('Unexpected Error: ' . $e->getMessage());
            abort(404);
        }
    }

    public function getHomePageData(): array
    {
        $userId = Auth::id();

        return [
            'movie_sliders' => Movie::where('status', 1)->orderBy('id', 'DESC')->limit(10)->get(),
            'latest_movies' => Movie::where('status', 1)->latest()->limit(10)->get(),
            'top_rating_movies' => Movie::where('status', 1)->orderByDesc('imdb_rating', 'DESC')->orderByDesc('rating')->limit(10)->get(),
            'reality_shows' => TvShow::where('status', 1)->where('is_tvseries', 0)->latest()->limit(10)->get(),
            'latest_tv_series' => TvShow::where('status', 1)->latest()->limit(10)->get(),
            'latest_blogs' => Blog::where('status', 1)->latest()->limit(5)->get(),
            'trending_movies' => Movie::where('status', 1)->where('is_trending', 1)->latest()->limit(10)->get(),
            'genres' => Genre::latest()->get(),
            'recommended_movies' => Movie::where('status', 1)->where('is_recommended', 1)->latest()->limit(6)->get(),
            'feature_tv_channels' => LiveTv::where('status', 1)->where('featured', 1)->get(),
            'watch_histories' => WatchHistory::where('user_id', $userId)->where('watchable_type', '!=', 'live_tv')->latest()->limit(10)->get(),
            'artists' => $this->getTopActors(),
            'top_view_today' => Movie::where('status', 1)->orderByDesc('today_view', 'DESC')->limit(10)->get(),
        ];
    }

    protected function getTopActors()
    {
        try {
            $starIds = Movie::where('status', 1)
                ->orderByDesc('imdb_rating')
                ->limit(20)
                ->get()
                ->flatMap(function ($movie) {
                    return json_decode($movie->stars ?? '[]', true);
                })
                ->unique()
                ->values();

            return Star::whereIn('id', $starIds)
                ->where('star_type', 'actor')
                ->get()
                ->take(7);
        } catch (Exception $e) {
            Log::error('Unexpected Error: ' . $e->getMessage());
            abort(404);
        }
    }

    public function getFaqs(): array
    {
        return [
            'payment_faqs' => Faq::where('type', 'payment')->where('status', 1)->latest()->get(),
            'order_faqs'   => Faq::where('type', 'order')->where('status', 1)->latest()->get(),
        ];
    }

    public function all_movies($request, $type)
    {
        try {
            $query = Movie::where('status', 1);

            if ($type == 'search') {
                 $query = $query->where('title', 'like', '%' . $request['search'] . '%');
            }

            if ($type == 'top-view') {
                $query = $query->orderByDesc('today_view', 'DESC');
            }
            if ($type == 'top-rating') {
                $query = $query->orderByDesc('imdb_rating', 'DESC')->orderByDesc('rating');
            }
            if ($type == 'trending') {
                $query = $query->where('is_trending', 1);
            }
            if ($type == 'recommended') {
                $query = $query->where('is_recommended', 1);
            }
            if ($type == 'featured') {
                $query = $query->where('is_featured', 1);
            }
            if ($type == 'blockbuster') {
                $query = $query->where('is_blockbuster', 1);
            }
            if ($type == 'real-life-story') {
                $query = $query->where('is_real_life_story', 1);
            }
            if ($type == 'popular') {
                $query = $query->orderByDesc('total_view');
            }

            if ($request->filled('ratings')) {
                // ratings can come as comma-separated like "5,7"
                $selectedRatings = explode('-', $request->ratings);

                $query->where(function ($q) use ($selectedRatings) {
                    foreach ($selectedRatings as $rating) {
                        $r = floatval($rating);
                        $tolerance = 0.999; // adjust as needed, e.g. ±0.3

                        $min = $r - $tolerance;
                        $max = $r + $tolerance;

                        $q->orWhere(function ($subQuery) use ($min, $max) {
                            $subQuery->whereBetween('rating', [$min, $max])
                                ->orWhereBetween('imdb_rating', [$min, $max]);
                        });
                    }
                });
            }

            // Genres
            if ($request->filled('genres')) {
                $slugs = explode('-', $request->genres);
                $genre_ids = Genre::whereIn('slug', $slugs)->pluck('id')->toArray();
                if (!empty($genre_ids)) {
                    $query->where(function ($q) use ($genre_ids) {
                        foreach ($genre_ids as $id) {
                            $q->orWhereJsonContains('genre', (string)$id);
                        }
                    });
                }
            }

            // Years
            if ($request->filled('years')) {
                $years = explode('-', $request->years);
                $query->where(function ($q) use ($years) {
                    foreach ($years as $year) {
                        $q->orWhereYear('release', $year);
                    }
                });
            }

            // Languages
            if ($request->filled('languages')) {
                $languages = explode('-', $request->languages);
                $language_ids = MovieLanguage::whereIn('slug', $languages)->pluck('id')->toArray();

                $query->where(function ($q) use ($language_ids) {
                    foreach ($language_ids as $id) {
                        $q->orWhereJsonContains('language', (string)$id);
                    }
                });
            }


            // Countries
            if ($request->filled('countries')) {
                $slugs = explode('-', $request->countries);
                $country_ids = Country::whereIn('slug', $slugs)->pluck('id')->toArray();
                $query->where(function ($q) use ($country_ids) {
                    foreach ($country_ids as $id) {
                        $q->orWhereJsonContains('country', (string)$id);
                    }
                });
            }

            if ($request->ajax()) {
                $movies = $query->paginate(15); // or whatever number you need
                $view = view('website.movie.partials.movie_cards', compact('movies'))->render();

                return response()->json([
                    'html' => $view,
                    'hasMore' => $movies->hasMorePages(),
                    'nextPage' => $movies->currentPage() + 1,
                ]);
            }

            return [
                'type'         => str_replace('-', ' ', $type),
                'current_year' => date('Y'),
                'languages' => MovieLanguage::get(),
                'countries' => Country::get(),
                'years'        => range(date('Y'), 1975),
                'videos'       => $query->latest()->paginate(25),
            ];
        } catch (Exception $e) {
            Log::error('Unexpected Error: ' . $e->getMessage());
            abort(404);
        }
    }

    public function movie_details($slug = null)
    {
        try {
            $movie = Movie::where('slug', $slug)->with('favoritedByUsers')->first();

            // If movie is not found, abort with 404
            if (!$movie) {
                abort(404);
            }


            // Get current time
            $now = Carbon::now();

            // Convert last_view_reset to Carbon instance (if available)
            $lastReset = $movie->last_view_reset ? Carbon::parse($movie->last_view_reset) : null;

            // Daily view logic
            if ($lastReset && $now->isSameDay($lastReset)) {
                $movie->increment('today_view');
            } else {
                $movie->today_view = 1;
            }

            // Weekly view logic
            if ($lastReset && $now->isSameWeek($lastReset)) {
                $movie->increment('weekly_view');
            } else {
                $movie->weekly_view = 1;
            }

            // Monthly view logic
            if ($lastReset && $now->isSameMonth($lastReset)) {
                $movie->increment('monthly_view');
            } else {
                $movie->monthly_view = 1;
            }

            // Always increment total views
            $movie->increment('total_view');

            // Update last reset time
            $movie->last_view_reset = $now;
            $movie->save();

            return [
                'movie' => $movie,
                'movie_files' => MovieFile::where('video_id', $movie->id)->orderBy('order', 'ASC')->get(),
                'related_movies' => Movie::latest()->limit(15)->get(),
                'recommended_movies' => Movie::where('status', 1)->where('is_recommended', 1)->latest()->limit(15)->get(),
            ];
        } catch (Exception $e) {
            Log::error('Unexpected Error on movie_details function: ' . $e->getMessage());
            abort(404);
        }
    }

    public function genre_wise_movie($request, $genre_ids, $slug)
    {
        try {
            $query = Movie::where('status', 1);

            $query->where(function ($q) use ($genre_ids) {
                foreach ($genre_ids as $id) {
                    $q->orWhereJsonContains('genre', (string)$id);
                }
            });

            if ($request->filled('ratings')) {
                // ratings can come as comma-separated like "5,7"
                $selectedRatings = explode('-', $request->ratings);

                $query->where(function ($q) use ($selectedRatings) {
                    foreach ($selectedRatings as $rating) {
                        $r = floatval($rating);
                        $tolerance = 0.999; // adjust as needed, e.g. ±0.3

                        $min = $r - $tolerance;
                        $max = $r + $tolerance;

                        $q->orWhere(function ($subQuery) use ($min, $max) {
                            $subQuery->whereBetween('rating', [$min, $max])
                                ->orWhereBetween('imdb_rating', [$min, $max]);
                        });
                    }
                });
            }

            // Genres
            if ($request->filled('genres')) {
                $slugs = explode('-', $request->genres);
                $genre_ids = Genre::whereIn('slug', $slugs)->pluck('id')->toArray();
                if (!empty($genre_ids)) {
                    $query->where(function ($q) use ($genre_ids) {
                        foreach ($genre_ids as $id) {
                            $q->orWhereJsonContains('genre', (string)$id);
                        }
                    });
                }
            }

            // Years
            if ($request->filled('years')) {
                $years = explode('-', $request->years);
                $query->where(function ($q) use ($years) {
                    foreach ($years as $year) {
                        $q->orWhereYear('release', $year);
                    }
                });
            }

            // Languages
            if ($request->filled('languages')) {
                $languages = explode('-', $request->languages);
                $language_ids = MovieLanguage::whereIn('slug', $languages)->pluck('id')->toArray();

                $query->where(function ($q) use ($language_ids) {
                    foreach ($language_ids as $id) {
                        $q->orWhereJsonContains('language', (string)$id);
                    }
                });
            }

            // Countries
            if ($request->filled('countries')) {
                $slugs = explode('-', $request->countries);
                $country_ids = Country::whereIn('slug', $slugs)->pluck('id')->toArray();
                $query->where(function ($q) use ($country_ids) {
                    foreach ($country_ids as $id) {
                        $q->orWhereJsonContains('country', (string)$id);
                    }
                });
            }

            return [
                'type'         => str_replace('-', ' ', $slug),
                'current_year' => date('Y'),
                'languages' => MovieLanguage::get(),
                'countries' => Country::get(),
                'years'        => range(date('Y'), 1975),
                'videos'       => $query->latest()->paginate(25),
                'is_genre' => 1
            ];
        } catch (Exception $e) {
            Log::error('Unexpected Error: ' . $e->getMessage());
            abort(404);
        }
    }

    public function country_wise_movie($request, $country_ids, $slug)
    {
        try {
            $query = Movie::where('status', 1);

            $query->where(function ($q) use ($country_ids) {
                foreach ($country_ids as $id) {
                    $q->orWhereJsonContains('country', (string)$id);
                }
            });

            if ($request->filled('ratings')) {
                // ratings can come as comma-separated like "5,7"
                $selectedRatings = explode('-', $request->ratings);

                $query->where(function ($q) use ($selectedRatings) {
                    foreach ($selectedRatings as $rating) {
                        $r = floatval($rating);
                        $tolerance = 0.999; // adjust as needed, e.g. ±0.3

                        $min = $r - $tolerance;
                        $max = $r + $tolerance;

                        $q->orWhere(function ($subQuery) use ($min, $max) {
                            $subQuery->whereBetween('rating', [$min, $max])
                                ->orWhereBetween('imdb_rating', [$min, $max]);
                        });
                    }
                });
            }

            // Genres
            if ($request->filled('genres')) {
                $slugs = explode('-', $request->genres);
                $genre_ids = Genre::whereIn('slug', $slugs)->pluck('id')->toArray();
                if (!empty($genre_ids)) {
                    $query->where(function ($q) use ($genre_ids) {
                        foreach ($genre_ids as $id) {
                            $q->orWhereJsonContains('genre', (string)$id);
                        }
                    });
                }
            }

            // Years
            if ($request->filled('years')) {
                $years = explode('-', $request->years);
                $query->where(function ($q) use ($years) {
                    foreach ($years as $year) {
                        $q->orWhereYear('release', $year);
                    }
                });
            }

            // Languages
            if ($request->filled('languages')) {
                $languages = explode('-', $request->languages);
                $language_ids = MovieLanguage::whereIn('slug', $languages)->pluck('id')->toArray();

                $query->where(function ($q) use ($language_ids) {
                    foreach ($language_ids as $id) {
                        $q->orWhereJsonContains('language', (string)$id);
                    }
                });
            }


            // Countries
            if ($request->filled('countries')) {
                $slugs = explode('-', $request->countries);
                $country_ids = Country::whereIn('slug', $slugs)->pluck('id')->toArray();
                $query->where(function ($q) use ($country_ids) {
                    foreach ($country_ids as $id) {
                        $q->orWhereJsonContains('country', (string)$id);
                    }
                });
            }

            return [
                'type'         => str_replace('-', ' ', $slug),
                'current_year' => date('Y'),
                'languages' => MovieLanguage::get(),
                'countries' => Country::get(),
                'years'        => range(date('Y'), 1975),
                'videos'       => $query->latest()->paginate(25),
                'is_country' => 1
            ];
        } catch (Exception $e) {
            Log::error('Unexpected Error on country_wise_movie function: ' . $e->getMessage());
            abort(404);
        }
    }

    public function all_tv_series($request, $type)
    {
        try {
            $query = TvShow::where('status', 1);

            if ($type == 'blockbuster') {
                $query = $query->where('is_blockbuster', 1);
            }
            if ($type == 'recommended') {
                $query = $query->where('is_recommended', 1);
            }
            if ($type == 'featured') {
                $query = $query->where('is_featured', 1);
            }
            if ($type == 'real-life-story') {
                $query = $query->where('is_real_life_story', 1);
            }
            if ($type == 'top-rating') {
                $query = $query->orderByDesc('imdb_rating', 'DESC')->orderByDesc('rating');
            }
            if ($type == 'popular') {
                $query = $query->orderByDesc('total_view');
            }

            if ($request->filled('ratings')) {
                // ratings can come as comma-separated like "5,7"
                $selectedRatings = explode('-', $request->ratings);

                $query->where(function ($q) use ($selectedRatings) {
                    foreach ($selectedRatings as $rating) {
                        $r = floatval($rating);
                        $tolerance = 0.999; // adjust as needed, e.g. ±0.3

                        $min = $r - $tolerance;
                        $max = $r + $tolerance;

                        $q->orWhere(function ($subQuery) use ($min, $max) {
                            $subQuery->whereBetween('rating', [$min, $max])
                                ->orWhereBetween('imdb_rating', [$min, $max]);
                        });
                    }
                });
            }

            // Genres
            if ($request->filled('genres')) {
                $slugs = explode('-', $request->genres);
                $genre_ids = Genre::whereIn('slug', $slugs)->pluck('id')->toArray();
                if (!empty($genre_ids)) {
                    $query->where(function ($q) use ($genre_ids) {
                        foreach ($genre_ids as $id) {
                            $q->orWhereJsonContains('genre', (string)$id);
                        }
                    });
                }
            }

            // Years
            if ($request->filled('years')) {
                $years = explode('-', $request->years);
                $query->where(function ($q) use ($years) {
                    foreach ($years as $year) {
                        $q->orWhereYear('release', $year);
                    }
                });
            }

            // Languages
            if ($request->filled('languages')) {
                $languages = explode('-', $request->languages);
                $language_ids = MovieLanguage::whereIn('slug', $languages)->pluck('id')->toArray();

                $query->where(function ($q) use ($language_ids) {
                    foreach ($language_ids as $id) {
                        $q->orWhereJsonContains('language', (string)$id);
                    }
                });
            }


            // Countries
            if ($request->filled('countries')) {
                $slugs = explode('-', $request->countries);
                $country_ids = Country::whereIn('slug', $slugs)->pluck('id')->toArray();
                $query->where(function ($q) use ($country_ids) {
                    foreach ($country_ids as $id) {
                        $q->orWhereJsonContains('country', (string)$id);
                    }
                });
            }

            if ($request->ajax()) {
                $videos = $query->paginate(15); // or whatever number you need
                $view = view('website.movie.partials.movie_cards', compact('videos'))->render();

                return response()->json([
                    'html' => $view,
                    'hasMore' => $videos->hasMorePages(),
                    'nextPage' => $videos->currentPage() + 1,
                ]);
            }

            return [
                'type'         => str_replace('-', ' ', $type),
                'current_year' => date('Y'),
                'languages' => MovieLanguage::get(),
                'countries' => Country::get(),
                'years'        => range(date('Y'), 1975),
                'videos'       => $query->latest()->paginate(25),
                'is_tv_series' => 1
            ];
        } catch (Exception $e) {
            Log::error('Unexpected Error on all_tv_series function: ' . $e->getMessage());
            abort(404);
        }
    }

    public function tv_series()
    {
        try {
            return [
                'top_rated' => TvShow::whereNotNull('imdb_rating')->where('imdb_rating', '!=', '')->where('status', 1)->orderByRaw('CAST(imdb_rating AS DECIMAL(3,1)) DESC')->limit(10)->get(),
                'latest' => TvShow::where('status', 1)->orderByDesc('created_at')->limit(10)->get(),
                // 'trending' => TvShow::where('status', 1)->where('is_trending', 1)->orderByDesc('id')->limit(10)->get(),
                'featured' => TvShow::where('status', 1)->where('is_featured', 1)->orderByDesc('id')->limit(10)->get(),
                'blockbuster' => TvShow::where('status', 1)->where('is_blockbuster', 1)->orderByDesc('id')->limit(10)->get(),
                'popular' => TvShow::where('status', 1)->orderByDesc('total_view')->limit(10)->get(),
                'real_life_story' => TvShow::where('status', 1)->where('is_real_life_story', 1)->orderByDesc('id')->limit(10)->get(),
                'recommended' => TvShow::where('status', 1)->where('is_recommended', 1)->orderByDesc('id')->limit(10)->get(),
            ];
        } catch (Exception $e) {
            Log::error('Unexpected Error on tv_series function: ' . $e->getMessage());
            abort(404);
        }
    }

    public function series_details($slug = null) {
        try {
            $series = TvShow::where('slug', $slug)->first();

            // If movie is not found, abort with 404
            if (!$series) {
                abort(404);
            }

            // Get current time
            $now = Carbon::now();

            // Convert last_view_reset to Carbon instance (if available)
            $lastReset = $series->last_view_reset ? Carbon::parse($series->last_view_reset) : null;

            // Daily view logic
            if ($lastReset && $now->isSameDay($lastReset)) {
                $series->increment('today_view');
            } else {
                $series->today_view = 1;
            }

            // Weekly view logic
            if ($lastReset && $now->isSameWeek($lastReset)) {
                $series->increment('weekly_view');
            } else {
                $series->weekly_view = 1;
            }

            // Monthly view logic
            if ($lastReset && $now->isSameMonth($lastReset)) {
                $series->increment('monthly_view');
            } else {
                $series->monthly_view = 1;
            }

            // Always increment total views
            $series->increment('total_view');

            // Update last reset time
            $series->last_view_reset = $now;
            $series->save();

            return [
                'series' => $series,
                'related_series' => TvShow::latest()->limit(15)->get(),
                'recommended_series' => TvShow::where('is_recommended', 1)->latest()->limit(15)->get(),
                'file_url' => '',
                'series_files' => [],
            ];
        } catch (Exception $e) {
            Log::error('Unexpected Error on series_details function: ' . $e->getMessage());
            abort(404);
        }
    }

    public function video_player($slug = null, $type = null, $key = null) {
        try {  
            if($type == 'movie') {
                $video = Movie::where('slug', $slug)->first();
                $video_files = MovieFile::where('stream_key', $key)->orderBy('order');
                $video->video_url = $video_files->first()?->file_url;
                $video->increment('total_view');
            } elseif ($type == 'episode') {
                $video = Episode::where('slug', $slug)->first();
                $video->increment('total_view');
                $video->video_url = $video?->file_url;
            }

            if(!$video) {
                abort(404);
            }

            $now = Carbon::now();
            $data = [
                'video' => $video,
                'video_type' => $type, 
                'video_files' => $type == 'movie' ? $video_files->get() : '',
                'pre_roll_ad' => Ads::where('type', 'pre_roll')->where('status', 1)->where('start_date', '<=', $now)->where('end_date', '>=', $now)->inRandomOrder()->first(),
                'mid_roll_ad' => Ads::where('type', 'mid_roll')->where('status', 1)->where('start_date', '<=', $now)->where('end_date', '>=', $now)->inRandomOrder()->first(),
                'post_roll_ad' => Ads::where('type', 'post_roll')->where('status', 1)->where('start_date', '<=', $now)->where('end_date', '>=', $now)->inRandomOrder()->first()
            ];
           
            return $data;

        } catch (Exception $e) {
            Log::error('Unexpected Error on video_player function: ' . $e->getMessage());
            abort(404);
        }
    }
}