/**
 * Adaptive Practice 来源元数据类型守卫。
 *
 * 从 data-access-strategy.ts 抽取为独立模块，便于单测与跨模块复用。
 *
 * 严格校验 PracticeSourceMeta 联合类型的字段结构，
 * 替代原先仅检查 key 存在性的弱校验。
 */

import { isRecord } from "@/shared/lib/type-guards"

import type {
  AiRecommendedSourceMeta,
  ErrorVariantSourceMeta,
  KnowledgePointSourceMeta,
  PracticeSourceMeta,
  WeakChapterSourceMeta,
} from "../types"

/**
 * 判断值是否为非空字符串数组。
 */
function isStringArray(value: unknown): value is string[] {
  return Array.isArray(value) && value.every((v) => typeof v === "string")
}

/**
 * 判断 sourceMeta 是否为错题重做类型。
 *
 * 严格校验 errorBookItemIds 与 sourceQuestionIds 均为非空 string[]。
 */
export function isErrorVariantSourceMeta(meta: unknown): meta is ErrorVariantSourceMeta {
  if (!isRecord(meta)) return false
  return isStringArray(meta.errorBookItemIds) && isStringArray(meta.sourceQuestionIds)
}

/**
 * 判断 sourceMeta 是否为知识点专项类型。
 *
 * 严格校验 knowledgePointIds 为非空 string[]，difficulty 为可选 1-5 数字。
 */
export function isKnowledgePointSourceMeta(meta: unknown): meta is KnowledgePointSourceMeta {
  if (!isRecord(meta)) return false
  if (!isStringArray(meta.knowledgePointIds)) return false
  if (meta.difficulty !== undefined) {
    if (typeof meta.difficulty !== "number") return false
    if (!Number.isInteger(meta.difficulty)) return false
    if (meta.difficulty < 1 || meta.difficulty > 5) return false
  }
  return true
}

/**
 * 判断 sourceMeta 是否为薄弱章节类型。
 *
 * chapterId 可选——未传时跨所有章节自动识别薄弱知识点；
 * 若传入必须为非空 string。
 * weakKnowledgePointIds 可选——未传时由 data-access 自动识别；
 * 若存在必须为非空 string[]。
 */
export function isWeakChapterSourceMeta(meta: unknown): meta is WeakChapterSourceMeta {
  if (!isRecord(meta)) return false
  // chapterId 可选：未传 → undefined；若传必须为非空 string
  if (meta.chapterId !== undefined) {
    if (typeof meta.chapterId !== "string" || meta.chapterId.length === 0) return false
  }
  // weakKnowledgePointIds 可选：未传 → undefined；若传必须为非空 string[]
  if (meta.weakKnowledgePointIds === undefined) return true
  return isStringArray(meta.weakKnowledgePointIds)
}

/** AI 推荐理由枚举集合（与 AiRecommendedReason 类型对齐） */
const AI_RECOMMENDED_REASONS = new Set([
  "student_initiated",
  "teacher_assigned",
  "parent_suggested",
])

/**
 * 判断 sourceMeta 是否为 AI 推荐类型。
 *
 * 严格校验 recommendedKnowledgePointIds 为非空 string[]，
 * reason 为 AiRecommendedReason 枚举值（业务数据，UI 层翻译）。
 */
export function isAiRecommendedSourceMeta(meta: unknown): meta is AiRecommendedSourceMeta {
  if (!isRecord(meta)) return false
  if (!isStringArray(meta.recommendedKnowledgePointIds)) return false
  return typeof meta.reason === "string" && AI_RECOMMENDED_REASONS.has(meta.reason)
}

/**
 * 根据练习类型字符串尝试收窄 sourceMeta。
 *
 * 用于在 actions 层替代 `as unknown as PracticeSourceMeta` 断言。
 *
 * @returns 收窄后的 sourceMeta；如果类型不匹配返回 null。
 */
export function parseSourceMeta(
  practiceType: string,
  raw: unknown,
): PracticeSourceMeta | null {
  switch (practiceType) {
    case "error_variant":
      return isErrorVariantSourceMeta(raw) ? raw : null
    case "knowledge_point":
      return isKnowledgePointSourceMeta(raw) ? raw : null
    case "weak_chapter":
      return isWeakChapterSourceMeta(raw) ? raw : null
    case "ai_recommended":
      return isAiRecommendedSourceMeta(raw) ? raw : null
    default:
      return null
  }
}
