'use strict';

var zod = require('zod');
var animations_presetAnimations = require('../animations/preset-animations.cjs');
var utils_easings = require('./easings.cjs');
var utils_transitionRenderer = require('./transition-renderer.cjs');

/**
 * 验证数值范围
 */
function validateRange(value, min, max, name = 'value') {
  if (typeof value !== 'number' || isNaN(value)) {
    throw new Error(`${name} must be a number`);
  }
  if (value < min || value > max) {
    throw new Error(`${name} must be between ${min} and ${max}`);
  }
  return value;
}

/**
 * 验证时间值（秒）
 */
function validateTime(value, name = 'time') {
  if (typeof value !== 'number' || isNaN(value) || value < 0) {
    throw new Error(`${name} must be a non-negative number`);
  }
  return value;
}

/**
 * 验证颜色值
 */
function validateColor(value, name = 'color') {
  if (typeof value !== 'string') {
    throw new Error(`${name} must be a string`);
  }
  // 简单的颜色验证（支持 hex, rgb, rgba, 颜色名）
  const colorRegex = /^(#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})|rgb\(|rgba\(|[a-zA-Z]+)$/;
  if (!colorRegex.test(value)) {
    throw new Error(`${name} must be a valid color value`);
  }
  return value;
}

/**
 * 验证坐标点
 */
function validatePoint(point, name = 'point') {
  if (!Array.isArray(point) || point.length !== 2) {
    throw new Error(`${name} must be an array of [x, y]`);
  }
  if (typeof point[0] !== 'number' || typeof point[1] !== 'number') {
    throw new Error(`${name} coordinates must be numbers`);
  }
  return point;
}

/**
 * 验证尺寸
 */
function validateSize(size, name = 'size') {
  if (!size || typeof size.width !== 'number' || typeof size.height !== 'number') {
    throw new Error(`${name} must be an object with width and height properties`);
  }
  if (size.width <= 0 || size.height <= 0) {
    throw new Error(`${name} width and height must be positive numbers`);
  }
  return size;
}

/**
 * 验证元素配置
 */
const Unit = zod.z.union([zod.z.number(), zod.z.string()]).describe('数值或单位字符串，支持 px、rpx、vw、vh、%');
const Color = zod.z.string().describe('CSS 颜色值，如 #fff、rgba(...) 或颜色名');

const ElementConfigSchema = zod.z.object({
  x: Unit.optional().describe('位置 X'),
  y: Unit.optional().describe('位置 Y'),
  width: Unit.optional().describe('元素宽度'),
  height: Unit.optional().describe('元素高度'),
  opacity: zod.z.number().min(0).max(1).optional().describe('透明度 0–1'),
  rotation: Unit.optional().describe('旋转角度或单位'),
  scaleX: Unit.optional().describe('水平缩放'),
  scaleY: Unit.optional().describe('垂直缩放'),
  anchor: zod.z.array(zod.z.number()).length(2).optional().describe('锚点 [0–1, 0–1]'),
}).describe('通用元素配置');

/**
 * 验证动画配置
 */
const EasingNameSchema = zod.z.enum(Object.keys(utils_easings.easingMap)).describe('缓动函数名称，来自 easings.js');
const PresetNameSchema = zod.z.enum(Object.keys(animations_presetAnimations.PRESET_ANIMATIONS)).describe('预设动画名称，来自 preset-animations.js');

const AnimationOverridePresetSchema = zod.z.object({
  type: PresetNameSchema.describe('预设动画类型'),
  duration: zod.z.number().positive().optional().describe('持续时间（秒）'),
  delay: zod.z.number().min(0).optional().describe('延迟（秒）'),
  easing: zod.z.union([EasingNameSchema, zod.z.string()]).optional().describe('缓动函数'),
  startTime: zod.z.number().min(0).optional().describe('动画开始时间（相对元素）'),
}).describe('以预设为类型的动画，允许覆盖时长/延迟/easing');

const TransformStateSchema = zod.z.object({
  x: Unit.optional().describe('位置 X'),
  y: Unit.optional().describe('位置 Y'),
  opacity: zod.z.number().min(0).max(1).optional().describe('透明度 0–1'),
  rotation: Unit.optional().describe('旋转角度或单位'),
  scaleX: Unit.optional().describe('水平缩放'),
  scaleY: Unit.optional().describe('垂直缩放'),
}).describe('变换状态');

const AnimationTransformSchema = zod.z.object({
  type: zod.z.literal('transform').describe('动画类型：transform'),
  from: TransformStateSchema.optional().describe('起始状态'),
  to: TransformStateSchema.optional().describe('结束状态'),
  duration: zod.z.number().positive().describe('持续时间（秒）'),
  delay: zod.z.number().min(0).optional().describe('延迟（秒）'),
  easing: zod.z.union([EasingNameSchema, zod.z.string()]).optional().describe('缓动函数'),
  startTime: zod.z.number().min(0).optional().describe('动画开始时间（相对元素）'),
}).describe('基础变换动画');

const KeyframePointSchema = zod.z.object({
  time: zod.z.number().min(0).describe('关键帧时间（0–1 或秒）'),
  x: Unit.optional().describe('位置 X'),
  y: Unit.optional().describe('位置 Y'),
  opacity: zod.z.number().min(0).max(1).optional().describe('透明度 0–1'),
  rotation: Unit.optional().describe('旋转角度或单位'),
  scaleX: Unit.optional().describe('水平缩放'),
  scaleY: Unit.optional().describe('垂直缩放'),
  translateX: Unit.optional().describe('水平位移'),
  translateY: Unit.optional().describe('垂直位移'),
}).describe('关键帧点');

const AnimationKeyframeSchema = zod.z.object({
  type: zod.z.literal('keyframe').describe('动画类型：keyframe'),
  keyframes: zod.z.array(KeyframePointSchema).min(1).describe('关键帧数组'),
  duration: zod.z.number().positive().describe('持续时间（秒）'),
  delay: zod.z.number().min(0).optional().describe('延迟（秒）'),
  easing: zod.z.union([EasingNameSchema, zod.z.string()]).optional().describe('缓动函数'),
  startTime: zod.z.number().min(0).optional().describe('动画开始时间（相对元素）'),
}).describe('关键帧动画');

 

const AnimationConfigSchema = zod.z.union([
  AnimationOverridePresetSchema,
  AnimationTransformSchema,
  AnimationKeyframeSchema,
]).describe('动画配置联合：preset/transform/keyframe');

const AnimationInputSchema = zod.z.union([
  PresetNameSchema,
  AnimationConfigSchema,
]).describe('动画输入：预设名或动画对象');

const BaseTimingSchema = zod.z.object({
  startTime: zod.z.number().min(0).optional(),
  endTime: zod.z.number().optional(),
  duration: zod.z.number().positive().optional(),
  zIndex: zod.z.number().optional(),
  visible: zod.z.boolean().optional(),
  animations: zod.z.array(AnimationInputSchema).optional(),
}).describe('通用时间与显示控制');

const ElementBaseSchema = ElementConfigSchema.merge(BaseTimingSchema).extend({
  type: zod.z.string().describe('元素类型'),
}).describe('元素基础配置');

const TextElementSchema = ElementBaseSchema.extend({
  type: zod.z.literal('text'),
  text: zod.z.string().describe('文本内容'),
  fontSize: Unit.optional().describe('字号'),
  fontFamily: zod.z.string().optional().describe('字体'),
  fontWeight: zod.z.union([zod.z.string(), zod.z.number()]).optional(),
  fontStyle: zod.z.string().optional(),
  color: Color.optional().describe('文字颜色'),
  textAlign: zod.z.enum(['left', 'center', 'right']).optional().describe('水平对齐'),
  textBaseline: zod.z.enum(['top', 'middle', 'bottom', 'alphabetic']).optional().describe('垂直对齐'),
  lineHeight: zod.z.union([zod.z.number(), zod.z.string()]).optional(),
  stroke: zod.z.boolean().optional(),
  strokeColor: Color.optional(),
  strokeWidth: Unit.optional(),
  split: zod.z.union([zod.z.literal('letter'), zod.z.literal('word'), zod.z.literal('line')]).nullable().optional().describe('文本拆分粒度'),
  splitDelay: zod.z.number().optional().describe('拆分延迟'),
  splitDuration: zod.z.number().optional().describe('拆分片段持续时间'),
}).describe('文本元素');

const ImageElementSchema = ElementBaseSchema.extend({
  type: zod.z.literal('image'),
  src: zod.z.string().describe('图片路径'),
  fit: zod.z.enum(['contain', 'cover', 'fill', 'scale-down', 'none']).optional().describe('缩放模式'),
  preserveAspectRatio: zod.z.boolean().optional().describe('保持纵横比'),
  blendMode: zod.z.string().optional().describe('混合模式'),
  borderRadius: Unit.optional(),
  borderWidth: Unit.optional(),
  borderColor: Color.optional(),
  shadowBlur: zod.z.number().min(0).optional().describe('阴影模糊半径'),
  shadowColor: Color.optional().describe('阴影颜色'),
  shadowOffsetX: zod.z.number().optional().describe('阴影 X 偏移'),
  shadowOffsetY: zod.z.number().optional().describe('阴影 Y 偏移'),
  filter: zod.z.union([zod.z.string(), zod.z.null()]).optional().describe('滤镜'),
  flipX: zod.z.boolean().optional(),
  flipY: zod.z.boolean().optional(),
  brightness: zod.z.number().min(0).max(2).optional().describe('亮度 0–2'),
  contrast: zod.z.number().min(0).max(2).optional().describe('对比度 0–2'),
  saturation: zod.z.number().min(0).max(2).optional().describe('饱和度 0–2'),
  hue: zod.z.number().min(0).max(360).optional().describe('色相 0–360'),
  grayscale: zod.z.number().min(0).max(1).optional().describe('灰度 0–1'),
  glassEffect: zod.z.boolean().optional().describe('毛玻璃效果'),
  glassBlur: zod.z.number().min(0).optional().describe('毛玻璃模糊半径'),
  glassOpacity: zod.z.number().min(0).max(1).optional().describe('毛玻璃透明度 0–1'),
  glassTint: Color.optional().describe('毛玻璃色调'),
  glassBorder: zod.z.boolean().optional().describe('毛玻璃边框'),
  glassBorderColor: Color.optional().describe('毛玻璃边框颜色'),
  glassBorderWidth: zod.z.number().min(0).optional().describe('毛玻璃边框宽度'),
}).describe('图片元素');

const VideoElementSchema = ElementBaseSchema.extend({
  type: zod.z.literal('video'),
  src: zod.z.string().optional().describe('视频源 URL'),
  videoPath: zod.z.string().optional().describe('视频文件路径'),
  fit: zod.z.enum(['contain', 'cover', 'fill', 'scale-down', 'none']).optional().describe('缩放模式'),
  blendMode: zod.z.string().optional().describe('混合模式'),
  borderRadius: Unit.optional(),
  borderWidth: Unit.optional(),
  borderColor: Color.optional(),
  shadowBlur: zod.z.number().min(0).optional().describe('阴影模糊半径'),
  shadowColor: Color.optional().describe('阴影颜色'),
  shadowOffsetX: zod.z.number().optional().describe('阴影 X 偏移'),
  shadowOffsetY: zod.z.number().optional().describe('阴影 Y 偏移'),
  filter: zod.z.union([zod.z.string(), zod.z.null()]).optional().describe('滤镜'),
  flipX: zod.z.boolean().optional(),
  flipY: zod.z.boolean().optional(),
  brightness: zod.z.number().min(0).max(2).optional().describe('亮度 0–2'),
  contrast: zod.z.number().min(0).max(2).optional().describe('对比度 0–2'),
  saturation: zod.z.number().min(0).max(2).optional().describe('饱和度 0–2'),
  hue: zod.z.number().min(0).max(360).optional().describe('色相 0–360'),
  grayscale: zod.z.number().min(0).max(1).optional().describe('灰度 0–1'),
  glassEffect: zod.z.boolean().optional().describe('毛玻璃效果'),
  glassBlur: zod.z.number().min(0).optional().describe('毛玻璃模糊半径'),
  glassOpacity: zod.z.number().min(0).max(1).optional().describe('毛玻璃透明度 0–1'),
  glassTint: Color.optional().describe('毛玻璃色调'),
  glassBorder: zod.z.boolean().optional().describe('毛玻璃边框'),
  glassBorderColor: Color.optional().describe('毛玻璃边框颜色'),
  glassBorderWidth: zod.z.number().min(0).optional().describe('毛玻璃边框宽度'),
  cutFrom: zod.z.number().min(0).optional().describe('裁剪起始时间（秒）'),
  cutTo: zod.z.number().optional().describe('裁剪结束时间（秒）'),
  speed: zod.z.number().positive().optional().describe('播放速度倍数'),
  loop: zod.z.boolean().optional().describe('循环播放'),
  mute: zod.z.boolean().optional().describe('静音'),
  volume: zod.z.number().min(0).max(1).optional().describe('音量 0–1'),
}).describe('视频元素');

const RectElementSchema = ElementBaseSchema.extend({
  type: zod.z.literal('rect'),
  bgcolor: Color.optional(),
  borderRadius: Unit.optional(),
  borderWidth: Unit.optional(),
  borderColor: Color.optional(),
}).describe('矩形元素');

const CircleElementSchema = ElementBaseSchema.extend({
  type: zod.z.literal('circle'),
  radius: Unit.optional(),
  bgcolor: Color.optional(),
  borderWidth: Unit.optional(),
  borderColor: Color.optional(),
}).describe('圆形元素');

const PathElementSchema = ElementBaseSchema.extend({
  type: zod.z.literal('path'),
  points: zod.z.array(zod.z.array(Unit)).optional(),
  closed: zod.z.boolean().optional(),
  fillColor: Color.optional(),
  strokeColor: Color.optional(),
  strokeWidth: Unit.optional(),
  dashArray: zod.z.array(Unit).optional(),
  dashOffset: Unit.optional(),
}).describe('路径元素');

const SVGElementSchema = ElementBaseSchema.extend({
  type: zod.z.literal('svg'),
  src: zod.z.string().optional().describe('SVG 文件路径'),
  svgString: zod.z.string().optional().describe('SVG 字符串'),
  fit: zod.z.enum(['contain', 'cover', 'fill', 'scale-down', 'none']).optional().describe('缩放模式'),
  preserveAspectRatio: zod.z.boolean().optional().describe('保持纵横比'),
  enableSVGAnimations: zod.z.boolean().optional().describe('启用原生 SVG 动画'),
}).describe('SVG 元素');

const AudioElementSchema = ElementBaseSchema.extend({
  type: zod.z.literal('audio'),
  src: zod.z.string().optional().describe('音频源 URL'),
  audioPath: zod.z.string().optional().describe('音频文件路径'),
  cutFrom: zod.z.number().min(0).optional().describe('裁剪起始时间（秒）'),
  cutTo: zod.z.number().optional().describe('裁剪结束时间（秒）'),
  volume: zod.z.number().min(0).max(1).optional().describe('音量 0–1'),
  loop: zod.z.boolean().optional().describe('循环播放'),
}).describe('音频元素');

const SubtitleElementSchema = ElementBaseSchema.extend({
  type: zod.z.literal('subtitle'),
  text: zod.z.string().describe('字幕内容'),
  fontSize: Unit.optional().describe('字号'),
  fontFamily: zod.z.string().optional().describe('字体'),
  color: Color.optional().describe('文字颜色'),
  textAlign: zod.z.enum(['left', 'center', 'right']).optional().describe('水平对齐'),
  split: zod.z.union([zod.z.literal('letter'), zod.z.literal('word'), zod.z.literal('line')]).nullable().optional().describe('文本拆分粒度'),
  splitDelay: zod.z.number().optional().describe('拆分延迟'),
  splitDuration: zod.z.number().optional().describe('拆分片段持续时间'),
}).describe('字幕元素');

const OscilloscopeElementSchema = ElementBaseSchema.extend({
  type: zod.z.literal('oscilloscope'),
  src: zod.z.string().optional().describe('音频源路径或 URL'),
  waveColor: Color.optional().describe('波形颜色'),
  backgroundColor: Color.optional().describe('背景颜色'),
  lineWidth: Unit.optional().describe('波形线宽'),
  smoothing: zod.z.number().optional().describe('平滑系数'),
  mirror: zod.z.boolean().optional().describe('镜像显示'),
  style: zod.z.string().optional().describe('样式类型'),
  sensitivity: zod.z.number().optional().describe('灵敏度'),
  windowSize: zod.z.number().optional().describe('窗口大小'),
  scrollSpeed: zod.z.number().optional().describe('滚动速度'),
  cutFrom: zod.z.number().min(0).optional().describe('裁剪起始时间'),
  cutTo: zod.z.number().optional().describe('裁剪结束时间'),
}).describe('示波器元素');

const EChartsElementSchema = ElementBaseSchema.extend({
  type: zod.z.literal('echarts'),
  option: zod.z.record(zod.z.any()).optional().describe('ECharts 配置对象'),
  renderer: zod.z.enum(['canvas', 'svg']).optional().describe('渲染器类型'),
  theme: zod.z.union([zod.z.string(), zod.z.null()]).optional().describe('主题名称或 null'),
  bgcolor: Color.optional().describe('背景颜色'),
}).describe('ECharts 元素');

const CodeElementSchema = ElementBaseSchema.extend({
  type: zod.z.literal('code'),
  code: zod.z.string().optional().describe('代码字符串'),
  language: zod.z.string().optional().describe('代码语言'),
  theme: zod.z.enum(['dark', 'light', 'monokai', 'dracula']).optional().describe('主题'),
  showLineNumbers: zod.z.boolean().optional().describe('显示行号'),
  padding: Unit.optional().describe('内容内边距'),
  lineHeight: zod.z.union([zod.z.number(), zod.z.string()]).optional().describe('行高'),
  fontSize: Unit.optional().describe('字号'),
  showBorder: zod.z.boolean().optional().describe('显示边框'),
  borderRadius: Unit.optional().describe('圆角'),
  borderWidth: Unit.optional().describe('边框宽度'),
  bgcolor: Color.optional().describe('背景颜色'),
  borderColor: Color.optional().describe('边框颜色'),
  split: zod.z.union([zod.z.literal('letter'), zod.z.literal('word'), zod.z.literal('line')]).nullable().optional().describe('文本拆分粒度'),
  splitDelay: zod.z.number().optional().describe('拆分延迟'),
  splitDuration: zod.z.number().optional().describe('拆分片段持续时间'),
  cursor: zod.z.boolean().optional().describe('显示光标'),
  cursorWidth: Unit.optional().describe('光标宽度'),
  cursorColor: Color.optional().describe('光标颜色'),
  cursorBlinkPeriod: zod.z.number().optional().describe('光标闪烁周期'),
}).describe('代码元素');

const SpriteElementSchema = ElementBaseSchema.extend({
  type: zod.z.literal('sprite'),
  spriteType: zod.z.enum(['Sprite', 'Rect', 'Circle', 'Label']).optional().describe('Sprite 类型'),
  spriteConfig: zod.z.record(zod.z.any()).optional().describe('Sprite 配置对象'),
  frames: zod.z.array(zod.z.string()).optional().describe('序列帧图片路径数组'),
  frameRate: zod.z.number().positive().optional().describe('帧率（帧/秒）'),
  loop: zod.z.boolean().optional().describe('是否循环播放'),
  autoplay: zod.z.boolean().optional().describe('是否自动播放'),
  playMode: zod.z.enum(['forward', 'reverse', 'pingpong']).optional().describe('播放模式'),
  fit: zod.z.enum(['contain', 'cover', 'fill', 'scale-down', 'none']).optional().describe('缩放模式'),
  preserveAspectRatio: zod.z.boolean().optional().describe('保持纵横比'),
  src: zod.z.string().optional().describe('精灵图图片路径'),
  columns: zod.z.number().positive().optional().describe('图集中列数（每行帧数）'),
  rows: zod.z.number().positive().optional().describe('图集中行数'),
  frameWidth: zod.z.number().positive().optional().describe('单帧宽度（像素）'),
  frameHeight: zod.z.number().positive().optional().describe('单帧高度（像素）'),
  frameCount: zod.z.number().positive().optional().describe('总帧数'),
  margin: zod.z.number().min(0).optional().describe('外边距（像素）'),
  spacing: zod.z.number().min(0).optional().describe('帧间距（像素）'),
  startIndex: zod.z.number().min(0).optional().describe('起始帧索引'),
  orientation: zod.z.enum(['row-major', 'column-major']).optional().describe('索引扫描方式'),
}).describe('精灵元素');

const JSONElementSchema = ElementBaseSchema.extend({
  type: zod.z.literal('json'),
  src: zod.z.string().optional().describe('JSON 文件路径'),
  jsonData: zod.z.record(zod.z.any()).optional().describe('JSON 对象'),
  jsonString: zod.z.string().optional().describe('JSON 字符串'),
  fit: zod.z.enum(['contain', 'cover', 'fill', 'scale-down', 'none']).optional().describe('缩放模式'),
  preserveAspectRatio: zod.z.boolean().optional().describe('保持纵横比'),
}).describe('JSON 元素');

const ElementSchema = zod.z.discriminatedUnion('type', [
  TextElementSchema,
  ImageElementSchema,
  VideoElementSchema,
  RectElementSchema,
  CircleElementSchema,
  PathElementSchema,
  SVGElementSchema,
  AudioElementSchema,
  SubtitleElementSchema,
  OscilloscopeElementSchema,
  EChartsElementSchema,
  CodeElementSchema,
  SpriteElementSchema,
  JSONElementSchema,
]).describe('元素联合 Schema，根据 type 选择具体结构');

const SceneConfigSchema = zod.z.object({
  duration: zod.z.number().positive(),
  startTime: zod.z.number().min(0).optional(),
  name: zod.z.string().optional(),
}).describe('场景配置');

const TrackConfigSchema = zod.z.object({
  zIndex: zod.z.number().optional(),
  name: zod.z.string().optional(),
  width: zod.z.number().optional(),
  height: zod.z.number().optional(),
  fps: zod.z.number().optional(),
}).describe('轨道配置');

const VideoBuilderConfigSchema = zod.z.object({
  width: zod.z.number().positive(),
  height: zod.z.number().positive(),
  fps: zod.z.number().positive(),
  backgroundColor: Color.optional(),
}).describe('VideoBuilder 配置');

const PresetAnimationNamesSchema = PresetNameSchema.describe('预设动画名称枚举');
const EasingNamesSchema = EasingNameSchema.describe('缓动函数名称枚举');
const TransitionNameSchema = zod.z.enum(utils_transitionRenderer.AllTransitions).describe('转场名称，来自 transition-renderer.js AllTransitions');
const TransitionNamesSchema = TransitionNameSchema.describe('转场名称枚举');

exports.AnimationConfigSchema = AnimationConfigSchema;
exports.AnimationInputSchema = AnimationInputSchema;
exports.AudioElementSchema = AudioElementSchema;
exports.CircleElementSchema = CircleElementSchema;
exports.CodeElementSchema = CodeElementSchema;
exports.EChartsElementSchema = EChartsElementSchema;
exports.EasingNamesSchema = EasingNamesSchema;
exports.ElementConfigSchema = ElementConfigSchema;
exports.ElementSchema = ElementSchema;
exports.ImageElementSchema = ImageElementSchema;
exports.JSONElementSchema = JSONElementSchema;
exports.OscilloscopeElementSchema = OscilloscopeElementSchema;
exports.PathElementSchema = PathElementSchema;
exports.PresetAnimationNamesSchema = PresetAnimationNamesSchema;
exports.RectElementSchema = RectElementSchema;
exports.SVGElementSchema = SVGElementSchema;
exports.SceneConfigSchema = SceneConfigSchema;
exports.SpriteElementSchema = SpriteElementSchema;
exports.SubtitleElementSchema = SubtitleElementSchema;
exports.TextElementSchema = TextElementSchema;
exports.TrackConfigSchema = TrackConfigSchema;
exports.TransitionNamesSchema = TransitionNamesSchema;
exports.VideoBuilderConfigSchema = VideoBuilderConfigSchema;
exports.VideoElementSchema = VideoElementSchema;
exports.validateColor = validateColor;
exports.validatePoint = validatePoint;
exports.validateRange = validateRange;
exports.validateSize = validateSize;
exports.validateTime = validateTime;
//# sourceMappingURL=validator.cjs.map
