/**
 * Adaptive Practice 练习类型与状态类型守卫。
 *
 * 替代 data-access.ts 中的 `as` 断言，从 DB 取出的 enum 字段
 * 通过类型守卫严格校验后再使用。
 */

import {
  isAiRecommendedSourceMeta,
  isErrorVariantSourceMeta,
  isKnowledgePointSourceMeta,
  isWeakChapterSourceMeta,
} from "./source-meta"

import type {
  PracticeAnswerStatus,
  PracticeSourceMeta,
  PracticeStatus,
  PracticeType,
} from "../types"

const PRACTICE_TYPES = new Set<PracticeType>([
  "error_variant",
  "knowledge_point",
  "weak_chapter",
  "ai_recommended",
])

const PRACTICE_STATUSES = new Set<PracticeStatus>([
  "in_progress",
  "completed",
  "abandoned",
])

const PRACTICE_ANSWER_STATUSES = new Set<PracticeAnswerStatus>([
  "pending",
  "answered",
  "skipped",
])

export function isPracticeType(value: unknown): value is PracticeType {
  return typeof value === "string" && PRACTICE_TYPES.has(value as PracticeType)
}

export function isPracticeStatus(value: unknown): value is PracticeStatus {
  return typeof value === "string" && PRACTICE_STATUSES.has(value as PracticeStatus)
}

export function isPracticeAnswerStatus(value: unknown): value is PracticeAnswerStatus {
  return typeof value === "string" && PRACTICE_ANSWER_STATUSES.has(value as PracticeAnswerStatus)
}

/**
 * 安全转换 DB 行的 practiceType 字段。
 *
 * @throws {Error} 当值不是合法 PracticeType
 */
export function asPracticeType(value: unknown): PracticeType {
  if (!isPracticeType(value)) {
    throw new Error(`Invalid practice type: ${String(value)}`)
  }
  return value
}

/**
 * 安全转换 DB 行的 status 字段。
 *
 * @throws {Error} 当值不是合法 PracticeStatus
 */
export function asPracticeStatus(value: unknown): PracticeStatus {
  if (!isPracticeStatus(value)) {
    throw new Error(`Invalid practice status: ${String(value)}`)
  }
  return value
}

/**
 * 安全转换 DB 行的 answer status 字段。
 *
 * @throws {Error} 当值不是合法 PracticeAnswerStatus
 */
export function asPracticeAnswerStatus(value: unknown): PracticeAnswerStatus {
  if (!isPracticeAnswerStatus(value)) {
    throw new Error(`Invalid practice answer status: ${String(value)}`)
  }
  return value
}

/**
 * 安全转换 DB 行的 sourceMeta 字段。
 *
 * 不假设 practiceType 上下文，依次尝试四种来源元数据类型守卫，
 * 任意一个通过即返回收窄后的值；DB 为 null 或结构不合法时返回 null。
 *
 * 替代 `value as PracticeSourceMeta` 断言，避免脏数据导致运行时崩溃。
 */
export function asPracticeSourceMeta(value: unknown): PracticeSourceMeta | null {
  if (value === null || value === undefined) return null
  if (isErrorVariantSourceMeta(value)) return value
  if (isKnowledgePointSourceMeta(value)) return value
  if (isWeakChapterSourceMeta(value)) return value
  if (isAiRecommendedSourceMeta(value)) return value
  // 结构不匹配任何已知类型，视为损坏数据
  return null
}
