import type { SurfaceProps } from "../spec.js";
import { defineFilm, defineRig } from "../spec.js";
import { defineAction } from "../adapters.js";
import { compileFilm } from "../compile.js";
import { FilmSpecStage } from "../stage.js";
import { EASING, ramp } from "../motion.js";

type Product = { label: string };
type Event = { at: number; kind: "publish" };
type View = { published: boolean; progress: number };
/** Replace this component with your own React product screen. */
function ProductScreen({ instance, view, localTime }: SurfaceProps<View>) {
  const enter = ramp(localTime, .1, 1.1, EASING.out);
  return <div style={{ width: "100%", height: "100%", boxSizing: "border-box", background: "#141719", borderRadius: 38, padding: 64, fontFamily: "ui-sans-serif, system-ui, sans-serif", color: "#f4f6f3", boxShadow: "0 30px 80px #1525242a", transform: `translateY(${(1 - enter) * 40}px)` }}>
    <div style={{ fontSize: 24, color: "#9ba8a2" }}>Product update</div>
    <h1 style={{ fontSize: 76, lineHeight: 1.05, letterSpacing: "-.055em", margin: "58px 0 32px", fontWeight: 600 }}>{String(instance.init?.label)}</h1>
    <div style={{ marginTop: 78, padding: 38, borderRadius: 22, border: "1px solid #38453e", background: "#212c25" }}>
      <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", fontSize: 27 }}><span>New release</span><span style={{ color: "#c0e9a8" }}>{view.published ? "Published ✓" : "Draft"}</span></div>
      <div style={{ height: 12, background: "#3b4940", borderRadius: 6, marginTop: 40, overflow: "hidden" }}><div style={{ height: "100%", width: `${view.progress * 100}%`, background: "#c0e9a8" }} /></div>
    </div>
    <div style={{ marginTop: 60, fontSize: 32, color: "#c0e9a8", opacity: view.progress }}>Your customers can use it now.</div>
  </div>;
}
export const productRig = defineRig<Product, Event, View>({
  parseInit(input) {
    if (!input || typeof input !== "object" || !("label" in input) || typeof input.label !== "string" || !input.label.trim()) throw new Error("A product label is required.");
    return { label: input.label };
  },
  actions: {
    publish: defineAction(
      input => { if (!input || typeof input !== "object" || Object.keys(input).length) throw new Error("publish takes no arguments."); return {}; },
      at => [{ at, kind: "publish" as const }],
      () => ({ after: 1.2 }),
    ),
  },
  fold: (_init, events) => time => {
    const event = events.find(e => e.at <= time);
    return { published: !!event, progress: event ? ramp(time, event.at, event.at + 1.2, EASING.out) : 0 };
  },
  Surface: ProductScreen,
});
export const productReactSpec = defineFilm({
  id: "product-react", fps: 30,
  stage: { w: 1080, h: 1350, bg: "#e9eee6" },
  scenes: [{
    id: "publish", claim: "A draft becomes a published product update.", min: 6,
    rigs: [{ id: "product", rig: "product-screen", slot: { x: 60, y: 175, w: 960, h: 1000 }, init: { label: "A small update. A better product." }, entrance: { kind: "none" } }],
    events: [{ id: "published", target: "product", action: "publish", at: 2.4 }],
    camera: { moves: [{ to: "product", at: .3, over: 1.4, s: 1.03 }] },
    narration: "Publish the update. Your customers can use it now.", holds: { settled: true },
  }],
});
export const productReactFilm = compileFilm(productReactSpec, { adapters: { "product-screen": productRig } });
export function ProductReactStory() { return <FilmSpecStage film={productReactFilm} />; }
