"use client";

import { VideoModal } from "@/components/video-player";
import { useFocusRevalidate } from "@/hooks/use-focus-revalidate";
import {
  courseViewReducer,
  createInitialCourseViewState,
} from "@/features/course-view/course-view-reducer";
import type { CourseEditorEvent } from "@/services/course-editor-service";
import { makeLoader } from "@/services/route-action.server";
import { courseViewEffect } from "@/features/course-view/course-view-loader.server";
import { VideoOperationsService } from "@/services/db-video-operations.server";
import { NotFoundError } from "@/services/db-service-errors";
import {
  PointerSensor,
  KeyboardSensor,
  useSensor,
  useSensors,
} from "@dnd-kit/core";
import { sortableKeyboardCoordinates } from "@dnd-kit/sortable";
import { Effect } from "effect";
import { ChevronLeft } from "lucide-react";
import { useCallback, useContext, useEffect, useMemo, useRef } from "react";
import {
  Link,
  useFetcher,
  useLocation,
  useNavigate,
  useSearchParams,
  useSubmit,
} from "react-router";
import { useEffectReducer } from "use-effect-reducer";
import type { Route } from "./+types/_app.courses.$courseId.sections.$sectionId";
import { UploadContext } from "@/features/upload-manager/upload-context";
import { GenerateChaptersProvider } from "@/features/course-view/generate-chapters-context";
import { SectionGrid } from "@/features/course-view/section-grid";
import {
  ReadOnlyBanner,
  RouteModals,
} from "@/features/course-view/course-view-components";
import { createSectionDragHandler } from "@/features/course-view/course-editor-helpers";
import {
  courseEditorFetcherKeyForEvent,
  deleteVideoFetcherKey,
} from "@/features/course-view/optimistic-applier";
import {
  useOptimisticCourse,
  useCourseEditorFailureToast,
} from "@/features/course-view/use-optimistic-course";
import { DivergenceReportModal } from "@/features/course-view/divergence-report-modal";
import { BeatDescriptionsProvider } from "@/features/beats/beat-descriptions-context";
import { SectionScriptsView } from "@/features/course-view/section-scripts-view";
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs";

export const meta: Route.MetaFunction = ({ data }) => {
  const section = data?.selectedCourse?.sections[0];
  const courseName = data?.selectedCourse?.name;
  if (section && courseName) {
    return [{ title: `CVM - ${courseName} - ${section.path}` }];
  }
  return [{ title: "CVM" }];
};

export const loader = async (args: Route.LoaderArgs) => {
  const url = new URL(args.request.url);
  const selectedVersionId = url.searchParams.get("versionId");

  return makeLoader({
    effect: ({ params }) =>
      courseViewEffect({
        courseId: params.courseId!,
        selectedVersionId,
        viewMode: "compact",
      }).pipe(
        Effect.flatMap((result) =>
          Effect.gen(function* () {
            const sectionId = params.sectionId!;
            const section = result.selectedCourse?.sections.find(
              (s) => s.id === sectionId
            );
            if (!result.selectedCourse || !section) {
              return yield* Effect.fail(
                new NotFoundError({ type: "section", params: { sectionId } })
              );
            }

            // Re-attach the full script text the course-view loader slims away
            // (see `toSlimVideo`), scoped to just this one section, so the
            // Scripts tab can seed every field from the loader without a
            // per-field fetch. Writes still go per-video via the script route.
            const videoIds = section.lessons.flatMap((lesson) =>
              lesson.videos.map((video) => video.id)
            );
            const videoOps = yield* VideoOperationsService;
            const scripts = yield* videoOps.getVideoScriptsByIds(videoIds);
            const sectionWithScripts = {
              ...section,
              lessons: section.lessons.map((lesson) => ({
                ...lesson,
                videos: lesson.videos.map((video) => ({
                  ...video,
                  script: scripts[video.id] ?? null,
                })),
              })),
            };

            return {
              ...result,
              selectedCourse: {
                ...result.selectedCourse,
                sections: [sectionWithScripts],
              },
            };
          })
        )
      ),
  })(args);
};

const NO_COLLAPSED_SECTIONS = new Set<string>();
const noopToggleSection = () => {};

export default function Component(props: Route.ComponentProps) {
  const navigate = useNavigate();
  const location = useLocation();
  const courseId = props.params.courseId;
  const loaderData = props.loaderData;

  const [viewState, dispatch] = useEffectReducer(
    courseViewReducer,
    createInitialCourseViewState(),
    {}
  );

  // Which tab is showing lives in the URL (`?view=scripts`) so it is
  // bookmarkable, shareable, and survives refresh and focus-revalidation.
  // Default (absent param) = videos.
  const [searchParams, setSearchParams] = useSearchParams();
  const activeTab = searchParams.get("view") === "scripts" ? "scripts" : "videos";

  const submit = useSubmit();

  const submitEvent = useCallback(
    (event: CourseEditorEvent) => {
      submit(event, {
        method: "post",
        encType: "application/json",
        action: "/api/course-editor",
        navigate: false,
        fetcherKey: courseEditorFetcherKeyForEvent(event),
      });
    },
    [submit]
  );

  const optimisticData = useOptimisticCourse(loaderData);
  const { divergenceReport, clearDivergenceReport } =
    useCourseEditorFailureToast();

  const currentCourse = optimisticData.selectedCourse;
  const section = currentCourse?.sections[0];

  const {
    addLessonSectionId,
    insertAdjacentLessonId,
    insertPosition,
    addVideoToLessonId,
    editSectionId,
    deleteLessonId,
    editDescriptionLessonId,
    archiveSectionId,
    lessonSelection,
    videoPlayerState,
    priorityFilter,
    iconFilter,
    todoFilter,
    searchQuery,
  } = viewState;

  const { startExportUpload } = useContext(UploadContext);

  useFocusRevalidate({ enabled: true, intervalMs: 5000 });

  const submitDeleteVideo = useCallback(
    (videoId: string) => {
      submit(
        { videoId },
        {
          method: "post",
          action: "/api/videos/delete",
          navigate: false,
          fetcherKey: deleteVideoFetcherKey(videoId),
        }
      );
    },
    [submit]
  );

  const deleteVideoFileFetcher = useFetcher();
  const revealVideoFetcher = useFetcher();

  const sensors = useSensors(
    useSensor(PointerSensor, { activationConstraint: { distance: 8 } }),
    useSensor(KeyboardSensor, {
      coordinateGetter: sortableKeyboardCoordinates,
    })
  );

  const handleSectionDragEnd = useMemo(
    () => createSectionDragHandler(submitEvent),
    [submitEvent]
  );

  const displaySections = currentCourse?.sections ?? [];
  const hash = location.hash;
  const scrolledHashRef = useRef<string | null>(null);
  useEffect(() => {
    if (!hash || displaySections.length === 0) return;
    if (scrolledHashRef.current === hash) return;
    const el = document.getElementById(decodeURIComponent(hash.slice(1)));
    if (el) {
      el.scrollIntoView({ block: "center" });
      scrolledHashRef.current = hash;
    }
  }, [hash, displaySections.length]);

  const lessonSelectionRef = useRef(lessonSelection);
  lessonSelectionRef.current = lessonSelection;
  useEffect(() => {
    const sel = lessonSelectionRef.current;
    if (!sel) return;
    const sec = displaySections.find((s) => s.id === sel.sectionId);
    const currentLessonIds = sec?.lessons.map((l) => l.id) ?? [];
    dispatch({ type: "prune-lesson-selection", currentLessonIds });
  }, [displaySections, dispatch]);

  return (
    <GenerateChaptersProvider>
      <div className="flex-1 flex flex-col bg-background text-foreground">
        <div className="flex-1 overflow-y-auto">
          <div className="p-6">
            {currentCourse && section ? (
              <>
                <Link
                  to={`/courses/${currentCourse.id}`}
                  className="inline-flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground transition-colors mb-2"
                >
                  <ChevronLeft className="w-4 h-4" />
                  {currentCourse.name}
                </Link>

                <h1 className="text-2xl font-bold mb-4">{section.path}</h1>

                {loaderData.selectedVersion && !loaderData.isLatestVersion && (
                  <div className="mb-4">
                    <ReadOnlyBanner />
                  </div>
                )}

                <Tabs
                  value={activeTab}
                  onValueChange={(value) =>
                    setSearchParams(
                      (prev) => {
                        if (value === "scripts") prev.set("view", "scripts");
                        else prev.delete("view");
                        return prev;
                      },
                      { replace: true, preventScrollReset: true }
                    )
                  }
                >
                  <TabsList className="mb-4">
                    <TabsTrigger value="videos">Videos</TabsTrigger>
                    <TabsTrigger value="scripts">Scripts</TabsTrigger>
                  </TabsList>

                  <TabsContent value="videos">
                    <BeatDescriptionsProvider show>
                      <SectionGrid
                        currentCourse={currentCourse}
                        data={loaderData}
                        viewMode="compact"
                        singleColumn
                        sensors={sensors}
                        handleSectionDragEnd={handleSectionDragEnd}
                        priorityFilter={priorityFilter}
                        iconFilter={iconFilter}
                        todoFilter={todoFilter}
                        searchQuery={searchQuery}
                        addLessonSectionId={addLessonSectionId}
                        insertAdjacentLessonId={insertAdjacentLessonId}
                        insertPosition={insertPosition}
                        editSectionId={editSectionId}
                        addVideoToLessonId={addVideoToLessonId}
                        deleteLessonId={deleteLessonId}
                        editDescriptionLessonId={editDescriptionLessonId}
                        archiveSectionId={archiveSectionId}
                        collapsedSections={NO_COLLAPSED_SECTIONS}
                        toggleSection={noopToggleSection}
                        lessonSelection={lessonSelection}
                        dispatch={dispatch}
                        submitEvent={submitEvent}
                        navigate={navigate}
                        startExportUpload={startExportUpload}
                        revealVideoFetcher={revealVideoFetcher}
                        deleteVideoFileFetcher={deleteVideoFileFetcher}
                        submitDeleteVideo={submitDeleteVideo}
                      />
                    </BeatDescriptionsProvider>
                  </TabsContent>

                  <TabsContent value="scripts">
                    <SectionScriptsView
                      section={section}
                      readOnly={Boolean(
                        loaderData.selectedVersion &&
                        !loaderData.isLatestVersion
                      )}
                    />
                  </TabsContent>
                </Tabs>
              </>
            ) : (
              <div className="text-center py-12">
                <h1 className="text-xl font-semibold mb-2">
                  Section not found
                </h1>
                <p className="text-muted-foreground">
                  This section may have been archived or deleted.
                </p>
                {courseId && (
                  <Link
                    to={`/courses/${courseId}`}
                    className="text-primary hover:underline mt-2 inline-block"
                  >
                    Back to course
                  </Link>
                )}
              </div>
            )}
          </div>
        </div>

        <VideoModal
          videoId={videoPlayerState.videoId}
          videoTitle={videoPlayerState.videoTitle}
          isOpen={videoPlayerState.isOpen}
          onClose={() => dispatch({ type: "close-video-player" })}
        />

        <RouteModals
          currentCourse={currentCourse}
          data={loaderData}
          selectedCourseId={courseId}
          viewState={viewState}
          dispatch={dispatch}
          navigate={navigate}
        />

        <DivergenceReportModal
          report={divergenceReport}
          onClose={clearDivergenceReport}
        />
      </div>
    </GenerateChaptersProvider>
  );
}
