import React from "react";
import {
  AbsoluteFill,
  getInputProps,
  Img,
  interpolate,
  staticFile,
  useCurrentFrame,
  useVideoConfig,
} from "remotion";
import { Audio } from "@remotion/media";
import { FontsGate } from "./Fonts";
import { FilmGrain } from "./components/FilmGrain";
import { LogoMark } from "./components/Logo";
import {
  ReelSpecProvider,
  type ReelSlide,
  type ReelSpec,
  type ReelTiming,
} from "./job/reel";
import { derivePalette, FONTS } from "./theme";

/**
 * Property reel composition — a vertical 1080×1920, music-driven sequence of
 * full-bleed property photos with factual overlays (title, location, price,
 * beds/baths, features) and a contact end card. Built for the "Create Reel"
 * pipeline: no narration, no AI — every frame is derived from the ReelSpec.
 *
 * Slides use a slow Ken-Burns push so static photos feel alive; overlays use
 * the fixed brand palette via derivePalette() (warm editorial look).
 */

const WARM_PALETTE = derivePalette(null); // warm editorial default

// ─── small primitives ─────────────────────────────────────────────────────────

const springish = (frame: number, delay: number, damping = 14): number => {
  // Light, dependency-free ease-out-back approximation of Remotion's spring —
  // enough for 30fps renders and fully deterministic.
  const t = Math.max(0, (frame - delay) / 16);
  if (t <= 0) return 0;
  const c = damping / 10;
  return 1 + (c + 1) * Math.pow(t - 1, 3) + c * Math.pow(t - 1, 2);
};

const Kicker: React.FC<{ text: string; delay?: number }> = ({
  text,
  delay = 6,
}) => {
  const frame = useCurrentFrame();
  const f = springish(frame, delay);
  return (
    <div
      style={{
        display: "inline-flex",
        alignItems: "center",
        gap: 14,
        background: WARM_PALETTE.accent,
        color: WARM_PALETTE.onAccent,
        fontFamily: FONTS.sans,
        fontWeight: 800,
        fontSize: 30,
        letterSpacing: 6,
        textTransform: "uppercase",
        padding: "14px 34px",
        borderRadius: 999,
        opacity: f,
        transform: `translateY(${(1 - f) * 26}px)`,
        boxShadow: `0 18px 44px rgba(230,55,79,0.42)`,
      }}
    >
      {text}
    </div>
  );
};

/** Ken-Burns full-bleed photo with a bottom scrim for text legibility. */
const PhotoSlide: React.FC<{
  slide: ReelSlide;
  sceneDurationFrames: number;
  children?: React.ReactNode;
}> = ({ slide, sceneDurationFrames, children }) => {
  const frame = useCurrentFrame();
  const { fps } = useVideoConfig();
  const t = frame / fps;

  // Gentle Ken Burns: alternate zoom-in / pan direction per slide index parity.
  const zoom = interpolate(frame, [0, sceneDurationFrames], [1.04, 1.16]);
  const drift = interpolate(frame, [0, sceneDurationFrames], [0, -26]);

  return (
    <AbsoluteFill style={{ overflow: "hidden", backgroundColor: "#241a0f" }}>
      <Img
        src={staticFile(slide.image || "images/house1.jpg")}
        style={{
          position: "absolute",
          inset: -40,
          width: "calc(100% + 80px)",
          height: "calc(100% + 80px)",
          objectFit: "cover",
          transform: `scale(${zoom}) translateY(${drift}px)`,
        }}
      />
      {/* scrims: bottom for copy, top for brand */}
      <AbsoluteFill
        style={{
          background:
            "linear-gradient(180deg, rgba(20,13,6,0.42) 0%, rgba(20,13,6,0) 26%, rgba(20,13,6,0) 52%, rgba(20,13,6,0.78) 100%)",
        }}
      />
      {children}
    </AbsoluteFill>
  );
};

const FactChips: React.FC<{ spec: ReelSpec; delay?: number }> = ({
  spec,
  delay = 20,
}) => {
  const frame = useCurrentFrame();
  const chips: Array<{ icon: string; text: string }> = [];
  if (spec.property.bedrooms)
    chips.push({ icon: "🛏", text: `${spec.property.bedrooms} Bed` });
  if (spec.property.bathrooms)
    chips.push({ icon: "🛁", text: `${spec.property.bathrooms} Bath` });
  if (spec.property.listingType === "rent")
    chips.push({ icon: "🔑", text: "To Rent" });
  if (spec.property.listingType === "sale")
    chips.push({ icon: "🏷", text: "For Sale" });

  return (
    <div style={{ display: "flex", gap: 18, flexWrap: "wrap" }}>
      {chips.map((chip, i) => {
        const f = springish(frame, delay + i * 5);
        return (
          <div
            key={chip.text}
            style={{
              display: "inline-flex",
              alignItems: "center",
              gap: 12,
              background: "rgba(255,253,248,0.92)",
              color: WARM_PALETTE.ink,
              borderRadius: 999,
              padding: "14px 30px",
              fontFamily: FONTS.sans,
              fontSize: 30,
              fontWeight: 800,
              opacity: f,
              transform: `translateY(${(1 - f) * 20}px)`,
              boxShadow: "0 12px 30px rgba(20,13,6,0.35)",
            }}
          >
            <span style={{ fontSize: 34 }}>{chip.icon}</span>
            {chip.text}
          </div>
        );
      })}
    </div>
  );
};

// ─── opening brand card ───────────────────────────────────────────────────────

const IntroSlide: React.FC<{ spec: ReelSpec }> = ({ spec }) => {
  const frame = useCurrentFrame();
  const { fps } = useVideoConfig();
  const f1 = springish(frame, 2);
  const f2 = springish(frame, 10);
  const f3 = springish(frame, 20);

  return (
    <AbsoluteFill
      style={{
        background: `radial-gradient(circle at 50% 34%, rgba(246,239,227,0.14) 0%, rgba(20,13,6,0) 46%), linear-gradient(170deg, #2a1d10 0%, #241a0f 60%, #17100a 100%)`,
        justifyContent: "center",
        alignItems: "center",
        textAlign: "center",
        padding: "0 120px",
      }}
    >
      <div
        style={{
          transform: `scale(${0.92 + f1 * 0.08})`,
          opacity: f1,
        }}
      >
        <LogoMark size={210} />
      </div>
      <div
        style={{
          marginTop: 48,
          fontFamily: FONTS.display,
          fontWeight: 800,
          fontSize: 88,
          lineHeight: 1.14,
          color: "#f6efe3",
          opacity: f2,
          transform: `translateY(${(1 - f2) * 30}px)`,
        }}
      >
        {spec.tagline || spec.property.title}
      </div>
      <div
        style={{
          marginTop: 30,
          fontFamily: FONTS.sans,
          fontSize: 32,
          letterSpacing: 10,
          textTransform: "uppercase",
          fontWeight: 700,
          color: "rgba(246,239,227,0.72)",
          opacity: f3,
        }}
      >
        {spec.brand.name}
      </div>
    </AbsoluteFill>
  );
};

// ─── end card ─────────────────────────────────────────────────────────────────

const OutroSlide: React.FC<{ spec: ReelSpec }> = ({ spec }) => {
  const frame = useCurrentFrame();
  const f1 = springish(frame, 2);
  const f2 = springish(frame, 12);
  const f3 = springish(frame, 22);

  return (
    <AbsoluteFill
      style={{
        background: `linear-gradient(165deg, ${WARM_PALETTE.accent} 0%, #b91c33 62%, #17100a 130%)`,
        justifyContent: "center",
        alignItems: "center",
        textAlign: "center",
        padding: "0 110px",
      }}
    >
      <div
        style={{
          transform: `scale(${0.9 + f1 * 0.1})`,
          opacity: f1,
        }}
      >
        <LogoMark size={180} />
      </div>
      <div
        style={{
          marginTop: 44,
          fontFamily: FONTS.display,
          fontWeight: 800,
          fontSize: 84,
          color: "#ffffff",
          lineHeight: 1.16,
          opacity: f2,
          transform: `translateY(${(1 - f2) * 30}px)`,
        }}
      >
        {spec.property.location}
      </div>
      {spec.property.price ? (
        <div
          style={{
            marginTop: 24,
            display: "inline-flex",
            background: "#ffffff",
            color: WARM_PALETTE.accentDeep,
            fontFamily: FONTS.sans,
            fontWeight: 900,
            fontSize: 52,
            padding: "20px 54px",
            borderRadius: 999,
            boxShadow: "0 24px 60px rgba(0,0,0,0.35)",
            opacity: f2,
          }}
        >
          {spec.property.price}
        </div>
      ) : null}
      <div
        style={{
          marginTop: 54,
          fontFamily: FONTS.sans,
          fontWeight: 800,
          fontSize: 40,
          letterSpacing: 3,
          color: "#ffffff",
          background: "rgba(20,13,6,0.35)",
          padding: "22px 48px",
          borderRadius: 22,
          opacity: f3,
        }}
      >
        {spec.property.url || spec.brand.website} · Enquire today
      </div>
      <div
        style={{
          marginTop: 30,
          fontFamily: FONTS.sans,
          fontSize: 26,
          letterSpacing: 8,
          fontWeight: 700,
          color: "rgba(255,255,255,0.78)",
          textTransform: "uppercase",
          opacity: f3,
        }}
      >
        {spec.brand.tagline}
      </div>
    </AbsoluteFill>
  );
};

// ─── feature card (between photos) ───────────────────────────────────────────

const FeaturesSlide: React.FC<{ spec: ReelSpec }> = ({ spec }) => {
  const frame = useCurrentFrame();
  const features = spec.property.features
    .slice(0, 4)
    .map((text) => ({ icon: "", text }));
  const icons = ["✨", "🏡", "📍", "🔒"];

  return (
    <AbsoluteFill
      style={{
        background: `linear-gradient(170deg, ${WARM_PALETTE.surface} 0%, ${WARM_PALETTE.surfaceDeep} 100%)`,
        justifyContent: "center",
        padding: "0 130px",
      }}
    >
      <Kicker text="Highlights" />
      <div
        style={{
          marginTop: 40,
          display: "flex",
          flexDirection: "column",
          gap: 28,
        }}
      >
        {features.map((feature, i) => {
          const f = springish(frame, 14 + i * 8);
          return (
            <div
              key={feature.text}
              style={{
                display: "flex",
                alignItems: "center",
                gap: 26,
                background: WARM_PALETTE.card,
                borderRadius: 24,
                padding: "26px 34px",
                boxShadow: `0 16px 40px ${WARM_PALETTE.shadow}`,
                opacity: f,
                transform: `translateX(${(1 - f) * 44}px)`,
              }}
            >
              <span style={{ fontSize: 44 }}>{feature.icon || icons[i % icons.length]}</span>
              <span
                style={{
                  fontFamily: FONTS.sans,
                  fontSize: 36,
                  fontWeight: 700,
                  color: WARM_PALETTE.ink,
                }}
              >
                {feature.text}
              </span>
            </div>
          );
        })}
      </div>
      <div
        style={{
          marginTop: 44,
          fontFamily: FONTS.display,
          fontStyle: "italic",
          fontSize: 42,
          color: WARM_PALETTE.inkSoft,
          opacity: springish(frame, 14 + features.length * 8),
        }}
      >
        {spec.property.title}
      </div>
    </AbsoluteFill>
  );
};

// ─── photo slide overlays ─────────────────────────────────────────────────────

const PhotoOverlay: React.FC<{
  spec: ReelSpec;
  slide: ReelSlide;
  isFirstPhoto: boolean;
}> = ({ spec, slide, isFirstPhoto }) => {
  const frame = useCurrentFrame();
  const f = springish(frame, 10);
  const f2 = springish(frame, 22);

  return (
    <>
      {/* top-right brand mark */}
      <div
        style={{
          position: "absolute",
          top: 90,
          right: 80,
          opacity: 0.92,
        }}
      >
        <div
          style={{
            background: "rgba(255,253,248,0.94)",
            borderRadius: 20,
            padding: "14px 22px",
            boxShadow: "0 12px 30px rgba(20,13,6,0.3)",
            transform: `scale(${f})`,
          }}
        >
          <LogoMark size={56} />
        </div>
      </div>

      {/* slide label chip */}
      {slide.label ? (
        <div
          style={{
            position: "absolute",
            top: 96,
            left: 80,
            background: "rgba(20,13,6,0.55)",
            color: "#fff",
            fontFamily: FONTS.sans,
            fontSize: 26,
            fontWeight: 700,
            letterSpacing: 4,
            textTransform: "uppercase",
            padding: "12px 26px",
            borderRadius: 999,
            opacity: f,
          }}
        >
          {slide.label}
        </div>
      ) : null}

      {/* bottom copy — full facts only on the first photo, location+price after */}
      <div style={{ position: "absolute", left: 80, right: 80, bottom: 96 }}>
        {isFirstPhoto ? (
          <>
            <div
              style={{
                fontFamily: FONTS.display,
                fontWeight: 800,
                fontSize: 76,
                lineHeight: 1.12,
                color: "#ffffff",
                textShadow: "0 12px 40px rgba(0,0,0,0.55)",
                opacity: f,
                transform: `translateY(${(1 - f) * 34}px)`,
              }}
            >
              {spec.property.title}
            </div>
            <div
              style={{
                marginTop: 20,
                display: "flex",
                alignItems: "center",
                gap: 14,
                fontFamily: FONTS.sans,
                fontSize: 36,
                fontWeight: 700,
                color: "rgba(255,253,248,0.92)",
                opacity: f2,
                transform: `translateY(${(1 - f2) * 24}px)`,
              }}
            >
              <span style={{ fontSize: 34 }}>📍</span>
              {spec.property.location}
            </div>
            {spec.property.price ? (
              <div
                style={{
                  marginTop: 24,
                  display: "inline-flex",
                  background: WARM_PALETTE.accent,
                  color: WARM_PALETTE.onAccent,
                  fontFamily: FONTS.sans,
                  fontWeight: 900,
                  fontSize: 54,
                  padding: "18px 46px",
                  borderRadius: 20,
                  boxShadow: `0 20px 50px rgba(230,55,79,0.45)`,
                  opacity: f2,
                  transform: `translateY(${(1 - f2) * 24}px)`,
                }}
              >
                {spec.property.price}
              </div>
            ) : null}
            <div style={{ marginTop: 28 }}>
              <FactChips spec={spec} />
            </div>
          </>
        ) : (
          <>
            <div
              style={{
                fontFamily: FONTS.sans,
                fontSize: 32,
                fontWeight: 800,
                letterSpacing: 5,
                textTransform: "uppercase",
                color: "rgba(255,253,248,0.85)",
                opacity: f,
              }}
            >
              {spec.property.location}
            </div>
            {spec.property.price ? (
              <div
                style={{
                  marginTop: 12,
                  fontFamily: FONTS.sans,
                  fontWeight: 900,
                  fontSize: 58,
                  color: "#ffffff",
                  textShadow: "0 12px 40px rgba(0,0,0,0.5)",
                  opacity: f2,
                }}
              >
                {spec.property.price}
              </div>
            ) : null}
          </>
        )}
      </div>
    </>
  );
};

// ─── main composition ─────────────────────────────────────────────────────────

export const ReelVideoContent: React.FC<{
  spec: ReelSpec;
  schedule: ReelTiming[];
  durationInFrames: number;
}> = ({ spec, schedule, durationInFrames }) => {
  const frame = useCurrentFrame();
  const { fps } = useVideoConfig();

  const slides = spec.slides;
  const boundaries = schedule.map((s) => Math.round(s.start * fps));
  const spans = schedule.map((s, i) => ({
    from: boundaries[i],
    to: i + 1 < boundaries.length ? boundaries[i + 1] : durationInFrames,
  }));

  let photoSeen = false;

  return (
    <ReelSpecProvider value={spec}>
      <AbsoluteFill style={{ backgroundColor: "#241a0f", overflow: "hidden" }}>
        <FontsGate>
          {slides.slice(0, spans.length).map((slide, i) => {
            const { from, to } = spans[i];
            const isIntro = i === 0 && !slide.image;
            const isPhoto = Boolean(slide.image);
            const isFirstPhoto = isPhoto && !photoSeen;
            if (isPhoto) photoSeen = true;

            let content: React.ReactNode = null;
            if (isIntro) {
              content = <IntroSlide spec={spec} />;
            } else if (isPhoto) {
              content = (
                <PhotoSlide slide={slide} sceneDurationFrames={Math.max(1, to - from)}>
                  <PhotoOverlay
                    spec={spec}
                    slide={slide}
                    isFirstPhoto={isFirstPhoto}
                  />
                </PhotoSlide>
              );
            } else if (slide.label === "features") {
              content = <FeaturesSlide spec={spec} />;
            } else {
              content = <OutroSlide spec={spec} />;
            }

            return (
              <AbsoluteFill
                key={i}
                style={{
                  display: from <= frame ? undefined : "none",
                  opacity: from <= frame ? undefined : 0,
                }}
              >
                {/* fade in/out over ~0.4s at slide edges */}
                <AbsoluteFill
                  style={{
                    display: from <= frame && frame < to ? undefined : "none",
                  }}
                >
                  {content}
                </AbsoluteFill>
              </AbsoluteFill>
            );
          })}

          <FilmGrain />
        </FontsGate>

        {/* music bed (durations are fitted to the music by render-job.mjs) */}
        <Audio src={staticFile("music.wav")} volume={(f) => {
          const fadeOut = Math.min(1, Math.max(0, (durationInFrames - f) / 30));
          return fadeOut * 0.9;
        }} />
      </AbsoluteFill>
    </ReelSpecProvider>
  );
};

/** Bundled composition entry (Studio + server render). Reads the reel spec
 *  from input props set by scripts/render-job.mjs. */
export const ReelVideo: React.FC = () => {
  const input = React.useMemo(
    () => getInputProps() as Partial<{ spec: ReelSpec; schedule: ReelTiming[]; durationInFrames: number }> | undefined,
    []
  );
  const spec = input?.spec;
  const schedule = input?.schedule ?? [];
  const durationInFrames = input?.durationInFrames ?? 30 * 24;

  if (!spec || !spec.slides || spec.slides.length === 0) {
    return (
      <AbsoluteFill
        style={{
          backgroundColor: WARM_PALETTE.surface,
          justifyContent: "center",
          alignItems: "center",
          fontFamily: FONTS.sans,
          color: WARM_PALETTE.ink,
          fontSize: 40,
          textAlign: "center",
          padding: 80,
        }}
      >
        <div>
          <div style={{ fontSize: 72, marginBottom: 20 }}>🎬</div>
          No reel spec provided. Render this composition via scripts/render-job.mjs
        </div>
      </AbsoluteFill>
    );
  }
  return (
    <ReelVideoContent
      spec={spec}
      schedule={schedule}
      durationInFrames={durationInFrames}
    />
  );
};
