// 备课模块集中类型守卫：替代 `as` 断言，安全收窄 unknown 联合类型
import type {
  BlackboardBlockData,
  BlockData,
  BlockType,
  ExerciseBlockData,
  ExercisePurpose,
  HomeworkAssignment,
  HomeworkBlockData,
  ImportBlockData,
  KeyPointBlockData,
  KeyPointItem,
  LessonPlanNode,
  LessonPlanStatus,
  NewTeachingBlockData,
  ObjectiveBlockData,
  ObjectiveItem,
  ReflectionBlockData,
  ReflectionItem,
  RichTextBlockData,
  SummaryBlockData,
  TemplateBlockSkeleton,
  TemplateScope,
  TemplateType,
  TextStudyBlockData,
  TextbookContentNode,
} from "../types";

// ---- 基础类型守卫 ----
// M3 审核工作流：扩展为 6 种状态
const LESSON_PLAN_STATUSES = ["draft", "submitted", "approved", "published", "rejected", "archived"] as const;
export function isLessonPlanStatus(v: string): v is LessonPlanStatus {
  return (LESSON_PLAN_STATUSES as readonly string[]).includes(v);
}

/** M3 审核工作流：审核决策类型守卫 */
const REVIEW_DECISIONS = ["approved", "rejected"] as const;
export type ReviewDecision = (typeof REVIEW_DECISIONS)[number];
export function isReviewDecision(v: string): v is ReviewDecision {
  return (REVIEW_DECISIONS as readonly string[]).includes(v);
}

/** M3 审核工作流：代课教师状态类型守卫 */
const SUBSTITUTE_STATUSES = ["active", "expired", "cancelled"] as const;
export type SubstituteStatus = (typeof SUBSTITUTE_STATUSES)[number];
export function isSubstituteStatus(v: string): v is SubstituteStatus {
  return (SUBSTITUTE_STATUSES as readonly string[]).includes(v);
}

/** M3 审核工作流：附件类型守卫 */
const ATTACHMENT_TYPES = ["reference", "material", "supplementary"] as const;
export type AttachmentType = (typeof ATTACHMENT_TYPES)[number];
export function isAttachmentType(v: string): v is AttachmentType {
  return (ATTACHMENT_TYPES as readonly string[]).includes(v);
}

/** M3 审核工作流：形成性评价互动类型守卫 */
const FORMATIVE_INTERACTION_TYPES = ["poll", "quiz", "exit_ticket"] as const;
export type FormativeInteractionType = (typeof FORMATIVE_INTERACTION_TYPES)[number];
export function isFormativeInteractionType(v: string): v is FormativeInteractionType {
  return (FORMATIVE_INTERACTION_TYPES as readonly string[]).includes(v);
}

/** M3 审核工作流：标准层级类型守卫 */
const STANDARD_LEVELS = ["national", "curriculum", "custom"] as const;
export type StandardLevel = (typeof STANDARD_LEVELS)[number];
export function isStandardLevel(v: string): v is StandardLevel {
  return (STANDARD_LEVELS as readonly string[]).includes(v);
}

const TEMPLATE_TYPES = ["system", "personal"] as const;
export 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;
export function isTemplateScope(v: string): v is TemplateScope {
  return (TEMPLATE_SCOPES as readonly string[]).includes(v);
}

// ---- Block 数据类型守卫 ----
// 各守卫通过检查该 Block 数据接口的"特征字段"来收窄联合类型 BlockData。
// 特征字段选取接口中独有且必填的字段，避免与其他接口混淆。

function isObject(v: unknown): v is Record<string, unknown> {
  return typeof v === "object" && v !== null;
}

export function isRichTextBlockData(data: BlockData): data is RichTextBlockData {
  return isObject(data) && typeof data.html === "string" && Array.isArray(data.knowledgePointIds);
}

export function isTextStudyBlockData(data: BlockData): data is TextStudyBlockData {
  return (
    isObject(data) &&
    typeof data.sourceText === "string" &&
    Array.isArray(data.annotations) &&
    Array.isArray(data.knowledgePointIds)
  );
}

export function isExerciseBlockData(data: BlockData): data is ExerciseBlockData {
  return (
    isObject(data) &&
    Array.isArray(data.items) &&
    (data.purpose === "class_practice" || data.purpose === "after_class_homework")
  );
}

export function isObjectiveBlockData(data: BlockData): data is ObjectiveBlockData {
  return isObject(data) && Array.isArray(data.objectives);
}

export function isKeyPointBlockData(data: BlockData): data is KeyPointBlockData {
  return isObject(data) && Array.isArray(data.keyPoints);
}

export function isImportBlockData(data: BlockData): data is ImportBlockData {
  return (
    isObject(data) &&
    typeof data.prompt === "string" &&
    typeof data.durationMin === "number" &&
    typeof data.method === "string"
  );
}

export function isNewTeachingBlockData(data: BlockData): data is NewTeachingBlockData {
  return isObject(data) && Array.isArray(data.teachingPoints);
}

export function isSummaryBlockData(data: BlockData): data is SummaryBlockData {
  return isObject(data) && Array.isArray(data.summaryPoints) && typeof data.homeworkPreview === "string";
}

export function isHomeworkBlockData(data: BlockData): data is HomeworkBlockData {
  return isObject(data) && Array.isArray(data.assignments);
}

export function isBlackboardBlockData(data: BlockData): data is BlackboardBlockData {
  return (
    isObject(data) &&
    typeof data.layout === "string" &&
    typeof data.content === "string" &&
    Array.isArray(data.knowledgePointIds)
  );
}

export function isReflectionBlockData(data: BlockData): data is ReflectionBlockData {
  return isObject(data) && Array.isArray(data.reflection);
}

// ---- Block 字段值类型守卫（用于 select onChange 等场景，替代 `as` 断言）----

const BLACKBOARD_LAYOUTS = ["structure", "mindmap", "text"] as const;
export function isBlackboardLayout(
  v: string,
): v is BlackboardBlockData["layout"] {
  return (BLACKBOARD_LAYOUTS as readonly string[]).includes(v);
}

const IMPORT_METHODS = ["question", "situation", "review", "other"] as const;
export function isImportMethod(v: string): v is ImportBlockData["method"] {
  return (IMPORT_METHODS as readonly string[]).includes(v);
}

const EXERCISE_PURPOSES = ["class_practice", "after_class_homework"] as const;
export function isExercisePurpose(v: string): v is ExercisePurpose {
  return (EXERCISE_PURPOSES as readonly string[]).includes(v);
}

const OBJECTIVE_DIMENSIONS = ["knowledge", "process", "emotion"] as const;
export function isObjectiveDimension(
  v: string,
): v is ObjectiveItem["dimension"] {
  return (OBJECTIVE_DIMENSIONS as readonly string[]).includes(v);
}

const KEY_POINT_TYPES = ["key", "difficult"] as const;
export function isKeyPointType(v: string): v is KeyPointItem["type"] {
  return (KEY_POINT_TYPES as readonly string[]).includes(v);
}

const HOMEWORK_TYPES = ["exercise", "reading", "writing"] as const;
export function isHomeworkType(v: string): v is HomeworkAssignment["type"] {
  return (HOMEWORK_TYPES as readonly string[]).includes(v);
}

const REFLECTION_ASPECTS = [
  "effectiveness",
  "problems",
  "improvements",
] as const;
export function isReflectionAspect(
  v: string,
): v is ReflectionItem["aspect"] {
  return (REFLECTION_ASPECTS as readonly string[]).includes(v);
}

// ---- 节点类型守卫 ----
export function isTextbookContentNode(
  node: { type: string },
): node is TextbookContentNode {
  return node.type === "textbook_content";
}

export function isLessonPlanNode(
  node: { type: string },
): node is LessonPlanNode {
  return node.type !== "textbook_content";
}

// ---- 题目类型守卫 ----
export const VALID_QUESTION_TYPES = [
  "single_choice",
  "multiple_choice",
  "text",
  "judgment",
  "composite",
] as const;
export type ValidQuestionType = (typeof VALID_QUESTION_TYPES)[number];

export function isValidQuestionType(v: string): v is ValidQuestionType {
  return (VALID_QUESTION_TYPES as readonly string[]).includes(v);
}

// ---- BlockType 守卫 ----
const VALID_BLOCK_TYPES: BlockType[] = [
  "objective",
  "key_point",
  "import",
  "new_teaching",
  "consolidation",
  "summary",
  "homework",
  "blackboard",
  "text_study",
  "exercise",
  "rich_text",
  "reflection",
];
export function isBlockType(v: string): v is BlockType {
  return (VALID_BLOCK_TYPES as readonly string[]).includes(v);
}

// ---- TemplateBlockSkeleton 守卫与规范化（替代 as 断言从 DB unknown 转换）----
// isObject 已在上方定义（第 56 行），复用同一类型守卫

/**
 * 类型守卫：判断 unknown 是否为合法的 TemplateBlockSkeleton。
 * 用于从 DB JSON 字段安全收窄，替代 `as LessonPlanTemplate["blocks"]` 断言。
 */
export function isTemplateBlockSkeleton(v: unknown): v is TemplateBlockSkeleton {
  return (
    isObject(v) &&
    typeof v.type === "string" &&
    isBlockType(v.type) &&
    typeof v.title === "string" &&
    (v.hint === undefined || typeof v.hint === "string")
  );
}

/**
 * 规范化函数：将 unknown（DB JSON 字段）安全转换为 TemplateBlockSkeleton[]。
 * 过滤掉结构不合法的项，避免畸形数据导致运行时错误。
 * 替代 `as LessonPlanTemplate["blocks"]` / `as unknown as LessonPlanTemplate["blocks"]` 断言。
 */
export function normalizeTemplateBlocks(v: unknown): TemplateBlockSkeleton[] {
  if (!Array.isArray(v)) return [];
  return v.filter(isTemplateBlockSkeleton);
}
