import { interpolate } from 'remotion';
import { C } from '../lib/colors';
import { springIn, softSpring, clampLerp } from '../lib/easings';

// Phase 2 · 366 frames · 12.2s
//
// Beats:
//   0-85   typing (existing — character-by-character at ~20 cps)
//   85-105 hint "press Enter to build →" pops in
//   105-225  PARSE BEAT (new) — three highlights light up the prompt in
//            sequence; each gets a chip below the input that names what
//            was detected. The third chip points right with a → arrow,
//            visually foreshadowing the vault scene that follows.
//   225-310 SUMMARY PANEL (new) — three-column stats row materialises
//            under the chips: tools · secrets · targets.
//   310-354 hold
//   354-366 exit drift (existing)
//
// What this replaces: a six-second post-typing hold where only the caret
// blinked. The parse beat surfaces what the AI literally extracts from
// the prompt — concrete, supports the VO line "the AI generates the
// code — the prompt path and the secret path never cross."

// Segmented text — typing still feels continuous, but each segment can
// carry an independent highlight when the parse beat reaches it.
type HighlightKey = 'intent' | 'tool' | 'secret';

interface Segment {
  text: string;
  highlight?: HighlightKey;
}

const SEGMENTS: readonly Segment[] = [
  { text: 'Build me an ' },
  { text: 'MCP server', highlight: 'intent' },
  { text: ' that ' },
  { text: 'searches', highlight: 'tool' },
  { text: ' our ' },
  { text: 'Notion workspace', highlight: 'secret' },
  { text: '.' },
];

const PROMPT_TEXT = SEGMENTS.map((s) => s.text).join('');

// Timing constants (local frames)
const TYPE_CPS = 20; // ~1 char every 1.5 frames at 30fps
const TYPE_FRAMES_PER_CHAR = 30 / TYPE_CPS;
const TYPING_DONE_AT = PROMPT_TEXT.length * TYPE_FRAMES_PER_CHAR; // ~88
const HINT_START = TYPING_DONE_AT - 4;
const HINT_END = TYPING_DONE_AT + 10;

// Parse beat — each highlight starts when the previous chip has settled.
const PARSE_INTENT_AT = 110;
const PARSE_TOOL_AT = 145;
const PARSE_SECRET_AT = 180;
const PARSE_CHIP_DURATION = 20; // entrance duration
const HIGHLIGHT_HOLD = 90; // each highlight stays for this long after entrance

// Summary panel.
const SUMMARY_START = 230;
const SUMMARY_FULL = 270;

// "Never cross" mini-diagram — appears under the summary panel right
// at the 21 s mark in the global timeline, which is when the voice
// says "the prompt path and the secret path never cross." Visualises
// the architectural promise with two parallel arrows and a clear
// "no crossing" cross-mark between them.
const NEVER_CROSS_START = 250;   // local frame 250 ≈ global 21 s
const NEVER_CROSS_FULL = 280;

const SCENE_LEN = 366;
const EXIT_START = SCENE_LEN - 12;

// Map highlight key → its "appeared" timestamp so PromptText can colour
// the segment background once the parser hits it.
const HIGHLIGHT_AT: Record<HighlightKey, number> = {
  intent: PARSE_INTENT_AT,
  tool: PARSE_TOOL_AT,
  secret: PARSE_SECRET_AT,
};

export function PromptScene({ localFrame, fps }: { localFrame: number; fps: number }) {
  const inputIn = springIn(localFrame, fps, 0);
  const labelIn = clampLerp(localFrame, 4, 16);

  const typedChars = Math.max(0, Math.floor(localFrame / TYPE_FRAMES_PER_CHAR));
  const typingDone = localFrame >= TYPING_DONE_AT;

  // Caret blinks at 0.5 Hz once typing settles.
  const caretVisible = !typingDone || Math.floor(localFrame / 15) % 2 === 0;

  // Hint visibility — pops in once typing settles, then fades a bit
  // when the parse beat starts (less competition for attention).
  const hintIn = clampLerp(localFrame, HINT_START, HINT_END);
  const hintFade = 1 - clampLerp(localFrame, PARSE_INTENT_AT - 10, PARSE_INTENT_AT + 14) * 0.55;

  // Exit drift in the final 12 frames.
  const exitProgress = clampLerp(localFrame, EXIT_START, SCENE_LEN);
  const exitY = interpolate(exitProgress, [0, 1], [0, -52]);
  const exitScale = interpolate(exitProgress, [0, 1], [1, 0.96]);
  const enterScale = interpolate(inputIn, [0, 1], [0.92, 1]);

  return (
    <div
      style={{
        position: 'absolute',
        inset: 0,
        display: 'flex',
        flexDirection: 'column',
        alignItems: 'center',
        justifyContent: 'center',
        transform: `translateY(${exitY}px) scale(${exitScale})`,
      }}
    >
      {/* Label above input */}
      <div
        style={{
          fontFamily: 'ui-monospace, SF Mono, Menlo, monospace',
          fontSize: 18,
          letterSpacing: 4,
          textTransform: 'uppercase',
          color: C.fgSubtle,
          marginBottom: 24,
          opacity: labelIn,
          transform: `translateY(${interpolate(labelIn, [0, 1], [8, 0])}px)`,
        }}
      >
        describe your tool
      </div>

      {/* Input field — same shape as the actual product UI. */}
      <div
        style={{
          width: 1100,
          height: 92,
          borderRadius: 16,
          backgroundColor: C.bgElevated,
          border: `1px solid ${typingDone ? C.accent : C.borderStrong}`,
          boxShadow: typingDone
            ? `0 0 0 4px ${C.accentGlow}, 0 20px 60px rgba(0,0,0,0.55)`
            : `0 20px 60px rgba(0,0,0,0.55)`,
          display: 'flex',
          alignItems: 'center',
          paddingLeft: 32,
          paddingRight: 32,
          opacity: inputIn,
          transform: `scale(${enterScale})`,
        }}
      >
        <div
          style={{
            fontFamily: 'ui-monospace, SF Mono, Menlo, monospace',
            fontSize: 28,
            color: C.accent,
            marginRight: 20,
            lineHeight: 1,
          }}
        >
          ›
        </div>
        <div
          style={{
            fontFamily: 'ui-monospace, SF Mono, Menlo, monospace',
            fontSize: 28,
            color: C.fg,
            letterSpacing: 0.2,
            display: 'flex',
            alignItems: 'center',
            flex: 1,
          }}
        >
          <PromptText typedChars={typedChars} localFrame={localFrame} />
          <span
            style={{
              display: 'inline-block',
              width: 3,
              height: 32,
              backgroundColor: C.accent,
              marginLeft: 4,
              opacity: caretVisible ? 1 : 0,
              boxShadow: `0 0 10px ${C.accentGlow}`,
              borderRadius: 1,
            }}
          />
        </div>
      </div>

      {/* Hint below input */}
      <div
        style={{
          fontFamily: 'ui-monospace, SF Mono, Menlo, monospace',
          fontSize: 16,
          color: typingDone ? C.fgMuted : C.fgSubtle,
          marginTop: 24,
          opacity: hintIn * hintFade,
          transform: `translateY(${interpolate(hintIn, [0, 1], [-6, 0])}px)`,
          letterSpacing: 1,
        }}
      >
        press Enter to build  →
      </div>

      {/* Parse-beat chip row — three callouts appear in sequence, each
          tied to a highlighted segment above. The third chip points
          right with → arrow, foreshadowing the vault scene. */}
      <ChipRow localFrame={localFrame} fps={fps} />

      {/* Summary panel — three-stat row materialises after all three
          chips have landed. Tells the viewer what the AI extracted. */}
      <SummaryPanel localFrame={localFrame} fps={fps} />

      {/* "Never cross" mini-architecture diagram — appears at ≈ 21 s
          global to land precisely with the voice line "the prompt
          path and the secret path never cross." Two parallel arrows
          with a clear X-marker chip pinned between them. Compact so
          it sits under the summary panel without breaking layout. */}
      <NeverCrossMini localFrame={localFrame} fps={fps} />
    </div>
  );
}

// ---- Sub-components ----

function PromptText({
  typedChars,
  localFrame,
}: {
  typedChars: number;
  localFrame: number;
}) {
  // Render typed text segment-by-segment so each segment can carry an
  // independent highlight state. A running `consumed` counter slices the
  // single typing progress across segments — feels continuous to the
  // viewer.
  let consumed = 0;
  return (
    <>
      {SEGMENTS.map((seg, i) => {
        const segStart = consumed;
        consumed += seg.text.length;
        const visibleChars = Math.max(0, Math.min(seg.text.length, typedChars - segStart));
        if (visibleChars <= 0) return null;
        const visibleText = seg.text.slice(0, visibleChars);

        // Highlight intensity: fades in over 14 frames after its
        // chip lands, then holds bright.
        let highlightT = 0;
        if (seg.highlight) {
          const startAt = HIGHLIGHT_AT[seg.highlight];
          highlightT = clampLerp(localFrame, startAt, startAt + 14);
        }

        const hasHighlight = highlightT > 0.01;
        return (
          <span
            key={`${i}-${seg.text}`}
            style={
              hasHighlight
                ? {
                    background: `linear-gradient(180deg, transparent 55%, rgba(99,102,241,${0.22 * highlightT}) 55%)`,
                    color: C.fg,
                    padding: '0 2px',
                    borderRadius: 2,
                    whiteSpace: 'pre',
                  }
                : { whiteSpace: 'pre' }
            }
          >
            {visibleText}
          </span>
        );
      })}
    </>
  );
}

interface ChipDef {
  label: string;
  detail: string;
  startAt: number;
  trailingArrow?: boolean; // chip's right edge shows → indicating "to vault"
}

const CHIPS: readonly ChipDef[] = [
  { label: 'intent', detail: 'build server', startAt: PARSE_INTENT_AT },
  { label: 'tool', detail: 'search_pages', startAt: PARSE_TOOL_AT },
  {
    label: 'secret',
    detail: 'NOTION_API_KEY',
    startAt: PARSE_SECRET_AT,
    trailingArrow: true,
  },
];

function ChipRow({ localFrame, fps }: { localFrame: number; fps: number }) {
  const anyShowing = localFrame >= PARSE_INTENT_AT - 2;
  if (!anyShowing) return null;

  // Whole row fades out subtly when the summary panel materialises so
  // the focus shifts cleanly downward.
  const rowFade = 1 - clampLerp(localFrame, SUMMARY_FULL + 10, SUMMARY_FULL + 40) * 0.35;

  return (
    <div
      style={{
        marginTop: 18,
        display: 'flex',
        gap: 14,
        opacity: rowFade,
      }}
    >
      {CHIPS.map((chip) => {
        const t = springIn(localFrame, fps, chip.startAt);
        if (t < 0.01) return <PlaceholderSlot key={chip.label} />;
        const y = interpolate(t, [0, 1], [12, 0]);
        const isSecret = chip.label === 'secret';
        return (
          <div
            key={chip.label}
            style={{
              display: 'flex',
              alignItems: 'center',
              gap: 10,
              padding: '10px 16px',
              backgroundColor: isSecret
                ? 'rgba(99,102,241,0.14)'
                : 'rgba(99,102,241,0.06)',
              border: `1px solid ${isSecret ? C.accent : C.accentDim}`,
              borderRadius: 999,
              fontFamily: 'ui-monospace, SF Mono, Menlo, monospace',
              fontSize: 14,
              color: C.fg,
              opacity: t,
              transform: `translateY(${y}px)`,
              boxShadow: isSecret
                ? `0 0 18px rgba(99,102,241,0.30)`
                : '0 6px 18px rgba(0,0,0,0.30)',
              whiteSpace: 'nowrap',
            }}
          >
            <span
              style={{
                fontSize: 11,
                letterSpacing: 1.6,
                textTransform: 'uppercase',
                color: isSecret ? C.accent : C.fgSubtle,
              }}
            >
              {chip.label}
            </span>
            <span style={{ color: C.fgMuted }}>·</span>
            <span style={{ color: C.fg, letterSpacing: 0.3 }}>{chip.detail}</span>
            {chip.trailingArrow && (
              <span
                style={{
                  color: C.accent,
                  marginLeft: 6,
                  fontSize: 14,
                  letterSpacing: 0,
                }}
              >
                → vault
              </span>
            )}
          </div>
        );
      })}
    </div>
  );
}

// Holds the row width steady before its chip enters, so the rest of the
// layout doesn't shift as chips materialise.
function PlaceholderSlot() {
  return (
    <div
      style={{
        height: 38,
        opacity: 0,
        pointerEvents: 'none',
      }}
    />
  );
}

interface SummaryStat {
  label: string;
  value: string;
  detail: string;
}

const STATS: readonly SummaryStat[] = [
  { label: 'tools', value: '2', detail: 'search_pages, get_page_content' },
  { label: 'secrets', value: '1', detail: 'NOTION_API_KEY' },
  { label: 'targets', value: '3', detail: 'Claude · Cursor · ChatGPT' },
];

function NeverCrossMini({ localFrame, fps }: { localFrame: number; fps: number }) {
  const inT = springIn(localFrame, fps, NEVER_CROSS_START);
  if (inT < 0.01) return null;
  const fadeOut = 1 - clampLerp(localFrame, SCENE_LEN - 30, SCENE_LEN - 14);
  const opacity = clampLerp(localFrame, NEVER_CROSS_START, NEVER_CROSS_FULL) * fadeOut;
  if (opacity < 0.01) return null;

  // Stroke-on for the two parallel arrows.
  const strokeT = clampLerp(localFrame, NEVER_CROSS_START + 4, NEVER_CROSS_FULL + 10);

  return (
    <div
      style={{
        marginTop: 20,
        opacity,
        transform: `translateY(${interpolate(inT, [0, 1], [12, 0])}px)`,
      }}
    >
      <div
        style={{
          width: 1100,
          padding: '18px 32px',
          backgroundColor: 'rgba(17,17,20,0.65)',
          border: `1px dashed ${C.borderStrong}`,
          borderRadius: 14,
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'space-between',
          gap: 28,
          position: 'relative',
        }}
      >
        {/* Left rail — "prompt → AI" */}
        <NeverCrossRail
          label="prompt"
          target="AI"
          tone="accent"
          strokeT={strokeT}
        />

        {/* Centre X-marker — explicit "no crossing" stamp */}
        <div
          style={{
            display: 'flex',
            flexDirection: 'column',
            alignItems: 'center',
            gap: 6,
            flexShrink: 0,
          }}
        >
          <div
            style={{
              width: 44,
              height: 44,
              borderRadius: 22,
              border: `1.5px solid ${C.fgMuted}`,
              backgroundColor: 'rgba(17,17,20,0.85)',
              display: 'flex',
              alignItems: 'center',
              justifyContent: 'center',
              boxShadow: `0 4px 14px rgba(0,0,0,0.4)`,
            }}
          >
            <svg width="20" height="20" viewBox="0 0 20 20" fill="none">
              <path d="M 5 5 L 15 15 M 15 5 L 5 15" stroke={C.fgMuted} strokeWidth={2.2} strokeLinecap="round" />
            </svg>
          </div>
          <div
            style={{
              fontFamily: 'ui-monospace, SF Mono, Menlo, monospace',
              fontSize: 11,
              letterSpacing: 2,
              textTransform: 'uppercase',
              color: C.fgMuted,
              whiteSpace: 'nowrap',
            }}
          >
            never crosses
          </div>
        </div>

        {/* Right rail — "vault → server" */}
        <NeverCrossRail
          label="vault"
          target="server"
          tone="accent"
          strokeT={strokeT}
          mirrored
        />
      </div>
    </div>
  );
}

function NeverCrossRail({
  label,
  target,
  tone,
  strokeT,
  mirrored,
}: {
  label: string;
  target: string;
  tone: 'accent';
  strokeT: number;
  mirrored?: boolean;
}) {
  const colour = C.accent;
  // The rail is a chip → arrow → chip pattern.
  return (
    <div
      style={{
        display: 'flex',
        alignItems: 'center',
        gap: 10,
        flexDirection: mirrored ? 'row-reverse' : 'row',
        flex: 1,
        justifyContent: mirrored ? 'flex-start' : 'flex-end',
      }}
    >
      <Pill text={label} colour={colour} />
      <svg width="100" height="14" viewBox="0 0 100 14" style={{ flexShrink: 0 }}>
        <defs>
          <marker id={`ncArrow-${label}`} viewBox="0 0 10 10" refX="8" refY="5" markerWidth="6" markerHeight="6" orient={mirrored ? 'auto' : 'auto-start-reverse'}>
            <path d="M 0 0 L 10 5 L 0 10 Z" fill={colour} />
          </marker>
        </defs>
        <line
          x1={mirrored ? 90 : 6}
          y1={7}
          x2={mirrored ? 6 : 90}
          y2={7}
          stroke={colour}
          strokeWidth={1.8}
          strokeDasharray={84}
          strokeDashoffset={(1 - strokeT) * 84}
          markerEnd={`url(#ncArrow-${label})`}
        />
      </svg>
      <Pill text={target} colour={colour} />
    </div>
  );
}

function Pill({ text, colour }: { text: string; colour: string }) {
  return (
    <div
      style={{
        padding: '7px 14px',
        backgroundColor: 'rgba(99,102,241,0.10)',
        border: `1px solid ${colour}`,
        borderRadius: 999,
        fontFamily: 'ui-monospace, SF Mono, Menlo, monospace',
        fontSize: 13,
        letterSpacing: 1.5,
        textTransform: 'uppercase',
        color: C.fg,
        whiteSpace: 'nowrap',
      }}
    >
      {text}
    </div>
  );
}

function SummaryPanel({ localFrame, fps }: { localFrame: number; fps: number }) {
  const panelT = springIn(localFrame, fps, SUMMARY_START);
  if (panelT < 0.01) return null;
  const fadeOutStart = SCENE_LEN - 30;
  const fadeOut = 1 - clampLerp(localFrame, fadeOutStart, fadeOutStart + 18);

  return (
    <div
      style={{
        marginTop: 22,
        opacity: panelT * fadeOut,
        transform: `translateY(${interpolate(panelT, [0, 1], [16, 0])}px)`,
      }}
    >
      <div
        style={{
          width: 1100,
          padding: '20px 28px',
          backgroundColor: 'rgba(17,17,20,0.65)',
          border: `1px dashed ${C.borderStrong}`,
          borderRadius: 14,
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'space-between',
          gap: 28,
          backdropFilter: 'blur(2px)',
        }}
      >
        <div
          style={{
            fontFamily: 'ui-monospace, SF Mono, Menlo, monospace',
            fontSize: 11,
            letterSpacing: 3.5,
            textTransform: 'uppercase',
            color: C.fgSubtle,
            minWidth: 80,
          }}
        >
          parsed
        </div>
        {STATS.map((s, i) => {
          const colT = springIn(localFrame, fps, SUMMARY_START + 4 + i * 5);
          return (
            <div
              key={s.label}
              style={{
                flex: 1,
                opacity: colT,
                transform: `translateY(${interpolate(colT, [0, 1], [8, 0])}px)`,
                display: 'flex',
                flexDirection: 'column',
                gap: 4,
              }}
            >
              <div
                style={{
                  display: 'flex',
                  alignItems: 'baseline',
                  gap: 10,
                }}
              >
                <span
                  style={{
                    fontFamily: 'ui-monospace, SF Mono, Menlo, monospace',
                    fontSize: 11,
                    letterSpacing: 2.5,
                    textTransform: 'uppercase',
                    color: C.fgSubtle,
                  }}
                >
                  {s.label}
                </span>
                <span
                  style={{
                    fontFamily: 'ui-monospace, SF Mono, Menlo, monospace',
                    fontSize: 26,
                    fontWeight: 600,
                    color: C.accent,
                    fontVariantNumeric: 'tabular-nums',
                    letterSpacing: -0.5,
                  }}
                >
                  {s.value}
                </span>
              </div>
              <div
                style={{
                  fontFamily: 'ui-monospace, SF Mono, Menlo, monospace',
                  fontSize: 13,
                  color: C.fgMuted,
                  letterSpacing: 0.2,
                }}
              >
                {s.detail}
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
}
