<?php

namespace App\Http\Controllers\Frontend;

use Carbon\Carbon;
use App\Models\Quiz;
use Firebase\JWT\JWT;
use App\Models\Course;
use App\Models\QuizResult;
use App\Models\Announcement;
use App\Models\CourseReview;
use App\Models\JitsiSetting;
use App\Models\QuizQuestion;
use Illuminate\Http\Request;
use App\Models\CourseProgress;
use App\Rules\CustomRecaptcha;
use App\Models\CourseChapterItem;
use App\Models\CourseChapterLesson;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Cache;
use App\Traits\GenerateSecureLinkTrait;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Facades\Storage;

class LearningController extends Controller {
    use GenerateSecureLinkTrait;
    function index(string $slug) {
        $user = userAuth();
        $course = Course::active()->with([
            'chapters',
            'chapters.chapterItems',
            'chapters.chapterItems.lesson',
            'chapters.chapterItems.quiz',
        ])->withTrashed()->where('slug', $slug)->whereHas('enrollments', fn($q) => $q->where('user_id', $user->id))->first();
        if(!$course){
            abort(404);
        }
        Session::put('course_slug', $slug);
        Session::put('course_title', $course->title);

        $currentProgress = CourseProgress::where('user_id', $user->id)
            ->where('course_id', $course->id)
            ->where('current', 1)
            ->orderBy('id', 'desc')
            ->first();

        $alreadyWatchedLectures = CourseProgress::where('user_id', $user->id)
            ->where('course_id', $course->id)
            ->where('type', 'lesson')
            ->where('watched', 1)
            ->pluck('lesson_id')
            ->toArray();

        $alreadyCompletedQuiz = CourseProgress::where('user_id', $user->id)
            ->where('course_id', $course->id)
            ->where('type', 'quiz')
            ->where('watched', 1)
            ->pluck('lesson_id')
            ->toArray();

        $announcements = Announcement::where('course_id', $course->id)->orderBy('id', 'desc')->get();

        $courseLectureCount = CourseChapterItem::whereHas('chapter', function ($q) use ($course) {
            $q->where('course_id', $course->id);
        })->count();

        $courseLectureCompletedByUser = CourseProgress::where('user_id', $user->id)
            ->where('course_id', $course->id)->where('watched', 1)->count();
        $courseCompletedPercent = $courseLectureCount > 0 ? ($courseLectureCompletedByUser / $courseLectureCount) * 100 : 0;

        if (!$currentProgress) {
            $lessonId = @$course->chapters?->first()?->chapterItems()?->first()?->lesson->id;
            if ($lessonId) {
                $currentProgress = CourseProgress::create([
                    'user_id'    => $user->id,
                    'course_id'  => $course->id,
                    'chapter_id' => $course->chapters->first()->id,
                    'lesson_id'  => $lessonId,
                    'current'    => 1,
                ]);
            }
        }
        return view('frontend.pages.learning-player.index', compact(
            'course',
            'currentProgress',
            'announcements',
            'courseCompletedPercent',
            'courseLectureCount',
            'courseLectureCompletedByUser',
            'alreadyWatchedLectures',
            'alreadyCompletedQuiz'
        ));
    }

    function getFileInfo(Request $request) {
        // set progress status
        CourseProgress::where('course_id', $request->courseId)->update(['current' => 0]);
        $progress = CourseProgress::updateOrCreate(
            [
                'user_id'    => userAuth()->id,
                'course_id'  => $request->courseId,
                'chapter_id' => $request->chapterId,
                'lesson_id'  => $request->lessonId,
                'type'       => $request->type,
            ],
            [
                'current' => 1,
            ]
        );

        if ($request->type == 'lesson') {
            $fileInfo = array_merge(CourseChapterLesson::select(['id', 'file_path', 'storage', 'file_type', 'downloadable', 'description'])->findOrFail($request->lessonId)->toArray(), ['type' => 'lesson']);
            if (in_array($fileInfo['storage'], ['wasabi', 'aws'])) {
                $fileInfo['file_path'] = Storage::disk($fileInfo['storage'])->temporaryUrl($fileInfo['file_path'], now()->addSeconds(30));
            }
            if($fileInfo['storage'] == 'upload'){
                $fileInfo['file_path'] = $this->generateSecureLink($fileInfo['file_path']);
            }
            return response()->json([
                'file_info' => $fileInfo,
            ]);
        } elseif ($request->type == 'live') {
            $fileInfo = array_merge(
                CourseChapterLesson::with([
                    'course:id,instructor_id,slug',
                    'course.instructor:id',
                    'course.instructor.zoom_credential:id,instructor_id,client_id,client_secret',
                    'course.instructor.jitsi_credential:id,instructor_id,app_id,api_key,permissions',
                    'live:id,lesson_id,start_time,type,meeting_id,password,join_url',
                ])->select([
                    'id', 'course_id', 'chapter_item_id', 'title', 'description',
                    'duration', 'file_path', 'storage', 'file_type', 'downloadable',
                ])->findOrFail($request->lessonId)->toArray(),
                ['type' => 'live']
            );

            $now = Carbon::now();
            $startTime = Carbon::parse($fileInfo['live']['start_time']);
            $endTime = $startTime->clone()->addMinutes($fileInfo['duration']);
            $fileInfo['start_time'] = formattedDateTime($startTime);
            $fileInfo['end_time'] = formattedDateTime($endTime);
            $fileInfo['is_live_now'] = $now->between($startTime, $endTime);

            if ($now->lt($startTime)) {
                $fileInfo['is_live_now'] = 'not_started';
            } elseif ($now->between($startTime, $endTime)) {
                $fileInfo['is_live_now'] = 'started';
            } else {
                $fileInfo['is_live_now'] = 'ended';
            }

            return response()->json([
                'file_info' => $fileInfo,
            ]);
        } elseif ($request->type == 'document') {
            $fileInfo = array_merge(CourseChapterLesson::select(['id', 'file_path', 'storage', 'file_type', 'downloadable', 'description'])->findOrFail($request->lessonId)->toArray(), ['type' => 'document']);
            if ('pdf' == $fileInfo['file_type']) {
                return response()->json([
                    'view'      => view('frontend.pages.learning-player.partials.pdf-viewer', ['file_path' => $fileInfo['file_path']])->render(),
                    'file_info' => $fileInfo,
                ]);
            } elseif ('docx' == $fileInfo['file_type']) {
                return response()->json([
                    'view'      => view('frontend.pages.learning-player.partials.docx-viewer', ['file_path' => $fileInfo['file_path']])->render(),
                    'file_info' => $fileInfo,
                ]);
            } else {
                return response()->json([
                    'file_info' => $fileInfo,
                ]);
            }
        } else {
            $fileInfo = array_merge(Quiz::findOrFail($request->lessonId)->toArray(), ['type' => 'quiz']);

            return response()->json([
                'file_info' => $fileInfo,
            ]);
        }
    }

    function makeLessonComplete(Request $request) {
        $progress = CourseProgress::where(['lesson_id' => $request->lessonId, 'user_id' => userAuth()->id, 'type' => $request->type])->first();
        if ($progress) {
            $progress->watched = $request->status;
            $progress->save();
            return response()->json(['status' => 'success', 'message' => __('Updated successfully.')]);
        } else {
            if ($request->status == 0) {
                return;
            }

            return response()->json(['status' => 'error', 'message' => __('You didnt watched this lesson')]);
        }
    }

    function downloadResource(string $lessonId) {
        $resource = CourseChapterLesson::findOrFail($lessonId);
        if (!\File::exists(public_path($resource->file_path))) {
            return redirect()->back()->with(['alert-type' => 'error', 'messege' => __('Links is broke or some thing went wrong')]);
        }
        return response()->download(public_path($resource->file_path));
    }

    function quizIndex(string $id) {
        $attempt = QuizResult::where('user_id', userAuth()->id)->where('quiz_id', $id)->count();
        $quiz = Quiz::withCount('questions')->findOrFail($id);
        if ($attempt >= $quiz->attempt) {
            return redirect()->route('student.learning.index', Session::get('course_slug'))->with(['alert-type' => 'error', 'messege' => __('You reached maximum attempt')]);
        }

        return view('frontend.pages.learning-player.quiz-index', compact('quiz', 'attempt'));
    }

    function quizStore(Request $request, string $id) {
        $grad = 0;
        $result = [];
        $quiz = Quiz::findOrFail($id);
        foreach ($request->question ?? [] as $key => $questionAns) {
            $question = QuizQuestion::findOrFail($key);
            $answer = $question->answers->where('correct', 1)->pluck('id')->toArray();

            if (in_array($questionAns, $answer)) {
                $grad += $question->grade;
            }
            $result[$key] = [
                "answer"  => $questionAns,
                "correct" => in_array($questionAns, $answer),
            ];
        }

        $quizResult = QuizResult::create([
            'user_id'    => userAuth()->id,
            'quiz_id'    => $id,
            'result'     => json_encode($result),
            'user_grade' => $grad,
            'status'     => $grad >= $quiz->pass_mark ? 'pass' : 'failed',
        ]);
        return redirect()->route('student.quiz.result', ['id' => $id, 'result_id' => $quizResult->id]);
    }

    function quizResult(string $id, string $resultId) {
        $attempt = QuizResult::where('user_id', userAuth()->id)->where('quiz_id', $id)->count();
        $quiz = Quiz::withCount('questions')->findOrFail($id);
        $quizResult = QuizResult::findOrFail($resultId);

        return view('frontend.pages.learning-player.quiz-result', compact('quiz', 'attempt', 'quizResult'));
    }

    function addReview(Request $request) {
        $request->validate([
            'course_id'            => ['required', 'exists:courses,id'],
            'rating'               => ['required', 'integer', 'min:1', 'max:5'],
            'review'               => ['required', 'max: 1000', 'string'],
            'g-recaptcha-response' => Cache::get('setting')->recaptcha_status === 'active' ? ['required', new CustomRecaptcha()] : 'nullable',
        ], [
            'rating.required'               => __('rating filed is required'),
            'rating.integer'                => __('rating have to be an integer'),
            'review.required'               => __('review filed is required'),
            'g-recaptcha-response.required' => __('Please complete the recaptcha to submit the form'),
        ]);

        $review = CourseReview::where(['course_id' => $request->course_id, 'user_id' => userAuth()->id])->first();
        if ($review) {
            return redirect()->back()->with(['alert-type' => 'error', 'messege' => __('Already added review')]);
        }

        CourseReview::create([
            'course_id' => $request->course_id,
            'user_id'   => userAuth()->id,
            'rating'    => $request->rating,
            'review'    => $request->review,
        ]);

        return redirect()->back()->with(['alert-type' => 'success', 'messege' => __('Review added successfully')]);

    }

    function fetchReviews(Request $request, string $courseId) {
        $reviews = CourseReview::where(['course_id' => $courseId, 'status' => 1])->whereHas('course')->whereHas('user')->orderBy('id', 'desc')->paginate(8, ['*'], 'page', $request->page ?? 1);
        return response()->json([
            'view'       => view('frontend.pages.learning-player.partials.review-card', compact('reviews'))->render(),
            'page'       => $request->page,
            'last_page'  => $reviews->lastPage(),
            'data_count' => $reviews->count(),
        ]);
    }

    function liveSession(Request $request, string $slug, string $lesson_id) {
        $lesson = CourseChapterLesson::select('id', 'course_id', 'chapter_item_id', 'title')->with(['course' => function ($q) {
            $q->select('id', 'instructor_id', 'slug');
        }, 'course.instructor' => function ($q) {
            $q->select('id');
        }, 'course.instructor.zoom_credential' => function ($q) {
            $q->select('id', 'instructor_id', 'client_id', 'client_secret');
        }, 'chapterItem' => function ($q) {
            $q->select('id', 'type');
        }, 'live' => function ($q) {
            $q->select('id', 'lesson_id', 'start_time', 'type', 'meeting_id', 'password', 'join_url');
        }])->findOrFail($lesson_id);

        if ($lesson->live->type == 'zoom') {
            return view('frontend.pages.learning-player.partials.live.zoom', compact('lesson'));
        } else {
            $jitsi_credential = JitsiSetting::where('instructor_id',$lesson->course->instructor_id)->first();
            if($jitsi_credential){
                $jwt = $this->generateJwtToken($jitsi_credential);
                $roomName = "{$jitsi_credential->app_id}/{$lesson->live->meeting_id}";
                return view('frontend.pages.learning-player.partials.live.jitsi', [
                    'title' => $lesson->title,
                    'jwt' => trim($jwt),
                    'roomName' => $roomName
                ]);
            }
            return back();
        }
    }

    /**
     * Generate a JaaS JWT token.
     *
     * @return string
     */
    protected function generateJwtToken($jitsi_credential) {
        $user = userAuth();
        $instructor = $jitsi_credential->instructor_id == $user->id;

        $api_key = $jitsi_credential->api_key;
        $app_id =  $jitsi_credential->app_id; // Your AppID (previously tenant)
        $user_email = $user->name;
        $user_name = $user->name;
        $user_is_moderator = $instructor;
        $user_avatar_url = !empty($user->image) ? asset($user->image) : "";
        $user_id = $user->id;
        $live_streaming_enabled = $instructor;
        $recording_enabled = $instructor;
        $outbound_enabled = false;
        $transcription_enabled = false;
        $exp_delay = 7200;
        $nbf_delay = 0;

        // Read your private key from file
        $private_key = file_get_contents(storage_path("app/user_{$jitsi_credential->instructor_id}/rsb_private_key.pk"));

        $payload = [
            'iss'     => 'chat',
            'aud'     => 'jitsi',
            'exp'     => time() + $exp_delay,
            'nbf'     => time() - $nbf_delay,
            'room'    => '*',
            'sub'     => $app_id,
            'context' => [
                'user'     => [
                    'moderator' => $user_is_moderator ? "true" : "false",
                    'email'     => $user_email,
                    'name'      => $user_name,
                    'avatar'    => $user_avatar_url,
                    'id'        => $user_id,
                ],
                'features' => [
                    'recording'     => $recording_enabled ? "true" : "false",
                    'livestreaming' => $live_streaming_enabled ? "true" : "false",
                    'transcription' => $transcription_enabled ? "true" : "false",
                    'outbound-call' => $outbound_enabled ? "true" : "false",
                ],
            ],
        ];

        return JWT::encode($payload, $private_key, "RS256", $api_key);
    }
}