import { promises as fs } from "fs";
import type { BrandProfile, PostSequenceItem, Project } from "@/types/workflow";
import { getSequenceContent } from "@/lib/context/format-sequence-context";
import type { StoryContextSections, SocialImageContext } from "@/lib/generation/social-image";
import { buildSocialImageContext } from "@/lib/generation/social-image";
import {
  buildDynamicVideoPrompt,
  buildDynamicVideoStoryboard,
} from "@/lib/generation/dynamic-video-prompt";
import { buildMultiSlideMp4, buildSlideshowMp4, isFfmpegAvailable } from "./ffmpeg-video";
import { getVideoConfig } from "./video-config";
import { rasterizeSvgToPng } from "./image-rasterize";
import {
  buildStorySlideSvg,
  decodeSvgDataUrl,
  STORY_SLIDE_COUNT,
} from "./story-slides";
import {
  getLocalMediaPath,
  mediaApiUrl,
  persistGeneratedVideo,
  resolveLocalMediaPath,
} from "@/lib/storage/media-files";

export interface SlideshowVideoInput {
  postId: string;
  /** Unique per generation — forces new slide/mp4 filenames on regenerate. */
  mediaAssetId: string;
  imageUrl: string | null;
  project: Project;
  brand: BrandProfile;
  sequenceItem: PostSequenceItem;
  caption: string;
  storySections?: StoryContextSections;
  sequenceIndex: number;
  marketingContext?: string;
  websiteAnalysis?: string;
  /** When provided, builds 5-screen story video from brand context instead of single-image zoom. */
  socialImageContext?: SocialImageContext;
}

export interface SlideshowVideoResult {
  videoUrl: string | null;
  videoStatus: "generated" | "failed" | "skipped";
  videoWarning?: string | null;
  videoPrompt: string;
  videoStoryboard: string;
  videoDurationSeconds: number;
  videoResolution: string;
  videoSlideCount?: number;
}

/** @deprecated Use buildDynamicVideoPrompt — kept for imports */
export function buildContextVideoPrompt(input: {
  brand: BrandProfile;
  project: Project;
  sequenceItem: PostSequenceItem;
  caption: string;
  storySections?: StoryContextSections;
  marketingContext?: string;
}): string {
  const cfg = getVideoConfig();
  return buildDynamicVideoPrompt({
    brand: input.brand,
    project: input.project,
    sequenceItem: input.sequenceItem,
    caption: input.caption,
    storySections: input.storySections,
    marketingContext:
      input.marketingContext ??
      getSequenceContent(input.sequenceItem).slice(0, 1500),
    durationSeconds: cfg.durationSeconds,
  });
}

export function buildContextVideoStoryboard(input: {
  brand: BrandProfile;
  sequenceItem: PostSequenceItem;
  storySections?: StoryContextSections;
  videoPrompt: string;
  durationSeconds?: number;
}): string {
  return buildDynamicVideoStoryboard(input.videoPrompt, {
    brand: input.brand,
    sequenceItem: input.sequenceItem,
    storySections: input.storySections,
    durationSeconds: input.durationSeconds,
  });
}

async function rasterizeStorySlides(input: {
  postId: string;
  mediaAssetId: string;
  socialCtx: SocialImageContext;
}): Promise<string[]> {
  const cfg = getVideoConfig();
  const paths: string[] = [];
  const assetId = input.mediaAssetId || input.postId;

  for (let i = 0; i < STORY_SLIDE_COUNT; i++) {
    const dataUrl = buildStorySlideSvg(input.socialCtx, i);
    const markup = decodeSvgDataUrl(dataUrl);
    if (!markup) continue;

    const svgPath = getLocalMediaPath(`${assetId}-slide-${i}.svg`);
    const pngPath = getLocalMediaPath(`${assetId}-slide-${i}.png`);
    await fs.writeFile(svgPath, markup, "utf-8");

    const ok = await rasterizeSvgToPng(svgPath, pngPath, {
      width: cfg.width,
      height: cfg.height,
    });
    if (ok) paths.push(pngPath);
  }

  return paths;
}

/** Create MP4 — 5 branded story screens when context is available, else Ken Burns on post image. */
export async function generateSlideshowVideo(
  input: SlideshowVideoInput,
): Promise<SlideshowVideoResult> {
  const cfg = getVideoConfig();
  const marketingContext =
    input.marketingContext ?? getSequenceContent(input.sequenceItem);

  const videoPromptBase = buildDynamicVideoPrompt({
    brand: input.brand,
    project: input.project,
    sequenceItem: input.sequenceItem,
    caption: input.caption,
    storySections: input.storySections,
    marketingContext,
    durationSeconds: cfg.durationSeconds,
    websiteAnalysis: input.websiteAnalysis,
  });
  const layoutSeed = input.socialImageContext?.layoutSeed;
  const videoPrompt =
    layoutSeed != null
      ? `${videoPromptBase}\n\n## Regeneration uniqueness\nAsset layout seed: ${layoutSeed}. Rebuild every scene from scratch with a unique composition — do not reuse prior frame layouts.`
      : videoPromptBase;

  const videoStoryboard = buildDynamicVideoStoryboard(videoPrompt, {
    brand: input.brand,
    sequenceItem: input.sequenceItem,
    storySections: input.storySections,
    durationSeconds: cfg.durationSeconds,
  });

  const base = {
    videoPrompt,
    videoStoryboard,
    videoDurationSeconds: cfg.durationSeconds,
    videoResolution: `${cfg.width}x${cfg.height}`,
  };

  if (!cfg.enabled) {
    return {
      ...base,
      videoUrl: null,
      videoStatus: "skipped",
      videoWarning: "VIDEO_PROVIDER=off — enable ffmpeg in .env.local for YouTube-ready MP4.",
    };
  }

  const ffmpegOk = await isFfmpegAvailable();
  if (!ffmpegOk) {
    return {
      ...base,
      videoUrl: null,
      videoStatus: "failed",
      videoWarning:
        "FFmpeg not installed on server. Install FFmpeg and set FFMPEG_PATH, or VIDEO_PROVIDER=off.",
    };
  }

  const assetId = input.mediaAssetId || input.postId;
  const outputPath = getLocalMediaPath(`${assetId}.mp4`);

  let slidePaths: string[] = [];
  if (input.socialImageContext) {
    slidePaths = await rasterizeStorySlides({
      postId: input.postId,
      mediaAssetId: assetId,
      socialCtx: input.socialImageContext,
    });
  }

  if (slidePaths.length >= STORY_SLIDE_COUNT) {
    const result = await buildMultiSlideMp4({
      slidePaths,
      outputPath,
      durationSeconds: cfg.durationSeconds,
    });

    if (result.ok) {
      const videoUrl = mediaApiUrl(`${assetId}.mp4`);
      const persisted = await persistGeneratedVideo(assetId, videoUrl);
      return {
        ...base,
        videoUrl: persisted,
        videoStatus: "generated",
        videoWarning: null,
        videoSlideCount: slidePaths.length,
      };
    }

    console.warn("[PostSync] Multi-slide video failed, falling back to post image:", result.error);
  }

  const imagePath = resolveLocalMediaPath(input.imageUrl);
  if (!imagePath) {
    return {
      ...base,
      videoUrl: null,
      videoStatus: "skipped",
      videoWarning: "Video skipped — post image must be saved locally (/api/media/...).",
    };
  }

  const result = await buildSlideshowMp4({
    imagePath,
    outputPath,
    durationSeconds: cfg.durationSeconds,
  });

  if (!result.ok) {
    return {
      ...base,
      videoUrl: null,
      videoStatus: "failed",
      videoWarning: result.error,
    };
  }

  const videoUrl = mediaApiUrl(`${assetId}.mp4`);
  const persisted = await persistGeneratedVideo(assetId, videoUrl);

  return {
    ...base,
    videoUrl: persisted,
    videoStatus: "generated",
    videoWarning: slidePaths.length
      ? `Multi-slide render failed — used single-image zoom fallback.`
      : null,
    videoSlideCount: 1,
  };
}

/** Helper to build social image context for video when not passed from generation run. */
export function buildVideoSocialContext(input: {
  project: Project;
  brand: BrandProfile;
  sequenceItem: PostSequenceItem;
  caption: string;
  storySections?: StoryContextSections;
}): SocialImageContext {
  return buildSocialImageContext({
    project: input.project,
    brand: input.brand,
    sequenceItem: input.sequenceItem,
    caption: input.caption,
    storySections: input.storySections,
  });
}
