// portfolio-shared.jsx
// Shared data, Vimeo oEmbed fetcher, hover-preview component, sub-brand list.
// Exposed on window for cross-file babel scope.

// ──────────────────────────────────────────────────────────────
// Project seed data — placeholders the user can replace by pasting Vimeo URLs.
// Each project has a deterministic gradient so the grid looks intentional
// before any real video is added.
// ──────────────────────────────────────────────────────────────
const SEED_PROJECTS = [
  { id: 'p01', title: 'Nocturne',     client: 'Aesop',         role: 'Director / DP',   year: 2025, runtime: '3:14', brand: 'CINESTEEL', tag: 'Brand Film',    vimeoId: null, hue: 8 },
  { id: 'p02', title: 'Drift',        client: 'Porsche',       role: 'Director',        year: 2025, runtime: '1:42', brand: 'FULLMETAL', tag: 'Campaign',      vimeoId: null, hue: 0 },
  { id: 'p03', title: 'Quiet Hours',  client: 'Le Labo',       role: 'Director / Edit', year: 2024, runtime: '2:08', brand: 'CINESTEEL', tag: 'Brand Film',    vimeoId: null, hue: 18 },
  { id: 'p04', title: 'Foundry',      client: 'Filson',        role: 'Director / DP',   year: 2024, runtime: '4:21', brand: 'FULLMETAL', tag: 'Documentary',   vimeoId: null, hue: 25 },
  { id: 'p05', title: 'Heatwave',     client: 'Carhartt WIP',  role: 'Director',        year: 2024, runtime: '0:60', brand: 'CINESTEEL', tag: 'Spot',          vimeoId: null, hue: 15 },
  { id: 'p06', title: 'Ember',        client: 'Hermès',        role: 'Director / DP',   year: 2024, runtime: '2:55', brand: 'CINESTEEL', tag: 'Brand Film',    vimeoId: null, hue: 12 },
  { id: 'p07', title: 'Static',       client: 'Sonos',         role: 'Director',        year: 2024, runtime: '1:15', brand: 'FULLMETAL', tag: 'Product Film',  vimeoId: null, hue: 350 },
  { id: 'p08', title: 'Coastline',    client: 'Patagonia',     role: 'Director / Edit', year: 2023, runtime: '5:42', brand: 'FULLMETAL', tag: 'Documentary',   vimeoId: null, hue: 20 },
  { id: 'p09', title: 'Soft Power',   client: 'Glossier',      role: 'Director',        year: 2023, runtime: '1:00', brand: 'CINESTEEL', tag: 'Spot',          vimeoId: null, hue: 355 },
  { id: 'p10', title: 'Volume',       client: 'Bose',          role: 'Director / DP',   year: 2023, runtime: '2:30', brand: 'FULLMETAL', tag: 'Product Film',  vimeoId: null, hue: 5 },
  { id: 'p11', title: 'Long Take',    client: 'A24',           role: 'Director / DP',   year: 2023, runtime: '7:14', brand: 'CINESTEEL', tag: 'Short Film',    vimeoId: null, hue: 358 },
  { id: 'p12', title: 'Halftone',     client: 'Vans',          role: 'Director',        year: 2023, runtime: '1:30', brand: 'CINESTEEL', tag: 'Campaign',      vimeoId: null, hue: 22 },
  { id: 'p13', title: 'Apparatus',    client: 'Leica',         role: 'Director / DP',   year: 2022, runtime: '3:00', brand: 'FULLMETAL', tag: 'Product Film',  vimeoId: null, hue: 350 },
  { id: 'p14', title: 'Slow Burn',    client: 'Buck Mason',    role: 'Director',        year: 2022, runtime: '2:12', brand: 'CINESTEEL', tag: 'Brand Film',    vimeoId: null, hue: 30 },
  { id: 'p15', title: 'Outlands',     client: 'Yeti',          role: 'DP',              year: 2022, runtime: '6:30', brand: 'FULLMETAL', tag: 'Documentary',   vimeoId: null, hue: 10 },
  { id: 'p16', title: 'Currents',     client: 'Acne Studios',  role: 'Director',        year: 2021, runtime: '1:55', brand: 'CINESTEEL', tag: 'Campaign',      vimeoId: null, hue: 350 },
  { id: 'p17', title: 'Ironwork',     client: 'Polestar',      role: 'Director / DP',   year: 2021, runtime: '2:42', brand: 'FULLMETAL', tag: 'Brand Film',    vimeoId: null, hue: 0 },
];

const SUB_BRANDS = [
  { id: 'fullmetal', name: 'FULLMETAL', href: 'https://fullmetal.store',  tagline: 'Industrial, automotive, motorsport. Heavy machinery and the people who run it.', focus: 'Direction · Production' },
  { id: 'cinesteel', name: 'CINESTEEL', href: 'https://cinesteel.studio', tagline: 'Narrative, brand films, and editorial commissions. Patient cameras.',           focus: 'Direction · Cinematography' },
];

// Services are grouped into three categories per the studio's offering:
// Video Work, Graphic Design, Clothing.
const SERVICES = [
  {
    k: '01', title: 'Video Work', tag: 'Film · Motion · Editorial',
    body: 'End-to-end direction, cinematography, and post. Brand films, campaigns, documentary, narrative shorts, and product film.',
    items: [
      { name: 'Direction',          note: 'Brand films, campaign, narrative.' },
      { name: 'Cinematography',     note: 'Anamorphic · ARRI Alexa · handheld.' },
      { name: 'Editorial & Post',   note: 'Offline edit, color, sound — in-house.' },
      { name: 'Motion & Title',     note: 'End-frames, mnemonics, title design.' },
    ],
  },
  {
    k: '02', title: 'Graphic Design', tag: 'Identity · Print · Digital',
    body: 'Brand systems, campaign keylines, and editorial-grade print. Built to extend across film, web, and physical goods.',
    items: [
      { name: 'Brand Systems',      note: 'Marks, type, motion bibles.' },
      { name: 'Campaign Keylines',  note: 'Print, OOH, social adaptation.' },
      { name: 'Editorial Design',   note: 'Books, lookbooks, press kits.' },
      { name: 'Digital & Web',      note: 'Microsites, presskits, drops.' },
    ],
  },
  {
    k: '03', title: 'Clothing', tag: 'Merch · Crew · Capsules',
    body: 'Custom apparel for clients, premieres, and crews. From single-run premiere tees to small capsule collections developed with the brand team.',
    items: [
      { name: 'Crew & Premiere',    note: 'Single-run film crew apparel.' },
      { name: 'Capsule Collections',note: 'Co-developed with brand teams.' },
      { name: 'Sourcing & Mfg',     note: 'Portugal, LA, NY shops.' },
      { name: 'Packaging',          note: 'Inserts, hangtags, hardware.' },
    ],
  },
];

// Team — each member has a list of projects they personally worked on, with
// the specific role they held on that project ("role on this film").
// `email` is the address copied by the LET'S WORK button on each member page.
// `portrait` (data URL or image URL) is the headshot — left empty by default;
// admin uploads via the admin panel.
const TEAM = [
  {
    id: 'richard', name: 'Richard Santos', title: 'Director / DP · Founder', hue: 0,
    email: 'richard@armature.studio', portrait: '',
    bio: 'Directs and shoots brand films, narrative, and editorial. Built ARMATURE around small crews and patient cameras.',
    projects: [
      { projectId: 'p01', role: 'Director · DP' },
      { projectId: 'p02', role: 'Director' },
      { projectId: 'p06', role: 'Director · DP' },
      { projectId: 'p11', role: 'Director · DP' },
      { projectId: 'p13', role: 'Director · DP' },
      { projectId: 'p17', role: 'Director · DP' },
    ],
  },
  {
    id: 'maya', name: 'Maya Okafor', title: 'Producer · EP', hue: 12,
    email: 'maya@armature.studio', portrait: '',
    bio: 'Runs production across both brands — bidding, talent, locations, post management.',
    projects: [
      { projectId: 'p02', role: 'Producer' },
      { projectId: 'p04', role: 'Line Producer' },
      { projectId: 'p05', role: 'Producer' },
      { projectId: 'p08', role: 'EP' },
      { projectId: 'p11', role: 'Producer' },
      { projectId: 'p17', role: 'EP' },
    ],
  },
  {
    id: 'lucas', name: 'Lucas Reyes', title: 'Editor · Post Lead', hue: 8,
    email: 'lucas@armature.studio', portrait: '',
    bio: 'Heads offline edit and post coordination — long-form narrative, brand films, and spots.',
    projects: [
      { projectId: 'p03', role: 'Editor' },
      { projectId: 'p07', role: 'Editor' },
      { projectId: 'p08', role: 'Editor · Story' },
      { projectId: 'p12', role: 'Editor' },
      { projectId: 'p14', role: 'Editor' },
    ],
  },
  {
    id: 'ana', name: 'Ana Mendes', title: 'Composer · Sound Design', hue: 350,
    email: 'ana@armature.studio', portrait: '',
    bio: 'Original score, sound design, and mix. Score-led films a specialty.',
    projects: [
      { projectId: 'p01', role: 'Composer · Sound' },
      { projectId: 'p09', role: 'Sound Design' },
      { projectId: 'p10', role: 'Composer' },
      { projectId: 'p15', role: 'Composer · Sound' },
    ],
  },
  {
    id: 'jin', name: 'Jin Park', title: 'Colorist', hue: 20,
    email: 'jin@armature.studio', portrait: '',
    bio: 'Colorist on staff. DaVinci, Baselight; deep narrative and high-end commercial finishing.',
    projects: [
      { projectId: 'p06', role: 'Colorist' },
      { projectId: 'p04', role: 'Colorist' },
      { projectId: 'p11', role: 'Colorist' },
      { projectId: 'p13', role: 'Colorist' },
    ],
  },
  {
    id: 'sofia', name: 'Sofia Vargas', title: 'Graphic & Brand Design', hue: 355,
    email: 'sofia@armature.studio', portrait: '',
    bio: 'Leads graphic design across both brands — keylines, end-frames, packaging, and merch design.',
    projects: [
      { projectId: 'p05', role: 'Title · Keyline' },
      { projectId: 'p07', role: 'Brand System' },
      { projectId: 'p12', role: 'Title Design' },
      { projectId: 'p04', role: 'Packaging · Merch' },
    ],
  },
];

// Clients are split into two columns: independent CREATORS the studio
// collaborates with, and BRANDS / clients commissioned by. Each entry carries
// an optional `logo` (image URL) and `link` — both editable from the Tweaks
// panel so Richard can swap in real headshots / brand marks and outbound URLs
// without touching code.
const CREATORS = [
  { name: 'Casey Neistat',  logo: '', link: 'https://www.youtube.com/@CaseyNeistat' },
  { name: 'Marques Brownlee', logo: '', link: 'https://www.youtube.com/@mkbhd' },
  { name: 'Emma Chamberlain', logo: '', link: 'https://www.instagram.com/emmachamberlain' },
  { name: 'Peter McKinnon', logo: '', link: 'https://www.youtube.com/@PeterMcKinnon' },
  { name: 'Yes Theory',     logo: '', link: 'https://www.youtube.com/@yestheory' },
  { name: 'Matti Haapoja',  logo: '', link: 'https://www.youtube.com/@MattiHaapoja' },
];

const BRANDS = [
  { name: 'Aesop',          logo: '', link: 'https://www.aesop.com' },
  { name: 'A24',            logo: '', link: 'https://a24films.com' },
  { name: 'Hermès',         logo: '', link: 'https://www.hermes.com' },
  { name: 'Porsche',        logo: '', link: 'https://www.porsche.com' },
  { name: 'Sonos',          logo: '', link: 'https://www.sonos.com' },
  { name: 'Patagonia',      logo: '', link: 'https://www.patagonia.com' },
  { name: 'Leica',          logo: '', link: 'https://leica-camera.com' },
  { name: 'Carhartt WIP',   logo: '', link: 'https://www.carhartt-wip.com' },
  { name: 'Acne Studios',   logo: '', link: 'https://www.acnestudios.com' },
  { name: 'Polestar',       logo: '', link: 'https://www.polestar.com' },
];

// Managed — brands ARMATURE helps run end-to-end (production, Shopify, ops).
const MANAGED_SEED = [
  { name: 'Ironclad Co.', logo: '', link: 'https://ironclad.co' },
  { name: 'Steelworks',   logo: '', link: 'https://steelworks.studio' },
];

// Sub-brand clients — fully owned and operated by ARMATURE.
const SUB_BRAND_CLIENTS_SEED = [
  { name: 'FULLMETAL', logo: '', link: 'https://fullmetal.store' },
  { name: 'CINESTEEL', logo: '', link: 'https://cinesteel.studio' },
];

// Back-compat — anything still importing CLIENTS gets the merged list.
const CLIENTS = [...CREATORS, ...BRANDS].map(c => c.name);

const PRESS_AWARDS = [
  { year: 2025, body: 'AICP Show — Direction',        outcome: 'Honoree' },
  { year: 2024, body: '1.4 Awards — Cinematography',   outcome: 'Silver' },
  { year: 2024, body: 'It’s Nice That — Spotlight',    outcome: 'Feature' },
  { year: 2023, body: 'Vimeo Staff Picks',             outcome: '×3' },
];

// Navigation links — editable from the admin panel so Richard can swap the
// store URL or point the sub-brand chips somewhere else without touching code.
// Keys map onto the live site's nav (Store) and the FULLMETAL / CINESTEEL
// chips that appear in the top bar and footer.
const NAV_LINKS = {
  store:     'https://fullmetal.store',
  fullmetal: 'https://fullmetal.store',
  cinesteel: 'https://cinesteel.studio',
  instagram: 'https://instagram.com/armature.studio',
};

// ──────────────────────────────────────────────────────────────
// Vimeo helpers
// ──────────────────────────────────────────────────────────────
function parseVimeoId(input) {
  if (!input) return null;
  const s = String(input).trim();
  if (/^\d{6,12}$/.test(s)) return s;
  const m = s.match(/vimeo\.com\/(?:video\/|channels\/[^/]+\/|groups\/[^/]+\/videos\/|album\/\d+\/video\/)?(\d{6,12})/i);
  return m ? m[1] : null;
}

async function fetchVimeoMeta(input) {
  const id = parseVimeoId(input);
  if (!id) throw new Error('Not a recognizable Vimeo URL or ID');
  const url = 'https://vimeo.com/api/oembed.json?url=' + encodeURIComponent('https://vimeo.com/' + id);
  const r = await fetch(url);
  if (!r.ok) throw new Error('Vimeo lookup failed (' + r.status + ')');
  const j = await r.json();
  return {
    vimeoId: id,
    title: j.title || 'Untitled',
    author: j.author_name || '',
    runtime: secondsToClock(j.duration || 0),
    thumb: (j.thumbnail_url || '').replace(/_\d+x\d+/, '_1280x720'),
    year: new Date().getFullYear(),
  };
}

function secondsToClock(s) {
  s = Math.max(0, Math.floor(s));
  const m = Math.floor(s / 60), r = s % 60;
  return m + ':' + String(r).padStart(2, '0');
}

function vimeoEmbed(id, { background = false, autoplay = false, controls = true, loop = false, muted = false } = {}) {
  const p = new URLSearchParams();
  if (background) { p.set('background', '1'); p.set('autoplay', '1'); p.set('loop', '1'); p.set('muted', '1'); }
  else {
    if (autoplay) p.set('autoplay', '1');
    if (muted) p.set('muted', '1');
    if (loop) p.set('loop', '1');
    if (!controls) p.set('controls', '0');
  }
  p.set('dnt', '1');
  return 'https://player.vimeo.com/video/' + id + '?' + p.toString();
}

// ──────────────────────────────────────────────────────────────
// YouTube helpers — mirror the Vimeo API surface.
// ──────────────────────────────────────────────────────────────
function parseYouTubeId(input) {
  if (!input) return null;
  const s = String(input).trim();
  if (/^[A-Za-z0-9_-]{11}$/.test(s)) return s;
  const m = s.match(/(?:youtube\.com\/(?:watch\?v=|embed\/|shorts\/|v\/)|youtu\.be\/)([A-Za-z0-9_-]{11})/);
  return m ? m[1] : null;
}

async function fetchYouTubeMeta(input) {
  const id = parseYouTubeId(input);
  if (!id) throw new Error('Not a recognizable YouTube URL or ID');
  // YouTube oEmbed is CORS-allowed and key-less. Duration isn't returned, so
  // runtime stays blank; admin can fill it in by hand if it matters.
  const url = 'https://www.youtube.com/oembed?url=' +
    encodeURIComponent('https://www.youtube.com/watch?v=' + id) + '&format=json';
  const r = await fetch(url);
  if (!r.ok) throw new Error('YouTube lookup failed (' + r.status + ')');
  const j = await r.json();
  return {
    source: 'youtube',
    videoId: id,
    title: j.title || 'Untitled',
    author: j.author_name || '',
    runtime: '',
    thumb: 'https://img.youtube.com/vi/' + id + '/maxresdefault.jpg',
    year: new Date().getFullYear(),
  };
}

// Unified meta lookup — picks YouTube first (its URL pattern is distinct),
// else falls through to Vimeo (which handles bare numeric IDs too).
async function fetchVideoMeta(input) {
  if (parseYouTubeId(input)) return fetchYouTubeMeta(input);
  const v = await fetchVimeoMeta(input);
  return { source: 'vimeo', videoId: v.vimeoId, ...v };
}

function youTubeEmbed(id, { background = false, autoplay = false, controls = true, loop = false, muted = false } = {}) {
  const p = new URLSearchParams();
  if (background) {
    p.set('autoplay', '1'); p.set('mute', '1'); p.set('loop', '1');
    p.set('controls', '0'); p.set('playlist', id);
  } else {
    if (autoplay) p.set('autoplay', '1');
    if (muted) p.set('mute', '1');
    if (loop) { p.set('loop', '1'); p.set('playlist', id); }
    if (!controls) p.set('controls', '0');
  }
  p.set('rel', '0'); p.set('modestbranding', '1');
  return 'https://www.youtube.com/embed/' + id + '?' + p.toString();
}

function projectVideoId(p) { return p.youtubeId || p.vimeoId || p.videoId || null; }
function projectIsYouTube(p) { return p.source === 'youtube' || !!p.youtubeId; }
function projectHasVideo(p) { return !!projectVideoId(p); }

function videoEmbedFor(project, opts) {
  if (projectIsYouTube(project)) return youTubeEmbed(project.youtubeId || project.videoId, opts);
  return vimeoEmbed(project.vimeoId || project.videoId, opts);
}

// ──────────────────────────────────────────────────────────────
// Deterministic gradient placeholder — used when a project has no Vimeo id.
// Looks like an intentional poster, not a blank tile.
// ──────────────────────────────────────────────────────────────
function placeholderBg(hue, dark = true) {
  const a = dark ? 18 : 96;
  const b = dark ? 7 : 90;
  return [
    'radial-gradient(120% 80% at 20% 20%, oklch(' + (a + 8) + '% 0.05 ' + hue + ') 0%, transparent 55%)',
    'radial-gradient(110% 90% at 80% 90%, oklch(' + a + '% 0.04 ' + ((hue + 40) % 360) + ') 0%, transparent 60%)',
    'linear-gradient(180deg, oklch(' + a + '% 0.02 ' + hue + ') 0%, oklch(' + b + '% 0.01 ' + hue + ') 100%)',
  ].join(', ');
}

// ──────────────────────────────────────────────────────────────
// HoverPreview — a tile that swaps a placeholder for a muted background Vimeo
// iframe on hover. Iframe is mounted lazily and torn down on mouse-out so the
// grid stays cheap.
// ──────────────────────────────────────────────────────────────
function HoverPreview({ project, dark = true, children, style, onClick, eager = false }) {
  const [hover, setHover] = React.useState(false);
  const [armed, setArmed] = React.useState(false);
  const t = React.useRef(null);
  React.useEffect(() => () => clearTimeout(t.current), []);

  function enter() {
    setHover(true);
    clearTimeout(t.current);
    t.current = setTimeout(() => setArmed(true), 180);
  }
  function leave() {
    setHover(false);
    clearTimeout(t.current);
    t.current = setTimeout(() => setArmed(false), 250);
  }

  const hasVideo = projectHasVideo(project);
  const showIframe = (armed && hasVideo) || (eager && hasVideo);

  return (
    <div
      onMouseEnter={enter}
      onMouseLeave={leave}
      onClick={onClick}
      style={{
        position: 'relative', overflow: 'hidden', cursor: onClick ? 'pointer' : 'default',
        background: placeholderBg(project.hue, dark),
        ...style,
      }}
    >
      {hasVideo && project.thumb && (
        <img
          src={project.thumb}
          alt=""
          style={{
            position: 'absolute', inset: 0, width: '100%', height: '100%',
            objectFit: 'cover',
            opacity: hover ? 0 : 1,
            transition: 'opacity .3s ease',
            filter: dark ? 'brightness(.85) contrast(1.05)' : 'none',
          }}
        />
      )}
      {showIframe && (
        <iframe
          key={projectVideoId(project)}
          src={videoEmbedFor(project, { background: true })}
          style={{
            position: 'absolute', inset: 0, width: '100%', height: '100%',
            border: 0, pointerEvents: 'none',
            opacity: hover ? 1 : 0,
            transition: 'opacity .35s ease',
          }}
          allow="autoplay; fullscreen"
          allowFullScreen
        />
      )}
      {children}
    </div>
  );
}

Object.assign(window, {
  SEED_PROJECTS, SUB_BRANDS, SERVICES, CLIENTS, CREATORS, BRANDS, MANAGED_SEED, SUB_BRAND_CLIENTS_SEED, PRESS_AWARDS, TEAM, NAV_LINKS,
  parseVimeoId, fetchVimeoMeta, secondsToClock, vimeoEmbed, placeholderBg,
  parseYouTubeId, fetchYouTubeMeta, fetchVideoMeta, youTubeEmbed,
  videoEmbedFor, projectVideoId, projectIsYouTube, projectHasVideo,
  HoverPreview,
});
