/* ===========================================================================
   iRaven App Store Studio — brand tokens, device specs, templates, defaults.
   Default project brand (Socc360): "Cobalt & Amber" — cinematic stadium
   darkness. Display: Space Grotesk · Body: Inter · Numeric: JetBrains Mono.
   =========================================================================== */

const BRAND = {
  stadium1000: '#03050e',
  stadium900:  '#060a18',
  stadium800:  '#0a1124',
  stadium700:  '#101a36',
  stadium600:  '#16224a',
  stadium400:  '#27345f',
  cobalt300:   '#7aa6ff',
  cobalt400:   '#4f86ff',
  cobalt500:   '#2f6df6',
  cobalt600:   '#1f54d6',
  amber300:    '#ffd479',
  amber400:    '#ffc24b',
  amber500:    '#f5a623',
  amber600:    '#d98a12',
  pitch500:    '#1f9d55',
  pitch600:    '#157a41',
  pitch700:    '#0e5e32',
  live500:     '#ff3b46',
  ink:         '#ffffff',
  inkSoft:     'rgba(255,255,255,0.66)',
  inkFaint:    'rgba(255,255,255,0.40)',
};

// Exact App Store screenshot canvases (portrait), in real export pixels.
const DEVICES = {
  iphone: {
    id: 'iphone',
    label: 'iPhone 6.7″',
    canvas: { w: 1284, h: 2778 },     // App Store accepted size (6.7")
    screenAspect: 1179 / 2556,        // uploaded screenshots ratio
    frame: {
      radiusRatio: 0.155,             // outer corner radius / device width
      bezelRatio:  0.026,             // bezel thickness / device width
      island: true,
    },
  },
  ipad: {
    id: 'ipad',
    label: 'iPad 13″',
    canvas: { w: 2048, h: 2732 },     // App Store iPad 12.9/13" requirement
    screenAspect: 2048 / 2732,
    frame: {
      radiusRatio: 0.055,
      bezelRatio:  0.022,
      island: false,
    },
  },
  watch: {
    id: 'watch',
    label: 'Apple Watch',
    canvas: { w: 410, h: 502 },       // App Store Apple Watch (Ultra 49mm)
    screenAspect: 410 / 502,
    frame: {
      radiusRatio: 0.27,
      bezelRatio:  0.055,
      island: false,
      watch: true,
    },
  },
};

// Background treatments — data-driven layer stacks (first = base, later = on top).
const BG_DEFS = {
  stadium: ['radial-gradient(125% 92% at 50% -10%, #1a2a57 0%, #0b1326 46%, #03050e 100%)',
    'radial-gradient(60% 38% at 50% 6%, rgba(122,166,255,0.20), transparent 60%)'],
  floodlight: ['linear-gradient(0deg,#05080f,#05080f)',
    'radial-gradient(70% 50% at 16% 10%, rgba(47,109,246,0.55), transparent 62%)',
    'radial-gradient(70% 52% at 86% 94%, rgba(245,166,35,0.42), transparent 60%)'],
  cobalt: ['radial-gradient(120% 92% at 50% -4%, #2f6df6 0%, #1a3c93 36%, #060e22 100%)'],
  ember: ['linear-gradient(0deg,#0c0505,#0c0505)',
    'radial-gradient(85% 60% at 50% -8%, rgba(255,98,40,0.50), transparent 60%)',
    'radial-gradient(70% 50% at 85% 95%, rgba(255,170,60,0.25), transparent 60%)'],
  aurora: ['linear-gradient(0deg,#040a0c,#040a0c)',
    'radial-gradient(70% 55% at 25% 0%, rgba(34,211,160,0.35), transparent 60%)',
    'radial-gradient(70% 55% at 80% 25%, rgba(99,102,241,0.35), transparent 62%)',
    'radial-gradient(60% 45% at 60% 100%, rgba(34,160,211,0.22), transparent 60%)'],
  royal: ['radial-gradient(120% 90% at 50% -8%, #4c1d95 0%, #2a1065 40%, #0a0518 100%)',
    'radial-gradient(55% 40% at 50% 8%, rgba(196,160,255,0.25), transparent 60%)'],
  dawn: ['linear-gradient(0deg,#120612,#120612)',
    'radial-gradient(85% 65% at 50% 105%, rgba(244,114,182,0.40), transparent 65%)',
    'radial-gradient(70% 50% at 50% -5%, rgba(251,146,60,0.30), transparent 60%)'],
  steel: ['linear-gradient(165deg,#1a2028 0%, #0d1117 55%, #07090d 100%)',
    'radial-gradient(60% 40% at 70% 0%, rgba(148,163,184,0.18), transparent 60%)'],
  noir: ['linear-gradient(0deg,#000,#000)',
    'radial-gradient(80% 55% at 50% 0%, rgba(255,255,255,0.07), transparent 60%)'],
  minimal: ['linear-gradient(180deg,#0a0f1c,#05070f)'],
};
const bgSwatch = (id) => (BG_DEFS[id] || BG_DEFS.stadium).slice().reverse().join(', ');

const BACKGROUNDS = [
  { id: 'stadium',    label: 'Stadium',    swatch: bgSwatch('stadium') },
  { id: 'floodlight', label: 'Floodlight', swatch: bgSwatch('floodlight') },
  { id: 'pitch',      label: 'Pitch',      swatch: 'linear-gradient(180deg,#0c1a12,#06100a)' },
  { id: 'cobalt',     label: 'Cobalt',     swatch: bgSwatch('cobalt') },
  { id: 'ember',      label: 'Ember',      swatch: bgSwatch('ember') },
  { id: 'aurora',     label: 'Aurora',     swatch: bgSwatch('aurora') },
  { id: 'royal',      label: 'Royal',      swatch: bgSwatch('royal') },
  { id: 'dawn',       label: 'Dawn',       swatch: bgSwatch('dawn') },
  { id: 'steel',      label: 'Steel',      swatch: bgSwatch('steel') },
  { id: 'noir',       label: 'Noir',       swatch: bgSwatch('noir') },
  { id: 'minimal',    label: 'Minimal',    swatch: bgSwatch('minimal') },
];

const TEMPLATES = [
  { id: 'headline-top',    label: 'Headline · Top' },
  { id: 'headline-bottom', label: 'Headline · Bottom' },
  { id: 'angled',          label: 'Angled hero' },
  { id: 'callouts',        label: 'Feature callouts' },
  { id: 'split',           label: 'Split band' },
  { id: 'fan',             label: 'Fan · 2 screens' },
  { id: 'duo',             label: 'Duo devices' },
  { id: 'companion',       label: 'Device + Watch' },
  { id: 'full-bleed',      label: 'Full bleed' },
  { id: 'poster',          label: 'Poster' },
  { id: 'big-stat',        label: 'Big statement' },
];

/* per-slide finishing controls (photo) */
const DEV_SIZES = [
  { id: 'sm', label: 'S', scale: 0.88 },
  { id: 'md', label: 'M', scale: 1.0 },
  { id: 'lg', label: 'L', scale: 1.12 },
];
const TILTS = [
  { id: -8, label: '-8°' }, { id: 0, label: '0°' }, { id: 8, label: '+8°' },
];
const GLOWS = [
  { id: 0, label: 'Off' }, { id: 0.5, label: 'Soft' }, { id: 1, label: 'Strong' },
];

/* video motion pacing */
const SPEEDS = [
  { id: 0.75, label: 'Calm' }, { id: 1, label: 'Normal' }, { id: 1.3, label: 'Fast' },
];

/* ---------- App Preview (video) specs — official App Store sizes ---------- */
const VIDEO_DEVICES = {
  iphone: { id: 'iphone', label: 'iPhone 6.5″', canvas: { w: 886,  h: 1920 } },
  ipad:   { id: 'ipad',   label: 'iPad 13″',   canvas: { w: 1200, h: 1600 } },
};

const VIDEO_TEMPLATES = [
  { id: 'rise',      label: 'Rise' },
  { id: 'reveal',    label: 'Reveal · zoom out' },
  { id: 'punch',     label: 'Punch · pop in' },
  { id: 'sweep',     label: 'Sweep' },
  { id: 'drift',     label: 'Drift' },
  { id: 'tilt',      label: 'Tilt sway' },
  { id: 'orbit',     label: 'Orbit' },
  { id: 'zoomline',  label: 'Slow zoom' },
  { id: 'risefan',   label: 'Fan rise · 2' },
  { id: 'showcase',  label: 'Showcase · 3 shots' },
  { id: 'duo',       label: 'Duo devices' },
  { id: 'companion', label: 'Device + Watch' },
  { id: 'spotlight', label: 'Spotlight' },
  { id: 'pulse',     label: 'Pulse · full bleed' },
];

const VIDEO_DURATIONS = [
  { id: 15, label: '15s' },
  { id: 20, label: '20s' },
  { id: 30, label: '30s' },
];

function isVideoPath(s) { return typeof s === 'string' && /\.(mp4|mov|webm)(\?|$)/i.test(s); }

/* ===========================================================================
   Scene-timeline model (App Previews).
   A preview = ordered list of SCENES. Each scene holds one media item (image
   or video) shown inside a device frame or full-bleed, for a chosen duration,
   with its own ENTER and EXIT animation (type · duration · easing). Videos use
   their own length; images use a chosen on-screen duration. One soundtrack is
   shared across the whole preview. Multiple previews can be stitched into one
   longer export.
   =========================================================================== */

/* entrance/exit motions — p:0 = hidden, p:1 = fully present (identity).
   x,y are fractions of canvas w/h; s = scale; r = degrees. */
const SCENE_ANIMS = [
  { id: 'fade',       label: 'Fade' },
  { id: 'rise',       label: 'Rise' },
  { id: 'slideUp',    label: 'Slide ↑' },
  { id: 'slideDown',  label: 'Slide ↓' },
  { id: 'slideLeft',  label: 'Slide ←' },
  { id: 'slideRight', label: 'Slide →' },
  { id: 'zoomIn',     label: 'Zoom in' },
  { id: 'zoomOut',    label: 'Zoom out' },
  { id: 'pop',        label: 'Pop' },
  { id: 'tilt',       label: 'Tilt in' },
  { id: 'none',       label: 'Cut' },
];

const SCENE_EASES = [
  { id: 'out',   label: 'Smooth' },
  { id: 'inOut', label: 'Glide' },
  { id: 'outBack', label: 'Spring' },
  { id: 'linear', label: 'Linear' },
];

/* durations available for the in/out animations (seconds) */
const ANIM_DURS = [
  { id: 0.3, label: '0.3s' }, { id: 0.5, label: '0.5s' }, { id: 0.8, label: '0.8s' },
  { id: 1.2, label: '1.2s' }, { id: 1.8, label: '1.8s' },
];

/* p:0 = hidden, p:1 = present. `amt` scales motion (1 = element just fully
   clears the frame edge; that's the slider max so it never travels pointlessly
   far off-canvas). Fade/cut ignore amt. */
function sceneAnimState(type, p, amt) {
  const e = Math.min(1, Math.max(0, p));
  const a = Math.max(0, amt == null ? 1 : amt);
  const d = 1 - e;
  switch (type) {
    case 'none':       return { o: e < 0.5 ? 0 : 1, x: 0, y: 0, s: 1, r: 0 };
    case 'fade':       return { o: e, x: 0, y: 0, s: 1, r: 0 };
    case 'rise':       return { o: e, x: 0, y: d * 0.16 * a, s: 1 - 0.05 * a * d, r: 0 };
    case 'slideUp':    return { o: e, x: 0, y: d * 1.0 * a, s: 1, r: 0 };
    case 'slideDown':  return { o: e, x: 0, y: -d * 1.0 * a, s: 1, r: 0 };
    case 'slideLeft':  return { o: e, x: d * 1.0 * a, y: 0, s: 1, r: 0 };
    case 'slideRight': return { o: e, x: -d * 1.0 * a, y: 0, s: 1, r: 0 };
    case 'zoomIn':     return { o: e, x: 0, y: 0, s: 1 - 0.5 * a * d, r: 0 };
    case 'zoomOut':    return { o: e, x: 0, y: 0, s: 1 + 0.6 * a * d, r: 0 };
    case 'pop':        return { o: Math.min(1, e * 1.6), x: 0, y: 0, s: Math.max(0.05, 1 - 0.7 * a * d), r: 0 };
    case 'tilt':       return { o: e, x: 0, y: d * 0.1 * a, s: 1 - 0.04 * a * d, r: d * -12 * a };
    default:           return { o: e, x: 0, y: 0, s: 1, r: 0 };
  }
}

let __sceneSeq = 0;
function sceneUid() { return 's' + Date.now().toString(36) + (__sceneSeq++).toString(36) + Math.random().toString(36).slice(2, 5); }

function makeScene(o) {
  return Object.assign({
    id: sceneUid(),
    media: null,            // image dataURL/path string, or {kind:'image'|'video', key, name}
    mediaDur: null,         // measured length for video media (seconds)
    layout: 'device',       // 'device' | 'fullbleed'
    dur: 2,                 // on-screen seconds for images (videos use mediaDur)
    headline: '', subtitle: '', titleSize: 'md',
    captionPos: 'top',      // 'top' | 'bottom' | 'none'
    enter: { type: 'rise', dur: 0.7, ease: 'out', dist: 1 },
    exit:  { type: 'fade', dur: 0.5, ease: 'in', dist: 1 },
  }, o);
}

/* a scene's total on-screen time (videos clamp to their own measured length) */
function sceneDuration(sc) {
  if (sc.media && (typeof sc.media === 'object' ? sc.media.kind === 'video' : window.isVideoPath(sc.media))) {
    return Math.max(1.2, sc.mediaDur || sc.dur || 3);
  }
  return Math.max(0.8, sc.dur || 2);
}

function previewDuration(preview) {
  const body = (preview.scenes || []).reduce((a, sc) => a + sceneDuration(sc), 0);
  return +(body + (preview.outro !== false ? 2.4 : 0)).toFixed(2);
}

/* migrate a legacy template-based video into the scene model */
function videoToScenes(v) {
  if (v && v.scenes) return v;   // already new model
  const slots = (v && v.images) || [];
  const scenes = [];
  slots.forEach((m, i) => {
    if (!m) return;
    scenes.push(makeScene({
      media: m,
      headline: i === 0 ? (v.headline || '') : '',
      subtitle: i === 0 ? (v.subtitle || '') : '',
      titleSize: v.titleSize || 'md',
      dur: 3,
      enter: { type: i === 0 ? 'rise' : 'slideLeft', dur: 0.7, ease: 'out' },
      exit:  { type: 'fade', dur: 0.5, ease: 'in' },
    }));
  });
  if (!scenes.length) {
    scenes.push(makeScene({ headline: (v && v.headline) || 'Your app,\nin motion.',
      subtitle: (v && v.subtitle) || 'One short supporting line.', dur: 3 }));
  }
  return {
    device: (v && v.device) || 'iphone',
    bg: (v && v.bg) || 'stadium',
    accent: (v && v.accent) || 'brand1',
    outro: v ? v.outro !== false : true,
    audio: (v && v.audio) || null,
    name: (v && v.name) || '',
    scenes,
  };
}

function makeDefaultVideos() {
  return [
    { device: 'iphone', bg: 'stadium', accent: 'cobalt', outro: true, audio: null, name: 'Matchday',
      scenes: [
        makeScene({ media: 'assets/rec-1.mp4', headline: 'Matchday,\nlive.',
          subtitle: 'Scores the instant they happen.', enter: { type: 'rise', dur: 0.8, ease: 'outBack' }, exit: { type: 'zoomOut', dur: 0.5, ease: 'in' } }),
        makeScene({ media: 'assets/shot-stats.png', headline: 'Every angle.', dur: 2.4,
          enter: { type: 'slideLeft', dur: 0.6, ease: 'out' }, exit: { type: 'fade', dur: 0.5, ease: 'in' } }),
        makeScene({ media: 'assets/rec-2.mp4', headline: 'Built for\nfans.', captionPos: 'bottom',
          enter: { type: 'fade', dur: 0.6, ease: 'out' }, exit: { type: 'fade', dur: 0.5, ease: 'in' } }),
      ] },
  ];
}

function makeBlankVideos() {
  return [
    { device: 'iphone', bg: 'stadium', accent: 'brand1', outro: true, audio: null, name: 'Preview 01',
      scenes: [
        makeScene({ headline: 'Your app,\nin motion.', subtitle: 'One short supporting line.', dur: 3 }),
        makeScene({ headline: 'Feature two.', layout: 'device', dur: 2.4,
          enter: { type: 'slideLeft', dur: 0.6, ease: 'out' } }),
      ] },
  ];
}

const ACCENTS = [
  { id: 'cobalt', label: 'Cobalt', color: BRAND.cobalt400 },
  { id: 'amber',  label: 'Amber',  color: BRAND.amber500 },
];

/* ---------- multi-app brand support ---------- */
window.CURRENT_BRAND = window.CURRENT_BRAND || {
  name: 'Socc360', tagline: 'Football from every angle.',
  accent1: '#4f86ff', accent2: '#f5a623',
};

function resolveAccent(id) {
  const B = window.CURRENT_BRAND || {};
  if (id === 'amber') return BRAND.amber500;
  if (id === 'brand1') return B.accent1 || BRAND.cobalt400;
  if (id === 'brand2') return B.accent2 || BRAND.amber500;
  return BRAND.cobalt400; // cobalt / default
}

function getAccentOptions() {
  const B = window.CURRENT_BRAND || {};
  const opts = [{ id: 'cobalt', label: 'Cobalt' }, { id: 'amber', label: 'Amber' }];
  if (B.accent1) opts.push({ id: 'brand1', label: 'Brand 1' });
  if (B.accent2) opts.push({ id: 'brand2', label: 'Brand 2' });
  return opts;
}

/* split a brand name for two-tone rendering ("Socc"+"360", else whole name) */
function splitBrandName(name) {
  const m = String(name || 'App').match(/^([^\d]*)(.*)$/);
  return [m[1], m[2]];
}

const TITLE_SIZES = [
  { id: 'sm', label: 'S', scale: 0.78 },
  { id: 'md', label: 'M', scale: 1.0 },
  { id: 'lg', label: 'L', scale: 1.22 },
];

// 10 default slides seeded from the app's real features.
// Only slide 1 ships with the uploaded home screenshot; rest are slots.
function makeDefaultSlides() {
  const s = (o) => Object.assign({
    device: 'iphone',
    template: 'headline-top',
    bg: 'stadium',
    accent: 'cobalt',
    titleSize: 'md',
    headline: '',
    subtitle: '',
    callouts: '',
    image: null,
    image2: null,
  }, o);

  return [
    s({ headline: 'Every match.\nOne place.', subtitle: 'Today, this week, every league — at a glance.',
        template: 'headline-top', bg: 'stadium', accent: 'cobalt',
        image: 'assets/home-screenshot.png' }),
    s({ headline: 'Live, the second\nit happens.', subtitle: 'Real-time scores with momentum signals.',
        template: 'angled', bg: 'floodlight', accent: 'amber',
        image: 'assets/shot-live-home.png' }),
    s({ headline: 'The whole\nstory.', subtitle: 'Goals, cards and subs on one clean timeline.',
        template: 'callouts', bg: 'stadium', accent: 'cobalt',
        callouts: 'Live timeline\nKey moments\nMatch stats',
        image: 'assets/shot-timeline.png' }),
    s({ headline: 'Know before\nkickoff.', subtitle: 'Win signals for every fixture.',
        template: 'split', bg: 'ember', accent: 'amber',
        image: 'assets/shot-signals.png' }),
    s({ headline: 'Stats that\ngo deep.', subtitle: 'Shots, possession, fouls — side by side.',
        template: 'duo', bg: 'steel', accent: 'cobalt',
        image: 'assets/shot-stats.png', image2: 'assets/shot-overview.png' }),
    s({ headline: 'Full lineups,\nreal faces.', subtitle: 'Every starter, every position, every photo.',
        template: 'headline-bottom', bg: 'royal', accent: 'amber',
        image: 'assets/shot-lineups.png' }),
    s({ headline: 'Know every\nteam.', subtitle: 'Squads, fixtures, results and seasons.',
        template: 'angled', bg: 'pitch', accent: 'cobalt',
        image: 'assets/shot-team.png' }),
    s({ headline: 'Match day,\ncovered.', subtitle: 'From kickoff to full time — every detail.',
        template: 'fan', bg: 'floodlight', accent: 'amber',
        image: 'assets/shot-overview.png', image2: 'assets/shot-live-lineups.png' }),
    s({ headline: 'Football,\nnot a feed.', subtitle: 'Intelligence, not noise.',
        template: 'poster', bg: 'noir', accent: 'cobalt',
        image: 'assets/shot-live-lineups.png' }),
    s({ headline: 'Football from\nevery angle.', subtitle: 'Independent. Clean. Built for fans.',
        template: 'big-stat', bg: 'stadium', accent: 'amber',
        image: 'assets/home-screenshot.png' }),
  ];
}

/* Resolve asset paths that may be provided by the standalone bundler */
function resolveAsset(src) {
  if (typeof src === 'string' && window.__resources && window.__resources.homeShot
      && src.indexOf('home-screenshot') !== -1) return window.__resources.homeShot;
  return src;
}

Object.assign(window, { DEV_SIZES, TILTS, GLOWS, SPEEDS, isVideoPath });

function makeBlankSlides() {
  const s = (o) => Object.assign({
    device: 'iphone', template: 'headline-top', bg: 'stadium', accent: 'brand1',
    titleSize: 'md', headline: '', subtitle: '', callouts: '', image: null, image2: null,
  }, o);
  return [
    s({ headline: 'Your headline\nhere.', subtitle: 'One short supporting line.' }),
    s({ headline: 'Feature two.', template: 'angled', bg: 'steel', accent: 'brand2' }),
    s({ headline: 'Feature three.', template: 'poster', bg: 'noir' }),
  ];
}

Object.assign(window, {
  BRAND, DEVICES, BACKGROUNDS, BG_DEFS, TEMPLATES, ACCENTS, TITLE_SIZES, makeDefaultSlides,
  VIDEO_DEVICES, VIDEO_TEMPLATES, VIDEO_DURATIONS, makeDefaultVideos, resolveAsset,
  resolveAccent, getAccentOptions, splitBrandName, makeBlankSlides, makeBlankVideos,
  SCENE_ANIMS, SCENE_EASES, ANIM_DURS, sceneAnimState, makeScene, sceneUid,
  sceneDuration, previewDuration, videoToScenes,
});
