import React, { useEffect, useState } from "react";
import { Composition, Sequence, AbsoluteFill, Audio, staticFile, Img, useCurrentFrame, interpolate, continueRender, delayRender } from "remotion";
import type { TemplateType, AspectRatio } from "@pipeline/shared";
import type { WordTimestamp, GithubSceneData } from "@pipeline/shared";
import NewsScene from "./news/index";
import KnowledgeScene from "./knowledge/index";
import OpinionScene from "./opinion/index";
import MarketingScene from "./marketing/index";
import GithubTrendingScene from "./github-trending/index";
import { THEMES } from "./base/theme/colors";

export interface RemotionScene {
  id: string;
  sceneType: "cover" | "content" | "summary" | "outro";
  startFrame: number;
  endFrame: number;
  narration: string;
  displayText?: string;
  title?: string;
  wordTimestamps: WordTimestamp[];
  keyframes: Array<{
    type: string;
    content: string;
    startFrame?: number;
    endFrame?: number;
    style?: Record<string, string>;
  }>;
  images?: Array<{ url?: string; query?: string; filename: string }>;
  audioFilename: string;
  backgroundAsset?: { id: string; filename: string };
  layoutHint: string;
  github?: GithubSceneData;
  // github-trending cover scene only: theme tags + trend line.
  coverTags?: string[];
  trendSummary?: string;
}

export interface RemotionProps {
  scenes: RemotionScene[];
  template: TemplateType;
  platform: string;
  title: string;
  subtitle?: string;
  outro?: {
    text: string;
    narration?: string;
    cta?: string;
  };
  channelName: string;
  globalStyle: {
    tone: string;
    pace: string;
  };
}

const SCENE_MAP: Record<TemplateType, React.FC<any>> = {
  news: NewsScene,
  knowledge: KnowledgeScene,
  opinion: OpinionScene,
  marketing: MarketingScene,
  "github-trending": GithubTrendingScene,
};

const RATIO_ID: Record<AspectRatio, string> = {
  "16:9": "landscape",
  "9:16": "portrait",
};

const ASPECT_RATIOS: Record<AspectRatio, { width: number; height: number }> = {
  "16:9": { width: 1920, height: 1080 },
  "9:16": { width: 1080, height: 1920 },
};

const TEMPLATES: TemplateType[] = ["news", "knowledge", "opinion", "marketing", "github-trending"];

const TemplateComposition: React.FC<RemotionProps> = (props) => {
  const SceneComponent = SCENE_MAP[props.template];
  const totalFrames = props.scenes.at(-1)?.endFrame ?? 90;

  return (
    <AbsoluteFill style={{ backgroundColor: "#000" }}>
      {props.scenes.map((scene) => {
        const duration = scene.endFrame - scene.startFrame;
        const sceneAudio = scene.audioFilename ? (
          <Audio src={staticFile(scene.audioFilename)} />
        ) : null;

        if (scene.sceneType === "cover") {
          return (
            <Sequence
              key={scene.id}
              from={scene.startFrame}
              durationInFrames={duration}
            >
              {sceneAudio}
              <CoverScene
                template={props.template}
                title={props.title}
                subtitle={props.subtitle}
                keyframes={scene.keyframes}
                backgroundAsset={scene.backgroundAsset}
                coverTags={scene.coverTags}
                trendSummary={scene.trendSummary}
                totalFrames={totalFrames}
              />
            </Sequence>
          );
        }
        if (scene.sceneType === "outro") {
          return (
            <Sequence
              key={scene.id}
              from={scene.startFrame}
              durationInFrames={duration}
            >
              {sceneAudio}
              <OutroScene
                text={props.outro?.text || scene.narration}
                cta={props.outro?.cta}
                totalFrames={totalFrames}
              />
            </Sequence>
          );
        }
        return (
          <Sequence
            key={scene.id}
            from={scene.startFrame}
            durationInFrames={duration}
          >
            {sceneAudio}
            <SceneComponent
              scene={scene}
              sceneIndex={props.scenes.filter((s) => s.sceneType === "content").indexOf(scene)}
              totalScenes={props.scenes.filter((s) => s.sceneType === "content").length}
              totalFrames={totalFrames}
              title={props.title}
              channelName={props.channelName}
            />
          </Sequence>
        );
      })}
      <GlobalProgressBar totalFrames={totalFrames} color={THEMES[props.template].primary} />
    </AbsoluteFill>
  );
};

// --- Cover Scene ---

const CoverScene: React.FC<{
  template: TemplateType;
  title: string;
  subtitle?: string;
  keyframes: Array<{ type: string; content: string }>;
  backgroundAsset?: { id: string; filename: string };
  coverTags?: string[];
  trendSummary?: string;
  totalFrames: number;
}> = ({ template, title, subtitle, keyframes, backgroundAsset, coverTags, trendSummary }) => {
  const accent = THEMES[template].primaryLight;
  const isGithubTrending = template === "github-trending";

  // github-trending cover doubles as the opening narration screen — light
  // background, large masthead typography, no dark image overlay. It also
  // shows the day's theme tags (coverTags) and a one-line trend summary
  // (trendSummary), both LLM-produced.
  if (isGithubTrending) {
    const hasTags = !!(coverTags && coverTags.length > 0);
    return (
      <AbsoluteFill style={{
        background: "linear-gradient(135deg, #f8fafc 0%, #e2e8f0 60%, #cbd5e1 100%)",
      }}>
        {/* Top accent bar in template primary */}
        <div style={{
          position: "absolute", top: 0, left: 0, width: "100%", height: 8,
          background: `linear-gradient(90deg, ${THEMES[template].primary}, ${accent})`,
        }} />
        <div style={{
          position: "absolute", inset: 0, display: "flex",
          flexDirection: "column", justifyContent: "center", alignItems: "center",
          padding: 80, textAlign: "center",
        }}>
          <div style={{
            fontSize: 104, fontWeight: 800, color: "#0f172a",
            fontFamily: "Noto Sans SC", lineHeight: 1.15,
            marginBottom: 28, letterSpacing: "-0.02em",
          }}>
            {title}
          </div>
          {subtitle && (
            <div style={{
              fontSize: 50, fontWeight: 600, color: "#475569",
              fontFamily: "Noto Sans SC",
              padding: "12px 36px",
              borderRadius: 16,
              background: "rgba(255,255,255,0.7)",
              border: `2px solid ${accent}`,
              boxShadow: "0 8px 24px rgba(15,23,42,0.08)",
              marginBottom: hasTags || trendSummary ? 44 : 0,
            }}>
              {subtitle}
            </div>
          )}
          {hasTags && (
            <div style={{
              display: "flex", flexWrap: "wrap", justifyContent: "center",
              gap: 18, maxWidth: "82%", marginBottom: trendSummary ? 36 : 0,
            }}>
              {coverTags!.map((tag, i) => (
                <div key={i} style={{
                  display: "inline-flex", alignItems: "center", gap: 12,
                  padding: "12px 26px", borderRadius: 12,
                  background: "rgba(255,255,255,0.78)",
                  border: `1.5px solid ${accent}66`,
                  color: "#1e293b",
                  fontFamily: "Noto Sans SC", fontSize: 34, fontWeight: 600,
                  boxShadow: "0 2px 10px rgba(15,23,42,0.06)",
                }}>
                  <span style={{
                    display: "inline-block", width: 11, height: 11,
                    borderRadius: "50%", background: accent, flexShrink: 0,
                  }} />
                  {tag}
                </div>
              ))}
            </div>
          )}
          {trendSummary && (
            <div style={{
              fontSize: 40, fontWeight: 500, color: "#475569",
              fontFamily: "Noto Sans SC", maxWidth: "70%", lineHeight: 1.5,
            }}>
              {trendSummary}
            </div>
          )}
        </div>
      </AbsoluteFill>
    );
  }

  return (
    <AbsoluteFill style={{ backgroundColor: "#0f172a" }}>
      {backgroundAsset && (
        <Img
          src={staticFile(backgroundAsset.filename)}
          style={{ position: "absolute", width: "100%", height: "100%", objectFit: "cover" }}
        />
      )}
      <div
        style={{
          position: "absolute",
          inset: 0,
          background:
            "linear-gradient(to bottom, rgba(0,0,0,0.25), rgba(0,0,0,0.55))",
        }}
      />
      <div style={{
        position: "absolute", inset: 0, display: "flex",
        flexDirection: "column", justifyContent: "center", alignItems: "center",
        padding: 80, textAlign: "center",
      }}>
        <div style={{
          fontSize: 72, fontWeight: 800, color: "white",
          fontFamily: "Noto Sans SC", lineHeight: 1.2, marginBottom: 20,
          maxWidth: "80%",
          textShadow: "0 2px 16px rgba(0,0,0,0.85), 0 0 4px rgba(0,0,0,0.85)",
        }}>
          {title}
        </div>
        {subtitle && (
          <div style={{
            fontSize: 28, color: "white",
            fontFamily: "Noto Sans SC", marginBottom: 40,
            textShadow: "0 2px 12px rgba(0,0,0,0.85)",
          }}>
            {subtitle}
          </div>
        )}
        {keyframes.length > 0 && (
          <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
            {keyframes.map((kf, i) => {
              const isHighlight = kf.type === "highlight";
              return (
                <div key={i} style={{
                  fontSize: isHighlight ? 30 : 24,
                  fontWeight: isHighlight ? 700 : 500,
                  color: isHighlight ? accent : "white",
                  fontFamily: "Noto Sans SC",
                  textShadow: "0 1px 8px rgba(0,0,0,0.85)",
                }}>
                  {kf.content}
                </div>
              );
            })}
          </div>
        )}
      </div>
    </AbsoluteFill>
  );
};

// --- Outro Scene ---

const OutroScene: React.FC<{
  text: string;
  cta?: string;
  totalFrames: number;
}> = ({ text, cta }) => {
  const frame = useCurrentFrame();
  const opacity = interpolate(frame, [0, 15], [0, 1], { extrapolateRight: "clamp" });

  return (
    <AbsoluteFill style={{ opacity, backgroundColor: "#0f172a" }}>
      <div style={{
        position: "absolute", inset: 0, display: "flex",
        flexDirection: "column", justifyContent: "center", alignItems: "center",
        padding: 80, textAlign: "center",
      }}>
        <div style={{
          fontSize: 48, fontWeight: 700, color: "white",
          fontFamily: "Noto Sans SC", lineHeight: 1.4, marginBottom: 40,
          maxWidth: "80%",
        }}>
          {text}
        </div>
        {cta && (
          <div style={{
            fontSize: 28, fontWeight: 600, color: "#fbbf24",
            fontFamily: "Noto Sans SC",
            padding: "16px 48px",
            borderRadius: 12,
            border: "2px solid #fbbf24",
          }}>
            {cta}
          </div>
        )}
      </div>
    </AbsoluteFill>
  );
};

const GlobalProgressBar: React.FC<{
  totalFrames: number;
  color: string;
}> = ({ totalFrames, color }) => {
  const frame = useCurrentFrame();
  const progress = interpolate(frame, [0, totalFrames], [0, 100], {
    extrapolateRight: "clamp",
  });

  return (
    <div
      style={{
        position: "absolute",
        bottom: 0,
        left: 0,
        width: "100%",
        height: 4,
        backgroundColor: "rgba(255,255,255,0.1)",
      }}
    >
      <div
        style={{
          width: `${progress}%`,
          height: "100%",
          backgroundColor: color,
        }}
      />
    </div>
  );
};

const defaultProps: RemotionProps = {
  scenes: [
    {
      id: "cover",
      sceneType: "cover",
      startFrame: 0,
      endFrame: 90,
      narration: "",
      wordTimestamps: [],
      audioFilename: "",
      keyframes: [
        { type: "text", content: "文本转视频，一键生成" },
      ],
      layoutHint: "centered",
    },
    {
      id: "scene-1",
      sceneType: "content",
      startFrame: 90,
      endFrame: 180,
      narration: "欢迎使用 Pipeline 视频生成工具",
      wordTimestamps: [],
      audioFilename: "",
      keyframes: [
        { type: "text", content: "支持资讯、知识、观点、营销四大模板" },
      ],
      layoutHint: "centered",
    },
    {
      id: "outro",
      sceneType: "outro",
      startFrame: 180,
      endFrame: 240,
      narration: "感谢观看",
      wordTimestamps: [],
      audioFilename: "",
      keyframes: [],
      layoutHint: "centered",
    },
  ],
  template: "news",
  platform: "bilibili",
  title: "Pipeline Demo",
  subtitle: "结构化视频生成",
  outro: { text: "感谢观看", cta: "点赞 | 关注" },
  channelName: "Pipeline",
  globalStyle: { tone: "formal", pace: "normal" },
};

export const RemotionRoot: React.FC = () => {
  // Load bundled Noto Sans SC at component mount (staticFile() requires the
  // bundle context which is only ready after the component tree mounts).
  const [fontHandle] = useState(() => delayRender("Loading Noto Sans SC"));
  useEffect(() => {
    let cancelled = false;
    try {
      const style = document.createElement("style");
      style.textContent = `
        @font-face {
          font-family: "Noto Sans SC";
          src: local("Noto Sans CJK SC"),
               url(${staticFile("fonts/NotoSansSC-Regular.ttf")}) format("truetype");
          font-weight: 400;
          font-display: block;
        }
        @font-face {
          font-family: "Noto Sans SC";
          src: local("Noto Sans CJK SC"),
               url(${staticFile("fonts/NotoSansSC-Bold.ttf")}) format("truetype");
          font-weight: 700;
          font-display: block;
        }
      `;
      document.head.appendChild(style);

      const fonts = document.fonts as unknown as {
        load: (font: string) => Promise<unknown>;
      };
      Promise.all([
        fonts.load('400 16px "Noto Sans SC"'),
        fonts.load('700 16px "Noto Sans SC"'),
      ])
        .then(() => {
          if (!cancelled) continueRender(fontHandle);
        })
        .catch((err) => {
          console.error("Font loading failed:", err);
          if (!cancelled) continueRender(fontHandle);
        });
    } catch (err) {
      console.error("Font init failed:", err);
      continueRender(fontHandle);
    }
    return () => {
      cancelled = true;
    };
  }, [fontHandle]);

  return (
    <>
      {TEMPLATES.map((template) =>
        (
          Object.entries(ASPECT_RATIOS) as [
            AspectRatio,
            { width: number; height: number },
          ][]
        ).map(([ratio, dims]) => (
          <Composition
            key={`${template}-${RATIO_ID[ratio]}`}
            id={`${template}-${RATIO_ID[ratio]}`}
            component={TemplateComposition as unknown as React.FC<Record<string, unknown>>}
            durationInFrames={180}
            fps={30}
            width={dims.width}
            height={dims.height}
            defaultProps={defaultProps}
            calculateMetadata={async (params) => {
              const p = params.props as unknown as RemotionProps;
              return {
                durationInFrames: p.scenes.at(-1)?.endFrame ?? 90,
                props: params.props,
              };
            }}
          />
        ))
      )}
    </>
  );
};
