import "server-only";

import { and, eq } from "drizzle-orm";
import { createId } from "@paralleldrive/cuid2";

import { db } from "@/shared/db";
import { lessonPlanTemplates, lessonPlans } from "@/shared/db/schema";
import { SYSTEM_TEMPLATES } from "./constants";
import { normalizeDocument, LessonPlanDataError } from "./data-access";
import type {
  LessonPlanTemplate,
  TemplateBlockSkeleton,
  TemplateType,
  TemplateScope,
} from "./types";

// ---- 类型守卫：安全地将 DB string 收窄为联合类型 ----
const TEMPLATE_TYPES = ["system", "personal"] as const;
function isTemplateType(v: string): v is TemplateType {
  return (TEMPLATE_TYPES as readonly string[]).includes(v);
}
const TEMPLATE_SCOPES = ["regular", "review", "experiment", "inquiry", "blank", "custom"] as const;
function isTemplateScope(v: string): v is TemplateScope {
  return (TEMPLATE_SCOPES as readonly string[]).includes(v);
}

// ---- 类型映射：Drizzle 行 → LessonPlanTemplate（Date → ISO string）----
function mapRowToTemplate(row: {
  id: string;
  name: string;
  type: string;
  scope: string;
  blocks: unknown;
  creatorId: string | null;
  createdAt: Date;
  updatedAt: Date;
}): LessonPlanTemplate {
  return {
    id: row.id,
    name: row.name,
    type: isTemplateType(row.type) ? row.type : "personal",
    scope: isTemplateScope(row.scope) ? row.scope : "custom",
    // 从 unknown 转换为 TemplateBlockSkeleton[]（DB JSON 字段）
    blocks: row.blocks as LessonPlanTemplate["blocks"],
    creatorId: row.creatorId,
    createdAt: row.createdAt.toISOString(),
    updatedAt: row.updatedAt.toISOString(),
  };
}

export async function getLessonPlanTemplates(
  userId: string,
): Promise<LessonPlanTemplate[]> {
  // system 模板（内存）+ personal 模板（DB）
  const systemTemplates: LessonPlanTemplate[] = SYSTEM_TEMPLATES.map((t) => ({
    id: t.id,
    name: t.name,
    type: "system",
    scope: t.scope,
    blocks: t.blocks,
    creatorId: null,
    createdAt: "",
    updatedAt: "",
  }));

  const personalRows = await db
    .select()
    .from(lessonPlanTemplates)
    .where(
      and(
        eq(lessonPlanTemplates.type, "personal"),
        eq(lessonPlanTemplates.creatorId, userId),
      ),
    );
  const personalTemplates = personalRows.map(mapRowToTemplate);

  return [...systemTemplates, ...personalTemplates];
}

export async function saveAsTemplate(input: {
  sourcePlanId: string;
  name: string;
  userId: string;
}): Promise<{ templateId: string }> {
  // 从课案 content 提取 block 骨架
  const plan = await db
    .select({ content: lessonPlans.content })
    .from(lessonPlans)
    .where(
      and(
        eq(lessonPlans.id, input.sourcePlanId),
        eq(lessonPlans.creatorId, input.userId),
      ),
    )
    .limit(1);
  if (plan.length === 0) throw new LessonPlanDataError("NOT_FOUND");

  const doc = normalizeDocument(plan[0].content);
  const skeleton: TemplateBlockSkeleton[] = doc.nodes.map((b) => ({
    type: b.type,
    title: b.title,
  }));

  const templateId = createId();
  await db.insert(lessonPlanTemplates).values({
    id: templateId,
    name: input.name,
    type: "personal",
    scope: "custom",
    blocks: skeleton,
    creatorId: input.userId,
  });
  return { templateId };
}

export async function deletePersonalTemplate(
  templateId: string,
  userId: string,
): Promise<void> {
  await db.delete(lessonPlanTemplates).where(
    and(
      eq(lessonPlanTemplates.id, templateId),
      eq(lessonPlanTemplates.type, "personal"),
      eq(lessonPlanTemplates.creatorId, userId),
    ),
  );
}
