import "server-only";
import { and, asc, desc, eq, inArray } from "drizzle-orm";
import { db } from "@/lib/db/client";
import {
  courses,
  courseModules,
  lessons,
  enrollments,
  lessonProgress,
} from "@/lib/db/schema";

export type CourseSummary = {
  id: string;
  slug: string;
  title: string;
  level: "Foundation" | "Intermediate" | "Advanced";
  topic: string;
  shortDescription: string;
  coverPhoto: string | null;
  coverPhotoAlt: string | null;
  instructorName: string | null;
  lessonsCount: number;
  durationMin: number;
  enrolledCount: number;
};

export async function listPublishedCourses(): Promise<CourseSummary[]> {
  const rows = await db
    .select()
    .from(courses)
    .where(eq(courses.status, "published"))
    .orderBy(asc(courses.position), desc(courses.publishedAt));

  if (rows.length === 0) return [];

  const courseIds = rows.map((c) => c.id);
  const moduleRows = await db
    .select()
    .from(courseModules)
    .where(inArray(courseModules.courseId, courseIds));
  const moduleIds = moduleRows.map((m) => m.id);

  const lessonRows =
    moduleIds.length === 0
      ? []
      : await db.select().from(lessons).where(inArray(lessons.moduleId, moduleIds));

  const enrolmentRows = await db
    .select()
    .from(enrollments)
    .where(inArray(enrollments.courseId, courseIds));

  return rows.map((c) => {
    const cMods = moduleRows.filter((m) => m.courseId === c.id);
    const cModIds = cMods.map((m) => m.id);
    const cLessons = lessonRows.filter((l) => cModIds.includes(l.moduleId));
    const totalDuration = cLessons.reduce((sum, l) => sum + l.durationMin, 0);
    return {
      id: c.id,
      slug: c.slug,
      title: c.title,
      level: c.level,
      topic: c.topic,
      shortDescription: c.shortDescription,
      coverPhoto: c.coverPhoto,
      coverPhotoAlt: c.coverPhotoAlt,
      instructorName: c.instructorName,
      lessonsCount: cLessons.length,
      durationMin: totalDuration,
      enrolledCount: enrolmentRows.filter((e) => e.courseId === c.id).length,
    };
  });
}

export type CourseDetail = {
  course: typeof courses.$inferSelect;
  modules: {
    id: string;
    title: string;
    position: number;
    lessons: {
      id: string;
      slug: string;
      title: string;
      type: "video" | "reading" | "quiz";
      durationMin: number;
      position: number;
    }[];
  }[];
  enrolledCount: number;
  totalLessons: number;
  totalDurationMin: number;
};

export async function getPublishedCourseBySlug(
  slug: string,
): Promise<CourseDetail | null> {
  const [course] = await db
    .select()
    .from(courses)
    .where(and(eq(courses.slug, slug), eq(courses.status, "published")))
    .limit(1);
  if (!course) return null;

  const moduleRows = await db
    .select()
    .from(courseModules)
    .where(eq(courseModules.courseId, course.id))
    .orderBy(asc(courseModules.position));

  const moduleIds = moduleRows.map((m) => m.id);
  const lessonRows =
    moduleIds.length === 0
      ? []
      : await db
          .select()
          .from(lessons)
          .where(inArray(lessons.moduleId, moduleIds))
          .orderBy(asc(lessons.position));

  const enrolmentCount = await db
    .select()
    .from(enrollments)
    .where(eq(enrollments.courseId, course.id));

  return {
    course,
    modules: moduleRows.map((m) => ({
      id: m.id,
      title: m.title,
      position: m.position,
      lessons: lessonRows
        .filter((l) => l.moduleId === m.id)
        .map((l) => ({
          id: l.id,
          slug: l.slug,
          title: l.title,
          type: l.type,
          durationMin: l.durationMin,
          position: l.position,
        })),
    })),
    enrolledCount: enrolmentCount.length,
    totalLessons: lessonRows.length,
    totalDurationMin: lessonRows.reduce((s, l) => s + l.durationMin, 0),
  };
}

// Admin-side full detail loader (including unpublished courses).
export async function getCourseForAdmin(courseId: string) {
  const [course] = await db
    .select()
    .from(courses)
    .where(eq(courses.id, courseId))
    .limit(1);
  if (!course) return null;

  const moduleRows = await db
    .select()
    .from(courseModules)
    .where(eq(courseModules.courseId, courseId))
    .orderBy(asc(courseModules.position));

  const moduleIds = moduleRows.map((m) => m.id);
  const lessonRows =
    moduleIds.length === 0
      ? []
      : await db
          .select()
          .from(lessons)
          .where(inArray(lessons.moduleId, moduleIds))
          .orderBy(asc(lessons.position));

  const enrolmentRows = await db
    .select()
    .from(enrollments)
    .where(eq(enrollments.courseId, courseId));

  return {
    course,
    modules: moduleRows.map((m) => ({
      ...m,
      lessons: lessonRows.filter((l) => l.moduleId === m.id),
    })),
    enrolmentCount: enrolmentRows.length,
  };
}

export async function listCoursesForAdmin() {
  return db.select().from(courses).orderBy(desc(courses.createdAt));
}

export async function getCourseForPlayer(courseId: string, userId: string) {
  const [course] = await db
    .select()
    .from(courses)
    .where(eq(courses.id, courseId))
    .limit(1);
  if (!course) return null;
  if (course.status !== "published") return null;

  const [enrolled] = await db
    .select()
    .from(enrollments)
    .where(
      and(eq(enrollments.courseId, courseId), eq(enrollments.userId, userId)),
    )
    .limit(1);
  if (!enrolled) return null;

  const moduleRows = await db
    .select()
    .from(courseModules)
    .where(eq(courseModules.courseId, courseId))
    .orderBy(asc(courseModules.position));

  const moduleIds = moduleRows.map((m) => m.id);
  const lessonRows =
    moduleIds.length === 0
      ? []
      : await db
          .select()
          .from(lessons)
          .where(inArray(lessons.moduleId, moduleIds))
          .orderBy(asc(lessons.position));

  const progressRows = await db
    .select()
    .from(lessonProgress)
    .where(eq(lessonProgress.userId, userId));

  return {
    course,
    modules: moduleRows.map((m) => ({
      ...m,
      lessons: lessonRows.filter((l) => l.moduleId === m.id),
    })),
    lessons: lessonRows,
    completedLessonIds: new Set(progressRows.map((p) => p.lessonId)),
  };
}
