import { z } from "zod";

export const sceneSchema = z.object({
  id: z.string().optional(),
  narration: z.string().optional(),
  on_screen_text: z.string().optional(),
  visual_direction: z.string().optional(),
  duration_seconds: z.number().positive().optional(),
});

export const captionSchema = z.object({
  text: z.string(),
  start_seconds: z.number(),
  end_seconds: z.number(),
  speaker: z.string().nullable().optional(),
});

export type CaptionSegment = z.infer<typeof captionSchema>;

export const brollClipSchema = z.object({
  scene_id: z.string().nullable().optional(),
  source: z.string().nullable().optional(),
  provider: z.string().nullable().optional(),
  clip_slug: z.string().nullable().optional(),
  url: z.string().url().nullable().optional(),
});

export const manifestSchema = z.object({
  render_job_id: z.string().uuid(),
  generation_id: z.string().uuid(),
  template_slug: z.string(),
  brand_kit: z.record(z.unknown()).optional(),
  product: z.record(z.unknown()).nullable().optional(),
  script: z
    .object({
      title: z.string().optional(),
      tagline: z.string().optional(),
      cta: z.string().optional(),
      scenes: z.array(sceneSchema).optional(),
      total_duration_seconds: z.number().positive().optional(),
    })
    .nullable()
    .optional(),
  vo_url: z.string().url().nullable().optional(),
  music_url: z.string().url().nullable().optional(),
  screen_recording_url: z.string().url().nullable().optional(),
  captions: z.array(captionSchema).optional(),
  silence_trim: z.array(z.record(z.unknown())).optional(),
  transcript: z.string().nullable().optional(),
  broll_clips: z.array(brollClipSchema).optional(),
  assets: z
    .array(
      z.object({
        uuid: z.string(),
        type: z.string().optional(),
        role: z.string().nullable().optional(),
        mime_type: z.string().nullable().optional(),
        url: z.string().url().nullable().optional(),
        width: z.number().nullable().optional(),
        height: z.number().nullable().optional(),
        duration_seconds: z.number().nullable().optional(),
      }),
    )
    .optional(),
  props: z.record(z.unknown()).optional(),
});

export type ColibriManifest = z.infer<typeof manifestSchema>;
export type ColibriScene = z.infer<typeof sceneSchema>;

export const remotionInputPropsSchema = z.object({
  templateSlug: z.string(),
  title: z.string(),
  tagline: z.string().optional(),
  cta: z.string().optional(),
  scenes: z.array(sceneSchema),
  captions: z.array(captionSchema).optional(),
  brandKit: z.record(z.unknown()).optional(),
  productName: z.string().optional(),
  palette: z
    .object({
      primary: z.string().optional(),
      secondary: z.string().optional(),
      accent: z.string().optional(),
    })
    .optional(),
  voFile: z.string().optional(),
  musicFile: z.string().optional(),
  screenRecordingFile: z.string().optional(),
  brollFiles: z.record(z.string()).optional(),
  fps: z.number().positive(),
  width: z.number().positive(),
  height: z.number().positive(),
});

export type ColibriRemotionInputProps = z.infer<typeof remotionInputPropsSchema>;

export function manifestToInputProps(
  manifest: ColibriManifest,
  localFiles: {
    voFile?: string;
    musicFile?: string;
    screenRecordingFile?: string;
    brollFiles?: Record<string, string>;
  },
  video: { fps: number; width: number; height: number },
): ColibriRemotionInputProps {
  const script = manifest.script ?? {};
  const scenes = script.scenes ?? (manifest.props?.scenes as ColibriScene[] | undefined) ?? [];
  const brandKit = (manifest.brand_kit ?? {}) as Record<string, unknown>;
  const palette = (brandKit.palette ?? {}) as Record<string, string>;
  const product = manifest.product as Record<string, unknown> | null | undefined;

  return remotionInputPropsSchema.parse({
    templateSlug: manifest.template_slug,
    title:
      script.title ??
      (manifest.props?.title as string | undefined) ??
      (product?.name as string | undefined) ??
      "Colibri Video",
    tagline: script.tagline ?? undefined,
    cta: script.cta ?? undefined,
    scenes,
    captions: (manifest.captions ?? [])
      .flatMap((caption) => {
        const parsed = captionSchema.safeParse(caption);
        return parsed.success ? [parsed.data] : [];
      }),
    brandKit,
    productName: product?.name as string | undefined,
    palette: {
      primary: palette.primary ?? "#4A9EFF",
      secondary: palette.secondary ?? "#B565F5",
      accent: palette.accent ?? "#FF6FCF",
    },
    voFile: localFiles.voFile,
    musicFile: localFiles.musicFile,
    screenRecordingFile: localFiles.screenRecordingFile,
    brollFiles: localFiles.brollFiles,
    fps: video.fps,
    width: video.width,
    height: video.height,
  });
}

export function totalDurationSeconds(manifest: ColibriManifest, fallback = 15): number {
  const scriptTotal = manifest.script?.total_duration_seconds;
  if (typeof scriptTotal === "number" && scriptTotal > 0) {
    return scriptTotal;
  }

  const scenes = manifest.script?.scenes ?? [];
  const sceneTotal = scenes.reduce(
    (sum, scene) => sum + (scene.duration_seconds ?? 0),
    0,
  );

  return sceneTotal > 0 ? sceneTotal : fallback;
}

export const TEMPLATE_DURATIONS: Record<string, number> = {
  app_launch_trailer: 30,
  feature_highlight: 15,
  product_demo: 60,
  customer_testimonial: 30,
  comparison_before_after: 20,
};

export { VIDEO_TEMPLATES, resolveCompositionId, resolveThumbnailCompositionId } from "./templates.js";

export function resolveDurationSeconds(manifest: ColibriManifest): number {
  const computed = totalDurationSeconds(manifest, 0);
  if (computed > 0) {
    return computed;
  }

  return TEMPLATE_DURATIONS[manifest.template_slug] ?? 15;
}
