"use server";


import { revalidatePath } from "next/cache";
import { redirect } from "next/navigation";
import { and, eq } from "drizzle-orm";
import { z } from "zod";
import { db } from "@/lib/db/client";
import { courses, courseModules, lessons, courseResources } from "@/lib/db/schema";
import { requireAdmin } from "@/lib/auth/admin-guard";
import { logAdminAction } from "@/lib/audit";

// -------------------------------------------------------------------------
// Helpers
// -------------------------------------------------------------------------

function slugify(input: string): string {
  return input
    .toLowerCase()
    .trim()
    .replace(/[^a-z0-9\s-]/g, "")
    .replace(/\s+/g, "-")
    .replace(/-+/g, "-")
    .slice(0, 80);
}

async function ensureAdmin() {
  const session = await requireAdmin();
  const adminId = (session.user as { id?: string }).id!;
  return adminId;
}

function multiline(input: string | null | undefined): string[] {
  if (!input) return [];
  return input
    .split("\n")
    .map((line) => line.trim())
    .filter((line) => line.length > 0);
}

// -------------------------------------------------------------------------
// Courses
// -------------------------------------------------------------------------

const courseLevelValues = ["Foundation", "Intermediate", "Advanced"] as const;
const courseStatusValues = ["draft", "published", "archived"] as const;

const createCourseSchema = z.object({
  title: z.string().min(3).max(200),
  level: z.enum(courseLevelValues),
  topic: z.string().min(1).max(120),
  shortDescription: z.string().max(400).optional(),
});

export async function createCourse(formData: FormData) {
  const adminId = await ensureAdmin();

  const parsed = createCourseSchema.parse({
    title: formData.get("title"),
    level: formData.get("level") ?? "Foundation",
    topic: (formData.get("topic") || "General") as string,
    shortDescription: formData.get("shortDescription") ?? "",
  });

  // Ensure slug uniqueness by suffixing a short random tail if collision.
  const baseSlug = slugify(parsed.title);
  let slug = baseSlug || "course";
  const [existing] = await db
    .select({ id: courses.id })
    .from(courses)
    .where(eq(courses.slug, slug))
    .limit(1);
  if (existing) {
    slug = `${slug}-${Math.random().toString(36).slice(2, 7)}`;
  }

  const [row] = await db
    .insert(courses)
    .values({
      slug,
      title: parsed.title,
      level: parsed.level,
      topic: parsed.topic,
      shortDescription: parsed.shortDescription ?? "",
    })
    .returning({ id: courses.id });

  await logAdminAction({
    adminUserId: adminId,
    action: "create_course",
    targetId: row.id,
    metadata: { slug },
  });

  revalidatePath("/admin/academy");
  redirect(`/admin/academy/${row.id}`);
}

const updateCourseSchema = z.object({
  id: z.string().uuid(),
  title: z.string().min(3).max(200),
  level: z.enum(courseLevelValues),
  topic: z.string().min(1).max(120),
  shortDescription: z.string().max(400),
  description: z.string().max(5000),
  outcomes: z.string().max(2000),
  prerequisites: z.string().max(2000),
  instructorName: z.string().max(200),
  instructorTitle: z.string().max(200),
  instructorBio: z.string().max(2000),
  coverPhoto: z.string().max(400),
  coverPhotoAlt: z.string().max(400),
});

export async function updateCourse(formData: FormData) {
  const adminId = await ensureAdmin();

  const parsed = updateCourseSchema.parse({
    id: formData.get("id"),
    title: formData.get("title") ?? "",
    level: formData.get("level") ?? "Foundation",
    topic: formData.get("topic") ?? "General",
    shortDescription: formData.get("shortDescription") ?? "",
    description: formData.get("description") ?? "",
    outcomes: formData.get("outcomes") ?? "",
    prerequisites: formData.get("prerequisites") ?? "",
    instructorName: formData.get("instructorName") ?? "",
    instructorTitle: formData.get("instructorTitle") ?? "",
    instructorBio: formData.get("instructorBio") ?? "",
    coverPhoto: formData.get("coverPhoto") ?? "",
    coverPhotoAlt: formData.get("coverPhotoAlt") ?? "",
  });

  await db
    .update(courses)
    .set({
      title: parsed.title,
      level: parsed.level,
      topic: parsed.topic,
      shortDescription: parsed.shortDescription,
      description: parsed.description,
      outcomes: multiline(parsed.outcomes),
      prerequisites: multiline(parsed.prerequisites),
      instructorName: parsed.instructorName || null,
      instructorTitle: parsed.instructorTitle || null,
      instructorBio: parsed.instructorBio || null,
      coverPhoto: parsed.coverPhoto || null,
      coverPhotoAlt: parsed.coverPhotoAlt || null,
      updatedAt: new Date(),
    })
    .where(eq(courses.id, parsed.id));

  await logAdminAction({
    adminUserId: adminId,
    action: "update_course",
    targetId: parsed.id,
  });

  revalidatePath("/admin/academy");
  revalidatePath(`/admin/academy/${parsed.id}`);
  revalidatePath("/products/academy/courses");
}

const setCourseStatusSchema = z.object({
  id: z.string().uuid(),
  status: z.enum(courseStatusValues),
});

export async function setCourseStatus(formData: FormData) {
  const adminId = await ensureAdmin();
  const parsed = setCourseStatusSchema.parse({
    id: formData.get("id"),
    status: formData.get("status"),
  });

  await db
    .update(courses)
    .set({
      status: parsed.status,
      publishedAt: parsed.status === "published" ? new Date() : null,
      updatedAt: new Date(),
    })
    .where(eq(courses.id, parsed.id));

  await logAdminAction({
    adminUserId: adminId,
    action: `course_${parsed.status}`,
    targetId: parsed.id,
  });

  revalidatePath("/admin/academy");
  revalidatePath(`/admin/academy/${parsed.id}`);
  revalidatePath("/products/academy/courses");
  revalidatePath(`/products/academy/courses/${parsed.id}`);
}

export async function deleteCourse(formData: FormData) {
  const adminId = await ensureAdmin();
  const id = z.string().uuid().parse(formData.get("id"));

  await db.delete(courses).where(eq(courses.id, id));

  await logAdminAction({
    adminUserId: adminId,
    action: "delete_course",
    targetId: id,
  });

  revalidatePath("/admin/academy");
  redirect("/admin/academy");
}

// -------------------------------------------------------------------------
// Modules
// -------------------------------------------------------------------------

const createModuleSchema = z.object({
  courseId: z.string().uuid(),
  title: z.string().min(1).max(200),
});

export async function createModule(formData: FormData) {
  const adminId = await ensureAdmin();
  const parsed = createModuleSchema.parse({
    courseId: formData.get("courseId"),
    title: formData.get("title"),
  });

  const existing = await db
    .select({ id: courseModules.id })
    .from(courseModules)
    .where(eq(courseModules.courseId, parsed.courseId));

  await db.insert(courseModules).values({
    courseId: parsed.courseId,
    title: parsed.title,
    position: existing.length,
  });

  await logAdminAction({
    adminUserId: adminId,
    action: "create_module",
    targetId: parsed.courseId,
  });

  revalidatePath(`/admin/academy/${parsed.courseId}`);
}

const renameModuleSchema = z.object({
  id: z.string().uuid(),
  courseId: z.string().uuid(),
  title: z.string().min(1).max(200),
});

export async function renameModule(formData: FormData) {
  const adminId = await ensureAdmin();
  const parsed = renameModuleSchema.parse({
    id: formData.get("id"),
    courseId: formData.get("courseId"),
    title: formData.get("title"),
  });

  await db
    .update(courseModules)
    .set({ title: parsed.title, updatedAt: new Date() })
    .where(eq(courseModules.id, parsed.id));

  await logAdminAction({
    adminUserId: adminId,
    action: "rename_module",
    targetId: parsed.id,
  });

  revalidatePath(`/admin/academy/${parsed.courseId}`);
}

export async function deleteModule(formData: FormData) {
  const adminId = await ensureAdmin();
  const id = z.string().uuid().parse(formData.get("id"));
  const courseId = z.string().uuid().parse(formData.get("courseId"));

  await db.delete(courseModules).where(eq(courseModules.id, id));

  await logAdminAction({
    adminUserId: adminId,
    action: "delete_module",
    targetId: id,
  });

  revalidatePath(`/admin/academy/${courseId}`);
}

// -------------------------------------------------------------------------
// Lessons
// -------------------------------------------------------------------------

const lessonTypeValues = ["video", "reading", "quiz"] as const;

const createLessonSchema = z.object({
  moduleId: z.string().uuid(),
  courseId: z.string().uuid(),
  title: z.string().min(1).max(200),
  type: z.enum(lessonTypeValues),
  durationMin: z.coerce.number().int().min(0).max(600),
});

export async function createLesson(formData: FormData) {
  const adminId = await ensureAdmin();
  const parsed = createLessonSchema.parse({
    moduleId: formData.get("moduleId"),
    courseId: formData.get("courseId"),
    title: formData.get("title"),
    type: formData.get("type") ?? "reading",
    durationMin: formData.get("durationMin") ?? 0,
  });

  const baseSlug = slugify(parsed.title) || "lesson";
  let slug = baseSlug;
  const [existing] = await db
    .select({ id: lessons.id })
    .from(lessons)
    .where(and(eq(lessons.moduleId, parsed.moduleId), eq(lessons.slug, slug)))
    .limit(1);
  if (existing) slug = `${slug}-${Math.random().toString(36).slice(2, 6)}`;

  const siblings = await db
    .select({ id: lessons.id })
    .from(lessons)
    .where(eq(lessons.moduleId, parsed.moduleId));

  await db.insert(lessons).values({
    moduleId: parsed.moduleId,
    slug,
    title: parsed.title,
    type: parsed.type,
    durationMin: parsed.durationMin,
    position: siblings.length,
  });

  await logAdminAction({
    adminUserId: adminId,
    action: "create_lesson",
    targetId: parsed.moduleId,
  });

  revalidatePath(`/admin/academy/${parsed.courseId}`);
}

const videoProviderValues = ["youtube", "vimeo", "mp4", "none"] as const;

const updateLessonSchema = z.object({
  id: z.string().uuid(),
  courseId: z.string().uuid(),
  title: z.string().min(1).max(200),
  type: z.enum(lessonTypeValues),
  durationMin: z.coerce.number().int().min(0).max(600),
  content: z.string().max(20000),
  transcript: z.string().max(20000),
  keyPoints: z.string().max(4000),
  videoProvider: z.enum(videoProviderValues).default("none"),
  videoUrl: z.string().max(600).optional(),
  videoPoster: z.string().max(600).optional(),
});

export async function updateLesson(formData: FormData) {
  const adminId = await ensureAdmin();
  const parsed = updateLessonSchema.parse({
    id: formData.get("id"),
    courseId: formData.get("courseId"),
    title: formData.get("title") ?? "",
    type: formData.get("type") ?? "reading",
    durationMin: formData.get("durationMin") ?? 0,
    content: formData.get("content") ?? "",
    transcript: formData.get("transcript") ?? "",
    keyPoints: formData.get("keyPoints") ?? "",
    videoProvider: (formData.get("videoProvider") as string) || "none",
    videoUrl: (formData.get("videoUrl") as string) ?? "",
    videoPoster: (formData.get("videoPoster") as string) ?? "",
  });

  const hasVideo = parsed.videoProvider !== "none" && (parsed.videoUrl ?? "").length > 0;

  await db
    .update(lessons)
    .set({
      title: parsed.title,
      type: parsed.type,
      durationMin: parsed.durationMin,
      content: parsed.content,
      transcript: parsed.transcript || null,
      keyPoints: multiline(parsed.keyPoints),
      videoProvider: hasVideo ? parsed.videoProvider : "none",
      videoUrl: hasVideo ? parsed.videoUrl! : null,
      videoPoster: parsed.videoPoster ? parsed.videoPoster : null,
      updatedAt: new Date(),
    })
    .where(eq(lessons.id, parsed.id));

  await logAdminAction({
    adminUserId: adminId,
    action: "update_lesson",
    targetId: parsed.id,
  });

  revalidatePath(`/admin/academy/${parsed.courseId}`);
}

export async function deleteLesson(formData: FormData) {
  const adminId = await ensureAdmin();
  const id = z.string().uuid().parse(formData.get("id"));
  const courseId = z.string().uuid().parse(formData.get("courseId"));

  await db.delete(lessons).where(eq(lessons.id, id));

  await logAdminAction({
    adminUserId: adminId,
    action: "delete_lesson",
    targetId: id,
  });

  revalidatePath(`/admin/academy/${courseId}`);
}

// -------------------------------------------------------------------------
// Course resources (course-level attachments / links)
// -------------------------------------------------------------------------

const resourceTypeValues = [
  "pdf",
  "poster",
  "slide_deck",
  "article",
  "link",
  "image",
  "video",
  "other",
] as const;

const saveResourcesSchema = z.object({
  courseId: z.string().uuid(),
  resources: z.string().max(50_000).optional(),
});

const resourceItemSchema = z.array(
  z.object({
    type: z.enum(resourceTypeValues).default("link"),
    title: z.string().trim().max(300).default(""),
    description: z.string().trim().max(1000).default(""),
    url: z.string().trim().max(600).default(""),
  }),
);

export async function saveCourseResources(formData: FormData) {
  const adminId = await ensureAdmin();
  const parsed = saveResourcesSchema.parse({
    courseId: formData.get("courseId"),
    resources: (formData.get("resources") as string) ?? "",
  });

  let items: Array<{ type: string; title: string; description: string; url: string }> = [];
  if (parsed.resources && parsed.resources.length > 0) {
    try {
      const raw = JSON.parse(parsed.resources);
      const result = resourceItemSchema.safeParse(raw);
      if (result.success) items = result.data;
    } catch {
      items = [];
    }
  }

  await db.delete(courseResources).where(eq(courseResources.courseId, parsed.courseId));

  const kept = items
    .filter((i) => i.title.trim().length > 0 && i.url.trim().length > 0)
    .map((item, position) => ({
      courseId: parsed.courseId,
      type: item.type as (typeof resourceTypeValues)[number],
      title: item.title,
      description: item.description,
      url: item.url,
      position,
    }));

  if (kept.length > 0) {
    await db.insert(courseResources).values(kept);
  }

  await logAdminAction({
    adminUserId: adminId,
    action: "save_course_resources",
    targetId: parsed.courseId,
    metadata: { count: kept.length },
  });

  revalidatePath(`/admin/academy/${parsed.courseId}`);
  revalidatePath("/products/academy/courses");
}

