import { useMutation } from '@tanstack/react-query';
import {
  CheckIcon,
  ChevronLeft,
  ChevronRight,
  Loader2Icon,
  LockIcon,
  XIcon,
} from 'lucide-react';
import { useEffect, useMemo, useState } from 'react';
import type { AICourseDocument } from '../../api/ai-roadmap';
import { readStream } from '../../lib/ai';
import { cn } from '../../lib/classname';
import { isLoggedIn, removeAuthToken } from '../../lib/jwt';
import {
  markdownToHtml,
  markdownToHtmlWithHighlighting,
} from '../../lib/markdown';
import { httpPatch } from '../../lib/query-http';
import { slugify } from '../../lib/slugger';
import {
  getAiCourseLimitOptions,
  getAiCourseOptions,
} from '../../queries/ai-course';
import { useIsPaidUser } from '../../queries/billing';
import { queryClient } from '../../stores/query-client';
import './AICourseLessonChat.css';
import { RegenerateLesson } from './RegenerateLesson';
import { TestMyKnowledgeAction } from './TestMyKnowledgeAction';
import { AICourseLessonChat } from './AICourseLessonChat';

type AICourseLessonProps = {
  courseSlug: string;
  progress: string[];

  activeModuleIndex: number;
  totalModules: number;
  currentModuleTitle: string;
  activeLessonIndex: number;
  totalLessons: number;
  currentLessonTitle: string;

  onGoToPrevLesson: () => void;
  onGoToNextLesson: () => void;

  onUpgrade: () => void;
};

export function AICourseLesson(props: AICourseLessonProps) {
  const {
    courseSlug,
    progress = [],

    activeModuleIndex,
    totalModules,
    currentModuleTitle,
    activeLessonIndex,
    totalLessons,
    currentLessonTitle,

    onGoToPrevLesson,
    onGoToNextLesson,

    onUpgrade,
  } = props;

  const [isLoading, setIsLoading] = useState(true);
  const [isGenerating, setIsGenerating] = useState(false);
  const [error, setError] = useState('');

  const [lessonHtml, setLessonHtml] = useState('');

  const lessonId = `${slugify(String(activeModuleIndex))}-${slugify(String(activeLessonIndex))}`;
  const isLessonDone = progress?.includes(lessonId);

  const { isPaidUser } = useIsPaidUser();

  const abortController = useMemo(
    () => new AbortController(),
    [activeModuleIndex, activeLessonIndex],
  );

  const generateAiCourseContent = async (
    isForce?: boolean,
    customPrompt?: string,
  ) => {
    setIsLoading(true);
    setError('');
    setLessonHtml('');

    if (!isLoggedIn()) {
      setIsLoading(false);
      setError('Please login to generate course content');
      return;
    }

    if (!currentModuleTitle || !currentLessonTitle) {
      setIsLoading(false);
      setError('Invalid module title or lesson title');
      return;
    }

    const response = await fetch(
      `${import.meta.env.PUBLIC_API_URL}/v1-generate-ai-course-lesson/${courseSlug}`,
      {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        signal: abortController.signal,
        credentials: 'include',
        body: JSON.stringify({
          moduleIndex: activeModuleIndex,
          lessonIndex: activeLessonIndex,
          isForce,
          customPrompt,
        }),
      },
    );

    if (!response.ok) {
      const data = await response.json();

      setError(data?.message || 'Something went wrong');
      setIsLoading(false);

      // Logout user if token is invalid
      if (data.status === 401) {
        removeAuthToken();
        window.location.reload();
      }
      return;
    }

    if (!response.body) {
      setIsLoading(false);
      setError('No response body received');
      return;
    }

    try {
      const reader = response.body.getReader();
      setIsLoading(false);
      setIsGenerating(true);
      await readStream(reader, {
        onStream: async (result) => {
          if (abortController.signal.aborted) {
            return;
          }

          setLessonHtml(markdownToHtml(result, false));
        },
        onStreamEnd: async (result) => {
          if (abortController.signal.aborted) {
            return;
          }

          setLessonHtml(await markdownToHtmlWithHighlighting(result));
          queryClient.invalidateQueries(getAiCourseLimitOptions());
          setIsGenerating(false);
        },
      });
    } catch (e) {
      setError(e instanceof Error ? e.message : 'Something went wrong');
      setIsLoading(false);
    }
  };

  const { mutate: toggleDone, isPending: isTogglingDone } = useMutation(
    {
      mutationFn: () => {
        return httpPatch<AICourseDocument>(
          `/v1-toggle-done-ai-lesson/${courseSlug}`,
          {
            moduleIndex: activeModuleIndex,
            lessonIndex: activeLessonIndex,
          },
        );
      },
      onSuccess: (data) => {
        queryClient.setQueryData(
          getAiCourseOptions({ aiCourseSlug: courseSlug }).queryKey,
          data,
        );
      },
    },
    queryClient,
  );

  useEffect(() => {
    generateAiCourseContent();
  }, [currentModuleTitle, currentLessonTitle]);

  useEffect(() => {
    return () => {
      abortController.abort();
    };
  }, [abortController]);

  const cantGoForward =
    (activeModuleIndex === totalModules - 1 &&
      activeLessonIndex === totalLessons - 1) ||
    isGenerating ||
    isLoading;

  const cantGoBack =
    (activeModuleIndex === 0 && activeLessonIndex === 0) ||
    isGenerating ||
    isLoading;

  return (
    <div className="grid h-full grid-cols-5">
      <div className="relative col-span-3">
        <div className="absolute inset-0 overflow-y-auto bg-white p-8 pb-0 max-lg:px-4 max-lg:pt-3">
          {(isGenerating || isLoading) && (
            <div className="absolute right-6 top-6 flex items-center justify-center">
              <Loader2Icon
                size={18}
                strokeWidth={3}
                className="animate-spin text-gray-400/70"
              />
            </div>
          )}

          <div className="mb-4 flex items-center justify-between">
            <div className="text-sm text-gray-500">
              Lesson {activeLessonIndex + 1} of {totalLessons}
            </div>

            {!isGenerating && !isLoading && (
              <div className="absolute right-6 top-6 flex items-center justify-between gap-2">
                <RegenerateLesson
                  onRegenerateLesson={(prompt) => {
                    generateAiCourseContent(true, prompt);
                  }}
                />
                <button
                  disabled={isLoading || isTogglingDone}
                  className={cn(
                    'flex items-center gap-1.5 rounded-full bg-black py-1 pl-2 pr-3 text-sm text-white hover:bg-gray-800 disabled:opacity-50 max-lg:text-xs',
                    isLessonDone
                      ? 'bg-red-500 hover:bg-red-600'
                      : 'bg-green-500 hover:bg-green-600',
                  )}
                  onClick={() => toggleDone()}
                >
                  {isTogglingDone ? (
                    <>
                      <Loader2Icon
                        size={16}
                        strokeWidth={3}
                        className="animate-spin text-white"
                      />
                      Please wait ...
                    </>
                  ) : (
                    <>
                      {isLessonDone ? (
                        <>
                          <XIcon size={16} />
                          Mark as Undone
                        </>
                      ) : (
                        <>
                          <CheckIcon size={16} />
                          Mark as Done
                        </>
                      )}
                    </>
                  )}
                </button>
              </div>
            )}
          </div>

          <h1 className="mb-6 text-balance text-3xl font-semibold max-lg:mb-3 max-lg:text-xl">
            {currentLessonTitle?.replace(/^Lesson\s*?\d+[\.:]\s*/, '')}
          </h1>

          {!error && isLoggedIn() && (
            <div
              className="course-content prose prose-lg mt-8 max-w-full text-black prose-headings:mb-3 prose-headings:mt-8 prose-blockquote:font-normal prose-pre:rounded-2xl prose-pre:text-lg prose-li:my-1 prose-thead:border-zinc-800 prose-tr:border-zinc-800 max-lg:mt-4 max-lg:text-base max-lg:prose-h2:mt-3 max-lg:prose-h2:text-lg max-lg:prose-h3:text-base max-lg:prose-pre:px-3 max-lg:prose-pre:text-sm"
              dangerouslySetInnerHTML={{ __html: lessonHtml }}
            />
          )}

          {error && isLoggedIn() && (
            <div className="mt-8 flex min-h-[300px] items-center justify-center rounded-xl bg-red-50/80">
              {error.includes('reached the limit') ? (
                <div className="flex max-w-sm flex-col items-center text-center">
                  <h2 className="text-xl font-semibold text-red-600">
                    Limit reached
                  </h2>
                  <p className="my-3 text-red-600">
                    You have reached the AI usage limit for today.
                    {!isPaidUser && (
                      <>Please upgrade your account to continue.</>
                    )}
                    {isPaidUser && (
                      <>&nbsp;Please wait until tomorrow to continue.</>
                    )}
                  </p>

                  {!isPaidUser && (
                    <button
                      onClick={() => {
                        onUpgrade();
                      }}
                      className="rounded-full bg-red-600 px-4 py-1 text-white hover:bg-red-700"
                    >
                      Upgrade Account
                    </button>
                  )}
                </div>
              ) : (
                <p className="text-red-600">{error}</p>
              )}
            </div>
          )}

          {!isLoggedIn() && (
            <div className="mt-8 flex min-h-[152px] flex-col items-center justify-center gap-3 rounded-lg border border-gray-200 p-8">
              <LockIcon className="size-7 stroke-[2] text-gray-400/90" />
              <p className="text-sm text-gray-500">
                Please login to generate course content
              </p>
            </div>
          )}

          {!isLoading && !isGenerating && !error && (
            <TestMyKnowledgeAction
              courseSlug={courseSlug}
              activeModuleIndex={activeModuleIndex}
              activeLessonIndex={activeLessonIndex}
            />
          )}

          <div className="mt-8 flex items-center justify-between">
            <button
              onClick={onGoToPrevLesson}
              disabled={cantGoBack}
              className={cn(
                'flex items-center rounded-full px-4 py-2 disabled:opacity-50 max-lg:px-3 max-lg:py-1.5 max-lg:text-sm',
                cantGoBack
                  ? 'cursor-not-allowed text-gray-400'
                  : 'bg-gray-100 text-gray-700 hover:bg-gray-200',
              )}
            >
              <ChevronLeft size={16} className="mr-2" />
              Previous <span className="hidden lg:inline">&nbsp;Lesson</span>
            </button>

            <div>
              <button
                onClick={() => {
                  if (!isLessonDone) {
                    toggleDone(undefined, {
                      onSuccess: () => {
                        onGoToNextLesson();
                      },
                    });
                  } else {
                    onGoToNextLesson();
                  }
                }}
                disabled={cantGoForward || isTogglingDone}
                className={cn(
                  'flex items-center rounded-full px-4 py-2 disabled:opacity-50 max-lg:px-3 max-lg:py-1.5 max-lg:text-sm',
                  cantGoForward
                    ? 'cursor-not-allowed text-gray-400'
                    : 'bg-gray-800 text-white hover:bg-gray-700',
                )}
              >
                {isTogglingDone ? (
                  <>
                    <Loader2Icon
                      size={16}
                      strokeWidth={3}
                      className="animate-spin text-white"
                    />
                    Please wait ...
                  </>
                ) : (
                  <>
                    Next <span className="hidden lg:inline">&nbsp;Lesson</span>
                    <ChevronRight size={16} className="ml-2" />
                  </>
                )}
              </button>
            </div>
          </div>

          <div className="mx-auto mb-10 mt-5 text-center text-sm text-gray-400">
            AI can make mistakes, check important info.
          </div>
        </div>
      </div>

      <AICourseLessonChat
        courseSlug={courseSlug}
        moduleTitle={currentModuleTitle}
        lessonTitle={currentLessonTitle}
        onUpgradeClick={onUpgrade}
        isDisabled={isGenerating || isLoading || isTogglingDone}
      />
    </div>
  );
}
