// movie-library.jsx - Movie mode screens, cards, search, detail, and import modal.

const MOVIE_FILTERS = [
  { id: 'all', label: 'All' },
  { id: 'want_to_watch', label: 'Want to watch' },
  { id: 'watched', label: 'Watched' },
  { id: 'favorite', label: 'Favorites' },
  { id: 'rewatch', label: 'Rewatch' },
  { id: 'top_rated', label: 'Top rated' },
  { id: 'missing', label: 'Missing details' },
];

function LibraryModeSwitch({ mode = 'jav', onChange, accent }) {
  const modeMeta = {
    jav: { glow: '#ff2d8d', tint: `${accent}14` },
    movie: { glow: '#f59e0b', tint: '#f59e0b20' },
  };
  return (
    <div style={{ padding: '0 16px 12px', paddingLeft: 'max(16px, env(safe-area-inset-left))', paddingRight: 'max(16px, env(safe-area-inset-right))' }}>
      <div style={{
        display: 'grid',
        gridTemplateColumns: '1fr 1fr',
        gap: 4,
        padding: 4,
        borderRadius: 14,
        background: 'rgba(255,255,255,0.055)',
        border: `0.5px solid ${window.VH_HAIRLINE}`,
        backdropFilter: 'blur(18px) saturate(150%)',
        boxShadow: '0 10px 34px rgba(0,0,0,0.28), inset 0 1px 0 rgba(255,255,255,0.08)',
      }}>
        {[{ id: 'jav', label: 'JAV' }, { id: 'movie', label: 'Movies' }].map(opt => {
          const active = mode === opt.id;
          const meta = modeMeta[opt.id];
          return (
            <button
              key={opt.id}
              onClick={() => onChange?.(opt.id)}
              className="vh-tap"
              style={{
                height: 34,
                borderRadius: 10,
                border: active ? `0.5px solid ${meta.glow}99` : '0.5px solid transparent',
                background: active ? `linear-gradient(180deg, ${meta.glow}30, ${meta.tint})` : 'transparent',
                color: active ? '#fff' : window.VH_DIM,
                fontSize: 12.5,
                fontWeight: 800,
                letterSpacing: 0,
                cursor: 'pointer',
                transition: 'background 180ms, color 180ms, box-shadow 180ms, border 180ms',
                boxShadow: active ? `0 0 18px ${meta.glow}66, inset 0 1px 0 rgba(255,255,255,0.12)` : 'none',
              }}>
              {opt.label}
            </button>
          );
        })}
      </div>
    </div>
  );
}

function MovieLibraryScreen({ items, locked, accent, onOpenVideo, onOpenAdd, onOpenBestRated, loading, mode, onModeChange }) {
  const [filter, setFilter] = React.useState('all');
  const [sort, setSort] = React.useState('release');
  const [layout, setLayout] = React.useState('compact');
  const visible = React.useMemo(() => filterAndSortMovies(items, filter, sort), [items, filter, sort]);
  return (
    <div style={{ paddingBottom: 140 }}>
      <window.TopBar
        topPad={locked.topPad}
        title="Movie Library"
        subtitle={`${items.length} saved`}
        locked={locked.value}
        onToggleLock={locked.signedIn ? null : locked.toggle}
        accent={accent}
        right={<MovieLayoutToggle layout={layout} onChange={setLayout}/>}
      />
      <LibraryModeSwitch mode={mode} onChange={onModeChange} accent={accent}/>
      <MovieFilterRail filter={filter} setFilter={setFilter} sort={sort} setSort={setSort} accent={accent} items={items}/>
      {loading ? (
        <MovieGrid loading accent={accent} layout={layout}/>
      ) : visible.length === 0 ? (
        <MovieEmptyState accent={accent} signedIn={locked.signedIn} onOpenAuth={locked.openAuth} onAdd={onOpenAdd}/>
      ) : (
        layout === 'list'
          ? <MovieRowList items={visible} locked={locked.value} accent={accent} onClick={onOpenVideo}/>
          : <MovieGrid items={visible} locked={locked.value} accent={accent} onClick={onOpenVideo} layout={layout}/>
      )}
    </div>
  );
}

function MovieSearchScreen({ items, locked, accent, onOpenVideo, mode, onModeChange }) {
  const [q, setQ] = React.useState('');
  const [filter, setFilter] = React.useState('all');
  const results = React.useMemo(() => {
    const term = q.trim().toLowerCase();
    return filterAndSortMovies(items, filter, 'release').filter(it => {
      if (!term) return true;
      return [
        it.movieTitle,
        it.originalTitle,
        it.director,
        ...(it.actors || []),
        ...(it.genres || []),
      ].some(v => String(v || '').toLowerCase().includes(term));
    });
  }, [items, q, filter]);
  return (
    <div style={{ paddingBottom: 140 }}>
      <window.TopBar title="Movie Search" subtitle={`${results.length} results`} locked={locked.value} onToggleLock={locked.signedIn ? null : locked.toggle} accent={accent}/>
      <LibraryModeSwitch mode={mode} onChange={onModeChange} accent={accent}/>
      <div style={{ padding: '0 16px' }}>
        <MovieSearchBox value={q} onChange={setQ} placeholder="Search title, actors, director, genres"/>
      </div>
      <MovieFilterRail filter={filter} setFilter={setFilter} accent={accent} items={items} compact/>
      {results.length === 0 ? (
        <MovieSimpleState accent={accent} title="No results" detail="Try another title, actor, director, or genre."/>
      ) : (
        <MovieRowList items={results} locked={locked.value} accent={accent} onClick={onOpenVideo}/>
      )}
    </div>
  );
}

function MovieBestRatedScreen({ items, locked, accent, onBack, onOpenVideo }) {
  const ranked = React.useMemo(() => filterAndSortMovies(items, 'top_rated', 'rating'), [items]);
  return (
    <div style={{ paddingBottom: 120 }}>
      <MovieSubHeader title="Best Rated Movies" subtitle={`${ranked.length} rated titles`} accent={accent} onBack={onBack}/>
      {locked.value ? <MovieSimpleState accent={accent} title="Locked" detail="Sign in to see your private movie ratings."/> :
        ranked.length === 0 ? <MovieSimpleState accent={accent} title="No ratings yet" detail="Rate a few movies and your best list will appear here."/> :
        <MovieGrid items={ranked} locked={false} accent={accent} onClick={onOpenVideo}/>}
    </div>
  );
}

function MovieBookmarksScreen({ items, locked, accent, onBack, onOpenVideo }) {
  const [filter, setFilter] = React.useState('all');
  const saved = React.useMemo(() => (items || []).filter(window.isVideoSaved), [items]);
  const visible = React.useMemo(() => filterAndSortMovies(saved, filter, 'release'), [saved, filter]);
  return (
    <div style={{ paddingBottom: 120 }}>
      <MovieSubHeader title="Movie Bookmarks" subtitle={`${saved.length} saved titles`} accent={accent} onBack={onBack}/>
      {locked.value ? (
        <MovieSimpleState accent={accent} title="Locked" detail="Sign in to manage movie bookmarks."/>
      ) : (
        <>
          <MovieFilterRail filter={filter} setFilter={setFilter} accent={accent} items={saved} compact/>
          {visible.length === 0
            ? <MovieSimpleState accent={accent} title="No bookmarks" detail="Saved movies will appear here."/>
            : <MovieGrid items={visible} locked={false} accent={accent} onClick={onOpenVideo}/>}
        </>
      )}
    </div>
  );
}

function MovieDetailScreen({ videoId, items, locked, accent, uid, onBack, onEditVideo, onDeleted, onOpenVideo }) {
  const item = (items || []).find(v => v.id === videoId);
  const [busy, setBusy] = React.useState(false);
  const [trailerOpen, setTrailerOpen] = React.useState(false);
  const [lightbox, setLightbox] = React.useState(null);
  const [savingTmdb, setSavingTmdb] = React.useState(null);
  const [refreshing, setRefreshing] = React.useState(false);
  const { t } = window.VHi18n.useT();
  React.useEffect(() => {
    if (!item || !uid || locked.value || !item.tmdbId || refreshing) return;
    const hasRich = (item.cast || []).length || (item.backdrops || []).length || (item.recommendations || []).length || item.trailerUrl;
    if (hasRich) return;
    let cancelled = false;
    setRefreshing(true);
    window.VHMovieMetadata.detail({ id: item.tmdbId, type: item.movieType, uid })
      .then(doc => {
        if (cancelled) return;
        const keepUser = {
          status: item.status,
          rating: item.rating,
          personalRating: item.personalRating,
          note: item.note,
          watchedAt: item.watchedAt || null,
        };
        return window.VHFirebase.updateVideo(uid, item.id, { ...doc, ...keepUser, contentType: 'movie' });
      })
      .catch(() => {})
      .finally(() => { if (!cancelled) setRefreshing(false); });
    return () => { cancelled = true; };
  }, [item?.id, item?.tmdbId, item?.movieType, uid, locked.value]);
  if (!item) return <MovieSimpleState accent={accent} title="Not found" detail="This movie is no longer in your library."/>;
  const directors = movieCrewNames(item, ['Director', 'Creator']) || item.director;
  const writers = movieCrewNames(item, ['Writer', 'Screenplay', 'Story']) || item.writer;
  const gallery = movieGalleryItems(item);
  const related = [...(item.recommendations || []), ...(item.similar || [])].filter((it, idx, arr) => it.tmdbId && arr.findIndex(x => x.tmdbId === it.tmdbId) === idx).slice(0, 18);
  const metaLine = [item.year || 'Unknown', item.runtimeMinutes ? `${item.runtimeMinutes} min` : '', item.releaseDate || ''].filter(Boolean).join(' - ');
  const setStatus = async (status) => {
    if (!uid) return;
    await window.VHFirebase.updateVideo(uid, item.id, {
      contentType: 'movie',
      status,
      watchedAt: status === 'watched' ? Date.now() : item.watchedAt || null,
    });
  };
  const remove = async () => {
    if (!uid || !confirm('Delete this movie from your library?')) return;
    setBusy(true);
    try {
      await window.VHFirebase.deleteVideo(uid, item.id);
      onDeleted?.();
    } finally {
      setBusy(false);
    }
  };
  const saveRelated = async (movie) => {
    if (!uid || !movie?.tmdbId) return;
    const existing = (items || []).find(v => Number(v.tmdbId) === Number(movie.tmdbId) && v.movieType === movie.movieType);
    if (existing) { onOpenVideo?.(existing.id); return; }
    setSavingTmdb(movie.tmdbId);
    try {
      const doc = await window.VHMovieMetadata.detail({ id: movie.tmdbId, type: movie.movieType, uid });
      const id = await window.VHFirebase.addVideo(uid, { ...doc, status: 'want_to_watch', rating: 0, personalRating: 0, contentType: 'movie' });
      onOpenVideo?.(id);
    } finally {
      setSavingTmdb(null);
    }
  };
  return (
    <div style={{ paddingBottom: 130, background: '#09090c', minHeight: '100%' }}>
      <div style={{ position: 'relative', minHeight: 470, overflow: 'hidden' }}>
        <MovieBackdrop item={item} accent={accent}/>
        <div style={{ position: 'relative', padding: '18px 16px 24px', paddingTop: 'max(18px, env(safe-area-inset-top))' }}>
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
            <button onClick={onBack} className="vh-tap" style={movieRoundBtnStyle()}>
              <svg width="16" height="16" viewBox="0 0 16 16"><path d="M10 3 5 8l5 5" stroke="currentColor" strokeWidth="1.7" fill="none" strokeLinecap="round" strokeLinejoin="round"/></svg>
            </button>
            {!locked.value && <button onClick={() => onEditVideo?.(item)} className="vh-tap" style={{ ...movieRoundBtnStyle(), width: 74, borderRadius: 99, fontSize: 12, fontWeight: 800 }}>{t('common.edit', 'Edit')}</button>}
          </div>
          <div style={{ display: 'grid', gridTemplateColumns: 'minmax(112px, 34vw) 1fr', gap: 16, alignItems: 'end', marginTop: 135 }}>
            <div style={{ maxWidth: 158, filter: locked.value ? 'blur(5px)' : 'none' }}><MoviePoster item={item} locked={locked.value} accent={accent}/></div>
            <div style={{ minWidth: 0 }}>
              <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap', marginBottom: 8 }}>
                <span style={movieBadgeStyle(accent)}>{item.movieType === 'series' ? 'Series' : 'Movie'}</span>
                {item.status && item.status !== 'skip' && <window.StatusPill status={item.status} compact/>}
                {item.collectionName && <span style={movieBadgeStyle('#c084fc')}>{item.collectionName}</span>}
              </div>
              <h1 style={{ margin: 0, color: '#fff', fontSize: 31, lineHeight: 1.02, fontWeight: 900, letterSpacing: 0 }}>
                {locked.value ? 'Locked' : item.movieTitle}
              </h1>
              {item.tagline && !locked.value && <div style={{ marginTop: 8, color: 'rgba(255,255,255,0.74)', fontSize: 13.5, lineHeight: 1.35, fontStyle: 'italic' }}>{item.tagline}</div>}
              <div style={{ marginTop: 9, color: 'rgba(255,255,255,0.70)', fontSize: 12.5 }}>{metaLine}</div>
              {!locked.value && <div style={{ marginTop: 9 }}><window.RatingStars value={item.rating || 0} accent={accent} size={13}/></div>}
              {!locked.value && item.trailerUrl && <button onClick={() => setTrailerOpen(true)} style={{ ...moviePrimaryBtnStyle(accent), width: 'auto', height: 40, padding: '0 16px', marginTop: 13, flex: 'none' }}>{t('movieDetail.watchTrailer', 'Watch Trailer')}</button>}
            </div>
          </div>
        </div>
      </div>
      <div style={{ padding: '18px 16px 0', marginTop: -18, position: 'relative' }}>
        {!locked.value && (
          <>
            <MovieSectionTitle title={t('movieDetail.yourShelf', 'Your Shelf')}/>
            <div style={movieGlassStyle()}>
              <div style={{ display: 'grid', gridTemplateColumns: 'repeat(5, 1fr)', gap: 5 }}>
              {[
                { id: 'want_to_watch' },
                { id: 'favorite' },
                { id: 'watched' },
                { id: 'rewatch' },
                { id: 'skip' },
              ].map(s => {
                const m = window.STATUS_META[s.id];
                const active = item.status === s.id;
                const label = window.VHi18n.t('status.' + s.id + '.short', m?.short || m?.label || s.id);
                return (
                  <button key={s.id} onClick={() => setStatus(s.id)} style={movieStatusButtonStyle(active, m)}>
                    <window.StatusGlyph icon={m?.icon} color={active ? m?.accent : window.VH_DIM} compact={false}/>
                    <span style={{ fontSize: 10, fontWeight: 650, lineHeight: 1, color: active ? m?.accent : window.VH_DIM, whiteSpace: 'nowrap' }}>{label}</span>
                  </button>
                );
              })}
              </div>
              <div style={{ marginTop: 12 }}><MovieRating value={item.rating || item.personalRating || 0} accent={accent} onChange={rating => window.VHFirebase.updateVideo(uid, item.id, { rating, personalRating: rating, contentType: 'movie' })}/></div>
            </div>
          </>
        )}
        <MovieSectionTitle title={t('movieDetail.overview', 'Overview')}/>
        <div style={movieGlassStyle()}>
          <div style={{ color: window.VH_TEXT, fontSize: 14, lineHeight: 1.62, filter: locked.value ? 'blur(5px)' : 'none' }}>{item.overview || 'No overview yet.'}</div>
          <MovieChipLine label="Genres" values={item.genres} locked={locked.value}/>
          <MovieInfoGrid item={{ ...item, director: directors, writer: writers }} locked={locked.value}/>
        </div>
        <MovieCastRail cast={item.cast} actors={item.actors} locked={locked.value} title={t('movieDetail.cast', 'Top Billed Cast')}/>
        <MovieWatchProviders data={item.watchProviders} locked={locked.value} title={t('movieDetail.watchProviders', 'Watch Providers')}/>
        <MovieChipLine label={t('movieDetail.keywords', 'Keywords')} values={item.keywords} locked={locked.value}/>
        <MovieGallery items={gallery} locked={locked.value} onOpen={setLightbox} title={t('movieDetail.gallery', 'Gallery')}/>
        <MovieRelatedRail items={related} libraryItems={items} locked={locked.value} accent={accent} savingTmdb={savingTmdb} onOpenVideo={onOpenVideo} onSave={saveRelated} title={t('movieDetail.recommended', 'Recommended')} saveLabel={t('common.save', 'Save')}/>
        <MovieExternalLinks item={item} accent={accent}/>
        {!locked.value && (
          <div style={{ display: 'flex', gap: 8, marginTop: 18 }}>
            <button onClick={remove} disabled={busy} style={movieDangerBtnStyle()}>{busy ? t('common.deleting', 'Deleting...') : t('common.delete', 'Delete')}</button>
          </div>
        )}
      </div>
      {trailerOpen && <MovieTrailerModal item={item} onClose={() => setTrailerOpen(false)}/>}
      {lightbox && <MovieLightbox image={lightbox} onClose={() => setLightbox(null)}/>}
    </div>
  );
}

function MovieAddModal({ open, onClose, uid, items, accent, onSaved, onOpenVideo, mode = 'add', initialVideo = null }) {
  const [tab, setTab] = React.useState('search');
  const [query, setQuery] = React.useState('');
  const [year, setYear] = React.useState('');
  const [type, setType] = React.useState('multi');
  const [sourceUrl, setSourceUrl] = React.useState('');
  const [results, setResults] = React.useState([]);
  const [page, setPage] = React.useState(1);
  const [hasMore, setHasMore] = React.useState(false);
  const [busy, setBusy] = React.useState(false);
  const [err, setErr] = React.useState('');
  const [form, setForm] = React.useState(null);

  React.useEffect(() => {
    if (!open) {
      setTab('search'); setQuery(''); setYear(''); setType('multi'); setSourceUrl('');
      setResults([]); setPage(1); setHasMore(false); setBusy(false); setErr(''); setForm(null);
      return;
    }
    if (mode === 'edit' && initialVideo) {
      setForm(window.normalizeMovieItem(initialVideo));
      setTab('review');
    }
  }, [open, mode, initialVideo?.id]);

  React.useEffect(() => {
    if (!open || tab !== 'search' || mode === 'edit') return;
    const q = query.trim();
    if (q.length < 2) {
      setResults([]);
      setHasMore(false);
      return;
    }
    const handle = setTimeout(() => runSearch(1, false), 360);
    return () => clearTimeout(handle);
  }, [query, year, type, tab, open]);

  if (!open) return null;

  async function runSearch(nextPage = 1, append = false) {
    setBusy(true); setErr('');
    try {
      const data = await window.VHMovieMetadata.search({ query, year, type, page: nextPage, uid });
      setResults(append ? [...results, ...(data.results || [])] : (data.results || []));
      setPage(data.page || nextPage);
      setHasMore(Boolean(data.hasMore));
    } catch (e) {
      setErr(window.VHMovieMetadata.friendlyMovieError(e));
    } finally {
      setBusy(false);
    }
  }

  async function selectResult(result) {
    setBusy(true); setErr('');
    try {
      const doc = await window.VHMovieMetadata.detail({ id: result.tmdbId, type: result.movieType, uid });
      setForm({ ...doc, status: 'want_to_watch', rating: 0, personalRating: 0 });
      setTab('review');
    } catch (e) {
      setErr(window.VHMovieMetadata.friendlyMovieError(e));
    } finally {
      setBusy(false);
    }
  }

  async function quickImport() {
    setBusy(true); setErr('');
    try {
      const doc = await window.VHMovieMetadata.importUrl({ sourceUrl, uid });
      setForm({ ...doc, status: 'want_to_watch', rating: 0, personalRating: 0, sourceUrl });
      setTab('review');
    } catch (e) {
      setErr(window.VHMovieMetadata.friendlyMovieError(e));
      setForm(blankMovieForm(sourceUrl));
      setTab('review');
    } finally {
      setBusy(false);
    }
  }

  async function save() {
    if (!form?.movieTitle?.trim()) { setErr('Movie title is required.'); return; }
    setBusy(true); setErr('');
    try {
      const rating = Number(form.rating || form.personalRating || 0) || 0;
      const payload = { ...form, contentType: 'movie', movieTitle: form.movieTitle.trim(), title: form.movieTitle.trim(), rating, personalRating: rating };
      if (mode === 'edit' && initialVideo?.id) await window.VHFirebase.updateVideo(uid, initialVideo.id, payload);
      else {
        const id = await window.VHFirebase.addVideo(uid, payload);
        onOpenVideo?.(id);
      }
      onSaved?.();
      onClose();
    } catch {
      setErr('Save failed. Please try again.');
    } finally {
      setBusy(false);
    }
  }

  return (
    <MovieModalShell onClose={onClose}>
      <div style={{ padding: '20px 20px 28px' }}>
        <MovieModalHeader title={mode === 'edit' ? 'Edit Movie' : tab === 'review' ? 'Review & Save' : 'Add Movie'} kicker={tab === 'search' ? 'Smart Search' : tab === 'quick' ? 'Quick Import' : 'Metadata'} onClose={onClose}/>
        {mode !== 'edit' && tab !== 'review' && (
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 6, padding: 4, borderRadius: 12, background: 'rgba(255,255,255,0.05)', border: `0.5px solid ${window.VH_HAIRLINE}` }}>
            <button onClick={() => setTab('search')} style={movieTabBtnStyle(tab === 'search', accent)}>Smart Search</button>
            <button onClick={() => setTab('quick')} style={movieTabBtnStyle(tab === 'quick', accent)}>Quick Import</button>
          </div>
        )}
        {tab === 'search' && (
          <div style={{ marginTop: 14 }}>
            <MovieField label="Movie / Series title" value={query} onChange={setQuery} placeholder="Interstellar, Breaking Bad, The Batman 2022"/>
            <div style={{ display: 'flex', gap: 8 }}>
              <MovieField flex label="Year" value={year} onChange={setYear} placeholder="2022"/>
              <MovieSelect label="Type" value={type} onChange={setType} options={[['multi','All'], ['movie','Movie'], ['series','Series']]}/>
            </div>
            {err && <MovieError>{err}</MovieError>}
            {busy && results.length === 0 ? <MovieResultSkeleton/> : <MovieSearchResults results={results} busy={busy} accent={accent} onSelect={selectResult}/>}
            {hasMore && <button onClick={() => runSearch(page + 1, true)} disabled={busy} style={{ ...moviePrimaryBtnStyle(accent), width: '100%', marginTop: 12 }}>{busy ? 'Loading...' : 'Load more'}</button>}
          </div>
        )}
        {tab === 'quick' && (
          <div style={{ marginTop: 14 }}>
            <MovieField label="Source URL" type="url" value={sourceUrl} onChange={setSourceUrl} placeholder="IMDb, TMDb, or Rotten Tomatoes URL"/>
            {sourceUrl && <div style={{ marginTop: 8 }}><span style={movieBadgeStyle(accent)}>{window.VHMovieMetadata.detectMovieSource(sourceUrl) || 'Source'}</span></div>}
            {err && <MovieError>{err}</MovieError>}
            <div style={{ display: 'flex', gap: 8, marginTop: 18 }}>
              <button onClick={() => { setForm(blankMovieForm(sourceUrl)); setTab('review'); }} style={movieSecondaryBtnStyle()}>Manual</button>
              <button onClick={quickImport} disabled={busy || !sourceUrl.trim()} style={{ ...moviePrimaryBtnStyle(accent), opacity: busy || !sourceUrl.trim() ? 0.55 : 1 }}>{busy ? 'Fetching...' : 'Fetch'}</button>
            </div>
          </div>
        )}
        {tab === 'review' && form && (
          <MovieReviewForm form={form} setForm={setForm} err={err} busy={busy} accent={accent} onBack={() => mode === 'edit' ? onClose() : setTab('search')} onSave={save}/>
        )}
      </div>
    </MovieModalShell>
  );
}

function filterAndSortMovies(items, filter, sort) {
  let out = [...(items || [])];
  if (filter === 'want_to_watch') out = out.filter(v => v.status === 'want_to_watch' || v.status === 'want');
  if (filter === 'watched') out = out.filter(v => v.status === 'watched');
  if (filter === 'favorite') out = out.filter(v => v.status === 'favorite');
  if (filter === 'rewatch') out = out.filter(v => v.status === 'rewatch');
  if (filter === 'top_rated') out = out.filter(v => (v.rating || v.personalRating || 0) > 0);
  if (filter === 'missing') out = out.filter(window.hasMissingVideoDetails);
  if (sort === 'rating' || filter === 'top_rated') {
    out.sort((a, b) => (b.rating || b.personalRating || 0) - (a.rating || a.personalRating || 0) || window.getVideoSortDate(b) - window.getVideoSortDate(a));
  } else {
    out.sort((a, b) => window.getVideoSortDate(b) - window.getVideoSortDate(a));
  }
  return out;
}

function MovieFilterRail({ filter, setFilter, sort, setSort, accent, items, compact }) {
  return (
    <div style={{ display: 'flex', gap: 8, padding: compact ? '12px 16px 10px' : '4px 16px 14px', overflowX: 'auto', scrollbarWidth: 'none' }}>
      {MOVIE_FILTERS.map(f => {
        const count = f.id === 'all' ? items.length : filterAndSortMovies(items, f.id, 'release').length;
        if (f.id !== 'all' && count === 0) return null;
        return <MovieChip key={f.id} active={filter === f.id} onClick={() => setFilter(f.id)} accent={accent}>{f.label}{f.id === 'all' ? ` - ${count}` : ''}</MovieChip>;
      })}
      {setSort && <MovieChip active={sort === 'rating'} onClick={() => setSort(sort === 'rating' ? 'release' : 'rating')} accent={accent}>{sort === 'rating' ? 'Best Rated' : 'Newest'}</MovieChip>}
    </div>
  );
}

function MovieGrid({ items = [], locked, accent, onClick, loading, layout = 'compact' }) {
  const compact = layout === 'compact';
  if (loading) {
    return <div className={compact ? 'vh-video-grid-compact' : 'vh-video-grid'}>{Array.from({ length: 8 }).map((_, i) => <div key={i}><div className="vh-skel" style={{ aspectRatio: compact ? '147 / 200' : '2/3', borderRadius: 12 }}/><div className="vh-skel" style={{ height: 10, width: '85%', marginTop: 8 }}/></div>)}</div>;
  }
  return (
    <div className={compact ? 'vh-video-grid-compact' : 'vh-video-grid'}>
      {items.map(it => <MovieCard key={it.id} item={it} locked={locked} accent={accent} onClick={() => onClick?.(it.id)} compact={compact}/>)}
    </div>
  );
}

function MovieCard({ item, locked, accent, onClick, compact = false }) {
  return (
    <button onClick={onClick} className="vh-tap vh-card" style={{ minWidth: 0, background: 'transparent', border: 'none', padding: 0, color: window.VH_TEXT, textAlign: 'left', cursor: 'pointer' }}>
      <div style={{ position: 'relative' }}>
        <MoviePoster item={item} locked={locked} accent={accent} ratio={compact ? '147 / 200' : '2 / 3'}/>
        {!locked && item.status && item.status !== 'skip' && <div style={{ position: 'absolute', bottom: 8, right: 8 }}><window.StatusPill status={item.status} compact/></div>}
      </div>
      <div style={{ marginTop: compact ? 5 : 7 }}>
        <div style={{ fontSize: compact ? 10.5 : 12.5, fontWeight: 750, color: window.VH_TEXT, lineHeight: compact ? 1.18 : 1.2, minHeight: compact ? 24 : 30, overflow: 'hidden', display: '-webkit-box', WebkitLineClamp: 2, WebkitBoxOrient: 'vertical', filter: locked ? 'blur(5px)' : 'none' }}>{item.movieTitle}</div>
        <div style={{ marginTop: 4, color: window.VH_DIM, fontSize: compact ? 9.5 : 10.5, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', filter: locked ? 'blur(5px)' : 'none' }}>{item.year || 'Unknown'} - {(item.sourceBadges || ['Movie'])[0]}</div>
        {!compact && !locked && <div style={{ marginTop: 5 }}><window.RatingStars value={item.rating || 0} accent={accent} size={11}/></div>}
      </div>
    </button>
  );
}

function MovieRowList({ items, locked, accent, onClick }) {
  return <div style={{ padding: '4px 12px' }}>{items.map(it => (
    <button key={it.id} onClick={() => onClick?.(it.id)} className="vh-tap" style={{ display: 'flex', gap: 12, width: '100%', padding: '10px 4px', background: 'transparent', border: 'none', borderBottom: `0.5px solid ${window.VH_HAIRLINE}`, color: window.VH_TEXT, textAlign: 'left', cursor: 'pointer' }}>
      <div style={{ width: 54, flexShrink: 0 }}><MoviePoster item={it} locked={locked} accent={accent}/></div>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ fontSize: 14, fontWeight: 750, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', filter: locked ? 'blur(5px)' : 'none' }}>{it.movieTitle}</div>
        <div style={{ fontSize: 12, color: window.VH_DIM, marginTop: 3, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', filter: locked ? 'blur(5px)' : 'none' }}>{it.year || 'Unknown'} - {(it.genres || []).slice(0, 2).join(', ')}</div>
        <div style={{ marginTop: 6, display: 'flex', alignItems: 'center', gap: 8 }}>{it.status !== 'skip' && <window.StatusPill status={it.status} compact/>}<window.RatingStars value={it.rating || 0} accent={accent} size={11}/></div>
      </div>
    </button>
  ))}</div>;
}

function MoviePoster({ item, locked, accent, ratio = '2 / 3' }) {
  const url = item.posterUrl || item.thumbnailUrl || '';
  return (
    <div style={{ aspectRatio: ratio, borderRadius: 12, overflow: 'hidden', background: moviePlaceholder(item, accent), border: `0.5px solid ${window.VH_HAIRLINE}`, boxShadow: '0 14px 28px rgba(0,0,0,0.28)' }}>
      {url && !locked ? <img src={url} alt="" loading="lazy" style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }} onError={e => { e.currentTarget.style.display = 'none'; }}/> :
        <div style={{ width: '100%', height: '100%', display: 'flex', alignItems: 'flex-end', padding: 10, color: '#fff', fontSize: 11, fontWeight: 850, letterSpacing: 0, filter: locked ? 'blur(4px)' : 'none' }}>{(item.movieTitle || 'MOVIE').slice(0, 18)}</div>}
    </div>
  );
}

function MovieBackdrop({ item, accent }) {
  const url = item.backdropUrl || (item.backdrops || [])[0] || item.posterUrl || '';
  return (
    <div style={{ position: 'absolute', inset: 0, background: moviePlaceholder(item, accent) }}>
      {url && <img src={url} alt="" style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block', opacity: 0.56, filter: 'saturate(1.08) contrast(1.04)' }}/>}
      <div style={{ position: 'absolute', inset: 0, backdropFilter: 'blur(1px)' }}/>
      <div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(180deg, rgba(4,4,7,0.18), rgba(9,9,12,0.42) 45%, #09090c 98%), linear-gradient(90deg, rgba(4,4,7,0.92), rgba(4,4,7,0.22) 68%)' }}/>
    </div>
  );
}

function MovieBestRail({ items, accent, onOpenVideo, onViewAll }) {
  return (
    <>
      <window.SectionHeader right={<button onClick={onViewAll} className="vh-tap" style={{ padding: 0, border: 'none', background: 'transparent', color: accent, fontSize: 12, fontWeight: 700, cursor: 'pointer' }}>View all</button>}>Best Rated</window.SectionHeader>
      <div style={{ display: 'flex', gap: 10, padding: '0 16px 20px', overflowX: 'auto', scrollbarWidth: 'none' }}>
        {items.map((it, idx) => <button key={it.id} onClick={() => onOpenVideo(it.id)} className="vh-tap vh-card" style={{ width: 218, flex: '0 0 auto', padding: 12, borderRadius: 16, border: `0.5px solid ${idx === 0 ? accent + '66' : window.VH_HAIRLINE}`, background: 'linear-gradient(135deg, rgba(255,255,255,0.075), rgba(255,255,255,0.018))', color: window.VH_TEXT, textAlign: 'left' }}>
          <div style={{ display: 'flex', gap: 10 }}>
            <div style={{ width: 62, flexShrink: 0 }}><MoviePoster item={it} locked={false} accent={accent}/></div>
            <div style={{ minWidth: 0 }}>
              <div style={{ color: accent, fontWeight: 900, fontSize: 12 }}>#{idx + 1}</div>
              <div style={{ fontSize: 13, fontWeight: 800, marginTop: 4, lineHeight: 1.2 }}>{it.movieTitle}</div>
              <div style={{ marginTop: 7 }}><window.RatingStars value={it.rating || 0} accent={accent} size={11}/></div>
            </div>
          </div>
        </button>)}
      </div>
    </>
  );
}

function MovieSectionTitle({ title, right }) {
  return <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', margin: '20px 0 10px' }}><div style={{ color: '#fff', fontSize: 16, fontWeight: 900 }}>{title}</div>{right}</div>;
}

function MovieCastRail({ cast, actors, locked, title = 'Top Billed Cast' }) {
  const people = (cast?.length ? cast : (actors || []).map(name => ({ name, character: '', profileUrl: '' }))).slice(0, 14);
  if (!people.length) return null;
  return (
    <>
      <MovieSectionTitle title={title}/>
      <div style={{ display: 'flex', gap: 10, overflowX: 'auto', scrollbarWidth: 'none', paddingBottom: 2, filter: locked ? 'blur(5px)' : 'none' }}>
        {people.map((p, idx) => (
          <div key={`${p.id || p.name}-${idx}`} style={{ width: 104, flex: '0 0 auto', borderRadius: 8, overflow: 'hidden', background: 'rgba(255,255,255,0.055)', border: `0.5px solid ${window.VH_HAIRLINE}` }}>
            <div style={{ aspectRatio: '2 / 3', background: moviePersonPlaceholder(p.name) }}>
              {p.profileUrl && <img src={p.profileUrl} alt="" loading="lazy" style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }} onError={e => { e.currentTarget.style.display = 'none'; }}/>}
            </div>
            <div style={{ padding: 8 }}>
              <div style={{ color: window.VH_TEXT, fontSize: 12, fontWeight: 850, lineHeight: 1.2 }}>{p.name}</div>
              {p.character && <div style={{ color: window.VH_DIM, fontSize: 10.5, lineHeight: 1.25, marginTop: 3 }}>{p.character}</div>}
            </div>
          </div>
        ))}
      </div>
    </>
  );
}

function MovieWatchProviders({ data, locked, title = 'Watch Providers' }) {
  const providers = data?.providers || [];
  if (!providers.length) return null;
  return (
    <>
      <MovieSectionTitle title={`${title}${data.region ? ` - ${data.region}` : ''}`}/>
      <div style={{ ...movieGlassStyle(), filter: locked ? 'blur(5px)' : 'none' }}>
        <div style={{ display: 'flex', gap: 10, overflowX: 'auto', scrollbarWidth: 'none' }}>
          {providers.map(p => (
            <div key={`${p.type}-${p.id}`} title={`${p.name} (${p.type})`} style={{ width: 62, flex: '0 0 auto', textAlign: 'center' }}>
              <div style={{ width: 48, height: 48, margin: '0 auto', borderRadius: 8, background: 'rgba(255,255,255,0.08)', overflow: 'hidden', border: `0.5px solid ${window.VH_HAIRLINE}` }}>
                {p.logoUrl && <img src={p.logoUrl} alt="" loading="lazy" style={{ width: '100%', height: '100%', objectFit: 'cover' }}/>}
              </div>
              <div style={{ color: window.VH_DIM, fontSize: 10, marginTop: 5, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{p.name}</div>
            </div>
          ))}
        </div>
      </div>
    </>
  );
}

function MovieGallery({ items, locked, onOpen, title = 'Gallery' }) {
  if (!items.length) return null;
  return (
    <>
      <MovieSectionTitle title={title}/>
      <div style={{ display: 'flex', gap: 10, overflowX: 'auto', scrollbarWidth: 'none', filter: locked ? 'blur(5px)' : 'none' }}>
        {items.map((url, idx) => (
          <button key={url} onClick={() => onOpen(url)} style={{ width: idx % 4 === 0 ? 156 : 104, flex: '0 0 auto', aspectRatio: idx % 4 === 0 ? '16 / 9' : '2 / 3', padding: 0, border: `0.5px solid ${window.VH_HAIRLINE}`, borderRadius: 8, overflow: 'hidden', background: 'rgba(255,255,255,0.05)', cursor: 'pointer' }}>
            <img src={url} alt="" loading="lazy" style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }}/>
          </button>
        ))}
      </div>
    </>
  );
}

function MovieRelatedRail({ items, libraryItems, locked, accent, savingTmdb, onOpenVideo, onSave, title = 'Recommended', saveLabel = 'Save' }) {
  if (!items.length || locked) return null;
  return (
    <>
      <MovieSectionTitle title={title}/>
      <div style={{ display: 'flex', gap: 10, overflowX: 'auto', scrollbarWidth: 'none' }}>
        {items.map(movie => {
          const saved = (libraryItems || []).find(v => Number(v.tmdbId) === Number(movie.tmdbId) && v.movieType === movie.movieType);
          return (
            <div key={`${movie.movieType}-${movie.tmdbId}`} style={{ width: 126, flex: '0 0 auto' }}>
              <button onClick={() => saved ? onOpenVideo?.(saved.id) : onSave?.(movie)} style={{ width: '100%', padding: 0, border: 'none', background: 'transparent', color: window.VH_TEXT, textAlign: 'left', cursor: 'pointer' }}>
                <MoviePoster item={movie} locked={false} accent={accent}/>
                <div style={{ fontSize: 12, fontWeight: 850, lineHeight: 1.18, marginTop: 7, minHeight: 28, overflow: 'hidden', display: '-webkit-box', WebkitLineClamp: 2, WebkitBoxOrient: 'vertical' }}>{movie.movieTitle}</div>
                <div style={{ color: window.VH_DIM, fontSize: 10.5, marginTop: 3 }}>{movie.year || 'TMDb'}{movie.tmdbRating ? ` - ${movie.tmdbRating}` : ''}</div>
              </button>
              {!saved && <button onClick={() => onSave?.(movie)} disabled={savingTmdb === movie.tmdbId} style={{ ...movieSecondaryBtnStyle(), height: 30, borderRadius: 8, fontSize: 11, marginTop: 7, width: '100%' }}>{savingTmdb === movie.tmdbId ? 'Saving...' : saveLabel}</button>}
            </div>
          );
        })}
      </div>
    </>
  );
}

function MovieExternalLinks({ item, accent }) {
  const links = [
    item.tmdbUrl || item.sourceUrl ? ['TMDb', item.tmdbUrl || item.sourceUrl] : null,
    item.imdbUrl ? ['IMDb', item.imdbUrl] : null,
  ].filter(Boolean);
  if (!links.length) return null;
  return <div style={{ display: 'flex', gap: 8, marginTop: 18 }}>{links.map(([label, url]) => <a key={label} href={url} target="_blank" rel="noreferrer" style={{ ...movieSecondaryBtnStyle(), height: 38, flex: '0 0 auto', padding: '0 14px', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', textDecoration: 'none', color: label === 'TMDb' ? accent : '#f5f5f7' }}>{label}</a>)}</div>;
}

function MovieTrailerModal({ item, onClose }) {
  return (
    <div onClick={onClose} style={{ position: 'fixed', inset: 0, zIndex: 130, background: 'rgba(0,0,0,0.78)', display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 16 }}>
      <div onClick={e => e.stopPropagation()} style={{ width: '100%', maxWidth: 820, background: '#0d0d11', border: `0.5px solid ${window.VH_HAIRLINE}`, borderRadius: 8, overflow: 'hidden', boxShadow: '0 28px 80px rgba(0,0,0,0.7)' }}>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: 12 }}>
          <div style={{ color: '#fff', fontWeight: 850 }}>{item.movieTitle}</div>
          <button onClick={onClose} style={movieRoundBtnStyle()}>x</button>
        </div>
        <div style={{ aspectRatio: '16 / 9', background: '#000' }}>
          {item.trailerEmbedUrl ? <iframe title="Trailer" src={item.trailerEmbedUrl} allowFullScreen style={{ width: '100%', height: '100%', border: 'none' }}/> : <a href={item.trailerUrl} target="_blank" rel="noreferrer" style={{ color: '#fff' }}>Open YouTube</a>}
        </div>
      </div>
    </div>
  );
}

function MovieLightbox({ image, onClose }) {
  return (
    <div onClick={onClose} style={{ position: 'fixed', inset: 0, zIndex: 130, background: 'rgba(0,0,0,0.86)', display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 14 }}>
      <button onClick={onClose} style={{ ...movieRoundBtnStyle(), position: 'absolute', top: 16, right: 16 }}>x</button>
      <img src={image} alt="" style={{ maxWidth: '100%', maxHeight: '86vh', objectFit: 'contain', borderRadius: 8, boxShadow: '0 26px 80px rgba(0,0,0,0.7)' }}/>
    </div>
  );
}

function MovieReviewForm({ form, setForm, err, busy, accent, onBack, onSave }) {
  return (
    <div style={{ marginTop: 12 }}>
      <div style={{ display: 'flex', gap: 12, alignItems: 'flex-start' }}>
        <div style={{ width: 78, flexShrink: 0 }}><MoviePoster item={form} locked={false} accent={accent}/></div>
        <div style={{ flex: 1 }}>
          <MovieField compact label="Title" value={form.movieTitle} onChange={v => setForm({ ...form, movieTitle: v })}/>
          <MovieField compact label="Year" value={form.year || ''} onChange={v => setForm({ ...form, year: v })}/>
        </div>
      </div>
      <MovieField label="Overview" value={form.overview || ''} onChange={v => setForm({ ...form, overview: v })} textarea/>
      <MovieField label="Tagline" value={form.tagline || ''} onChange={v => setForm({ ...form, tagline: v })}/>
      <MovieField label="Genres" value={(form.genres || []).join(', ')} onChange={v => setForm({ ...form, genres: splitCsv(v) })}/>
      <MovieField label="Director" value={form.director || ''} onChange={v => setForm({ ...form, director: v })}/>
      <MovieField label="Writer" value={form.writer || ''} onChange={v => setForm({ ...form, writer: v })}/>
      <MovieField label="Actors" value={(form.actors || []).join(', ')} onChange={v => setForm({ ...form, actors: splitCsv(v) })}/>
      <div style={{ display: 'flex', gap: 8 }}>
        <MovieField flex label="Runtime" value={form.runtimeMinutes || ''} onChange={v => setForm({ ...form, runtimeMinutes: Number(v) || '' })}/>
        <MovieField flex label="Release" value={form.releaseDate || ''} onChange={v => setForm({ ...form, releaseDate: v })}/>
      </div>
      <MovieField label="Poster URL" value={form.posterUrl || ''} onChange={v => setForm({ ...form, posterUrl: v })}/>
      <MovieField label="Backdrop URL" value={form.backdropUrl || ''} onChange={v => setForm({ ...form, backdropUrl: v })}/>
      <MovieField label="Trailer URL" value={form.trailerUrl || ''} onChange={v => setForm({ ...form, trailerUrl: v, trailerSite: v ? 'YouTube' : form.trailerSite })}/>
      <div style={{ display: 'flex', gap: 8, alignItems: 'flex-end' }}>
        <MovieSelect label="Status" value={form.status || 'want_to_watch'} onChange={v => setForm({ ...form, status: v })} options={[['want_to_watch','Want'], ['watched','Watched'], ['favorite','Favorite'], ['rewatch','Rewatch'], ['skip','Skip']]}/>
        <MovieRating value={form.rating || form.personalRating || 0} onChange={v => setForm({ ...form, rating: v, personalRating: v })} accent={accent}/>
      </div>
      <MovieField label="Note" value={form.note || ''} onChange={v => setForm({ ...form, note: v })} textarea/>
      {err && <MovieError>{err}</MovieError>}
      <div style={{ display: 'flex', gap: 8, marginTop: 16, position: 'sticky', bottom: 'max(0px, env(safe-area-inset-bottom))', paddingTop: 10, paddingBottom: 'max(0px, env(safe-area-inset-bottom))', background: 'linear-gradient(180deg, rgba(21,21,26,0), #15151a 35%)' }}>
        <button onClick={onBack} style={movieSecondaryBtnStyle()}>Back</button>
        <button onClick={onSave} disabled={busy} style={moviePrimaryBtnStyle(accent)}>{busy ? 'Saving...' : 'Save to Library'}</button>
      </div>
    </div>
  );
}

function MovieSearchResults({ results, busy, accent, onSelect }) {
  if (!results.length && !busy) return <MovieSimpleState accent={accent} title="Search TMDb" detail="Type at least two characters to find movies and series." compact/>;
  return <div style={{ display: 'grid', gap: 8, marginTop: 12 }}>{results.map(r => (
    <button key={`${r.movieType}-${r.tmdbId}`} onClick={() => onSelect(r)} style={{ display: 'flex', gap: 10, padding: 10, borderRadius: 12, border: `0.5px solid ${window.VH_HAIRLINE}`, background: 'rgba(255,255,255,0.04)', color: window.VH_TEXT, textAlign: 'left', cursor: 'pointer' }}>
      <div style={{ width: 52, flexShrink: 0 }}><MoviePoster item={r} locked={false} accent={accent}/></div>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ fontSize: 14, fontWeight: 800 }}>{r.movieTitle}</div>
        <div style={{ fontSize: 11.5, color: window.VH_DIM, marginTop: 3 }}>{r.year || 'Unknown'} - TMDb {r.tmdbRating || '-'}</div>
        <div style={{ fontSize: 12, color: window.VH_DIM, lineHeight: 1.35, marginTop: 5, display: '-webkit-box', WebkitLineClamp: 2, WebkitBoxOrient: 'vertical', overflow: 'hidden' }}>{r.overview || 'No overview.'}</div>
      </div>
    </button>
  ))}</div>;
}

function MovieInfoGrid({ item, locked }) {
  const rows = [
    ['Director', item.director],
    ['Writer', item.writer],
    ['Actors', (item.actors || []).join(', ')],
    ['Runtime', item.runtimeMinutes ? `${item.runtimeMinutes} min` : ''],
    ['Release date', item.releaseDate],
    ['Source', (item.sourceBadges || []).join(', ')],
  ].filter(([, v]) => v);
  return <div style={{ display: 'grid', gap: 10, marginTop: 14 }}>{rows.map(([label, value]) => <MovieInfoBlock key={label} label={label} locked={locked}>{value}</MovieInfoBlock>)}</div>;
}

function MovieInfoBlock({ label, children, locked }) {
  return <div style={{ marginTop: 12 }}><div style={{ fontSize: 10.5, color: window.VH_DIM2, textTransform: 'uppercase', letterSpacing: 0.7, fontWeight: 800 }}>{label}</div><div style={{ color: window.VH_TEXT, fontSize: 13.5, lineHeight: 1.55, marginTop: 4, filter: locked ? 'blur(5px)' : 'none' }}>{children}</div></div>;
}

function MovieChipLine({ label, values, locked }) {
  if (!values?.length) return null;
  return <div style={{ marginTop: 14 }}><div style={{ fontSize: 10.5, color: window.VH_DIM2, textTransform: 'uppercase', letterSpacing: 0.7, fontWeight: 800, marginBottom: 6 }}>{label}</div><div style={{ display: 'flex', gap: 6, flexWrap: 'wrap', filter: locked ? 'blur(5px)' : 'none' }}>{values.map(v => <span key={v} style={{ padding: '5px 8px', borderRadius: 99, background: 'rgba(255,255,255,0.06)', border: `0.5px solid ${window.VH_HAIRLINE}`, color: window.VH_TEXT, fontSize: 11.5 }}>{v}</span>)}</div></div>;
}

function MovieField({ label, value, onChange, placeholder, type = 'text', textarea, compact, flex }) {
  const inputStyle = { width: '100%', minHeight: textarea ? 74 : (compact ? 34 : 42), padding: '10px 12px', borderRadius: 10, background: 'rgba(255,255,255,0.04)', color: window.VH_TEXT, border: `0.5px solid ${window.VH_HAIRLINE}`, outline: 'none', fontSize: 14, fontFamily: 'inherit', resize: 'vertical' };
  return <label style={{ display: 'block', flex: flex ? 1 : undefined, marginTop: compact ? 0 : 10 }}><div style={movieLabelStyle()}>{label}</div>{textarea ? <textarea value={value || ''} onChange={e => onChange(e.target.value)} placeholder={placeholder} style={inputStyle}/> : <input type={type} value={value || ''} onChange={e => onChange(e.target.value)} placeholder={placeholder} style={inputStyle}/>}</label>;
}

function MovieSelect({ label, value, onChange, options }) {
  return <label style={{ display: 'block', flex: 1, marginTop: 10 }}><div style={movieLabelStyle()}>{label}</div><select value={value} onChange={e => onChange(e.target.value)} style={{ width: '100%', height: 42, padding: '0 12px', borderRadius: 10, background: '#1b1b21', color: window.VH_TEXT, border: `0.5px solid ${window.VH_HAIRLINE}`, fontSize: 14 }}>{options.map(([v, l]) => <option key={v} value={v}>{l}</option>)}</select></label>;
}

function MovieRating({ value, onChange, accent }) {
  return <div style={{ marginTop: 10 }}><div style={movieLabelStyle()}>Rating</div><div style={{ height: 42, padding: '0 10px', borderRadius: 10, background: 'rgba(255,255,255,0.04)', border: `0.5px solid ${window.VH_HAIRLINE}`, display: 'flex', alignItems: 'center', gap: 6 }}>{[1,2,3,4,5].map(i => <button key={i} onClick={() => onChange(i === value ? 0 : i)} style={{ border: 'none', background: 'transparent', padding: 4, cursor: 'pointer' }}><div style={{ width: 12, height: 12, borderRadius: 99, background: i <= value ? accent : 'rgba(255,255,255,0.18)' }}/></button>)}</div></div>;
}

function MovieSearchBox({ value, onChange, placeholder }) {
  return <div style={{ display: 'flex', alignItems: 'center', gap: 10, background: window.VH_SURFACE, borderRadius: 12, padding: '11px 14px', border: `0.5px solid ${window.VH_HAIRLINE}` }}><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><circle cx="7" cy="7" r="5" stroke={window.VH_DIM} strokeWidth="1.6"/><path d="M11 11l3 3" stroke={window.VH_DIM} strokeWidth="1.6" strokeLinecap="round"/></svg><input value={value} onChange={e => onChange(e.target.value)} placeholder={placeholder} style={{ flex: 1, background: 'transparent', border: 'none', outline: 'none', color: window.VH_TEXT, fontSize: 14 }}/></div>;
}

function MovieLayoutToggle({ layout, onChange }) {
  const modes = [
    { id: 'compact', icon: <svg width="16" height="16" viewBox="0 0 16 16" fill="none"><rect x="2" y="2" width="3" height="5" rx="0.9" stroke="currentColor" strokeWidth="1.3"/><rect x="6.5" y="2" width="3" height="5" rx="0.9" stroke="currentColor" strokeWidth="1.3"/><rect x="11" y="2" width="3" height="5" rx="0.9" stroke="currentColor" strokeWidth="1.3"/><rect x="2" y="9" width="3" height="5" rx="0.9" stroke="currentColor" strokeWidth="1.3"/><rect x="6.5" y="9" width="3" height="5" rx="0.9" stroke="currentColor" strokeWidth="1.3"/><rect x="11" y="9" width="3" height="5" rx="0.9" stroke="currentColor" strokeWidth="1.3"/></svg> },
    { id: 'grid', icon: <svg width="16" height="16" viewBox="0 0 16 16" fill="none"><rect x="2" y="2" width="5" height="5" rx="1" stroke="currentColor" strokeWidth="1.5"/><rect x="9" y="2" width="5" height="5" rx="1" stroke="currentColor" strokeWidth="1.5"/><rect x="2" y="9" width="5" height="5" rx="1" stroke="currentColor" strokeWidth="1.5"/><rect x="9" y="9" width="5" height="5" rx="1" stroke="currentColor" strokeWidth="1.5"/></svg> },
    { id: 'list', icon: <svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M2 4h12M2 8h12M2 12h12" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round"/></svg> },
  ];
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 4, padding: 3, borderRadius: 99, background: 'rgba(245,158,11,0.12)', border: '0.5px solid rgba(245,158,11,0.22)' }}>
      {modes.map(m => (
        <button key={m.id} onClick={() => onChange(m.id)} style={{ width: 30, height: 30, borderRadius: 99, border: 'none', cursor: 'pointer', background: layout === m.id ? 'rgba(245,158,11,0.26)' : 'transparent', color: layout === m.id ? '#f8fafc' : 'rgba(245,245,247,0.58)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
          {m.icon}
        </button>
      ))}
    </div>
  );
}

function MovieChip({ active, onClick, accent, children }) {
  return <button onClick={onClick} style={{ flexShrink: 0, padding: '6px 12px', borderRadius: 99, background: active ? `${accent}22` : 'rgba(255,255,255,0.05)', color: active ? accent : window.VH_TEXT, border: active ? `0.5px solid ${accent}66` : `0.5px solid ${window.VH_HAIRLINE}`, fontSize: 12, fontWeight: 700, cursor: 'pointer' }}>{children}</button>;
}

function MovieEmptyState({ accent, signedIn, onOpenAuth, onAdd }) {
  return <div style={{ padding: '60px 28px', textAlign: 'center' }}><div style={{ color: window.VH_TEXT, fontSize: 17, fontWeight: 800 }}>{signedIn ? 'No movies yet' : 'Movie Library locked'}</div><div style={{ color: window.VH_DIM, fontSize: 13, lineHeight: 1.55, marginTop: 7 }}>{signedIn ? 'Use Smart Search or Quick Import to add your first movie.' : 'Sign in to see your private movie library.'}</div><button onClick={signedIn ? onAdd : onOpenAuth} style={{ ...moviePrimaryBtnStyle(accent), width: 'auto', padding: '0 22px', marginTop: 18 }}>{signedIn ? 'Add Movie' : 'Unlock'}</button></div>;
}

function MovieSimpleState({ accent, title, detail, compact }) {
  return <div style={{ padding: compact ? '24px 12px' : '48px 24px', textAlign: 'center', color: window.VH_DIM }}><div style={{ color: window.VH_TEXT, fontSize: 16, fontWeight: 800 }}>{title}</div><div style={{ fontSize: 13, lineHeight: 1.55, marginTop: 6 }}>{detail}</div></div>;
}

function MovieSubHeader({ title, subtitle, accent, onBack }) {
  return <div style={{ padding: '24px 16px 14px', display: 'flex', alignItems: 'flex-start', gap: 12 }}><button onClick={onBack} className="vh-tap" style={movieRoundBtnStyle()}><svg width="16" height="16" viewBox="0 0 16 16"><path d="M10 3 5 8l5 5" stroke="currentColor" strokeWidth="1.7" fill="none" strokeLinecap="round" strokeLinejoin="round"/></svg></button><div style={{ flex: 1 }}><div style={{ fontSize: 26, fontWeight: 850, color: window.VH_TEXT }}>{title}</div><div style={{ marginTop: 4, fontSize: 12, color: window.VH_DIM }}>{subtitle}</div></div><div style={{ width: 16, height: 16, borderRadius: 99, background: accent, marginTop: 9 }}/></div>;
}

function MovieModalShell({ children, onClose }) {
  return <div onClick={onClose} style={{ position: 'fixed', inset: 0, zIndex: 100, background: 'rgba(0,0,0,0.58)', backdropFilter: 'blur(12px)', display: 'flex', alignItems: 'flex-end', justifyContent: 'center', animation: 'vhFadeIn 200ms ease-out' }}><div onClick={e => e.stopPropagation()} style={{ width: '100%', maxWidth: 560, maxHeight: '92vh', overflowY: 'auto', background: '#15151a', borderTopLeftRadius: 22, borderTopRightRadius: 22, border: '0.5px solid rgba(255,255,255,0.08)', borderBottom: 'none', boxShadow: '0 -20px 60px rgba(0,0,0,0.6)', animation: 'vhSlideUp 280ms cubic-bezier(.2,.7,.2,1)' }}><div style={{ display: 'flex', justifyContent: 'center', padding: '8px 0 0' }}><div style={{ width: 36, height: 4, borderRadius: 99, background: 'rgba(255,255,255,0.18)' }}/></div>{children}</div></div>;
}

function MovieModalHeader({ title, kicker, onClose }) {
  return <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 14 }}><div><div style={{ fontSize: 11, letterSpacing: 1.2, textTransform: 'uppercase', color: window.VH_DIM2, fontWeight: 800 }}>{kicker}</div><div style={{ fontSize: 19, fontWeight: 850, color: window.VH_TEXT }}>{title}</div></div><button onClick={onClose} style={movieRoundBtnStyle()}><svg width="11" height="11" viewBox="0 0 11 11"><path d="M1 1l9 9M10 1L1 10" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round"/></svg></button></div>;
}

function MovieResultSkeleton() {
  return <div style={{ display: 'grid', gap: 8, marginTop: 12 }}>{Array.from({ length: 4 }).map((_, i) => <div key={i} style={{ display: 'flex', gap: 10 }}><div className="vh-skel" style={{ width: 52, height: 78, borderRadius: 10 }}/><div style={{ flex: 1 }}><div className="vh-skel" style={{ height: 12, width: '70%', marginTop: 8 }}/><div className="vh-skel" style={{ height: 10, width: '42%', marginTop: 8 }}/><div className="vh-skel" style={{ height: 28, width: '100%', marginTop: 8 }}/></div></div>)}</div>;
}

function MovieError({ children }) {
  return <div style={{ marginTop: 12, padding: '10px 12px', borderRadius: 9, background: 'rgba(225,29,72,0.10)', border: '0.5px solid rgba(225,29,72,0.35)', color: '#fca5b1', fontSize: 12.5, lineHeight: 1.5 }}>{children}</div>;
}

function blankMovieForm(sourceUrl = '') {
  return { contentType: 'movie', movieTitle: '', originalTitle: '', year: '', releaseDate: '', posterUrl: '', backdropUrl: '', overview: '', tagline: '', genres: [], genreIds: [], director: '', writer: '', actors: [], actorIds: [], cast: [], crew: [], runtimeMinutes: '', imdbId: '', tmdbId: '', imdbUrl: '', tmdbUrl: '', rottenTomatoesUrl: '', externalRatings: {}, trailerUrl: '', trailerSite: '', watchProviders: null, keywords: [], backdrops: [], posters: [], recommendations: [], similar: [], collectionName: '', movieType: 'movie', sourceName: '', sourceUrl, status: 'want_to_watch', rating: 0, personalRating: 0, note: '' };
}

function splitCsv(value) {
  return String(value || '').split(',').map(s => s.trim()).filter(Boolean);
}

function moviePlaceholder(item, accent) {
  const hue = window.hashHue(item?.movieTitle || item?.title || 'movie');
  return `radial-gradient(120% 90% at 25% 15%, oklch(0.48 0.16 ${hue}), oklch(0.20 0.06 ${(hue + 54) % 360}) 58%, #111116 100%)`;
}

function moviePersonPlaceholder(name) {
  const hue = window.hashHue(name || 'cast');
  return `linear-gradient(145deg, oklch(0.35 0.12 ${hue}), oklch(0.16 0.04 ${(hue + 70) % 360}))`;
}

function movieGlassStyle() {
  return {
    padding: 13,
    borderRadius: 8,
    border: `0.5px solid ${window.VH_HAIRLINE}`,
    background: 'linear-gradient(135deg, rgba(255,255,255,0.075), rgba(255,255,255,0.026))',
    boxShadow: '0 18px 46px rgba(0,0,0,0.22), inset 0 1px 0 rgba(255,255,255,0.07)',
    backdropFilter: 'blur(18px) saturate(145%)',
  };
}

function movieCrewNames(item, jobs) {
  const names = (item.crew || []).filter(p => jobs.includes(p.job)).map(p => p.name).filter(Boolean);
  return [...new Set(names)].join(', ');
}

function movieGalleryItems(item) {
  return [...new Set([...(item.backdrops || []), ...(item.posters || [])].filter(Boolean))].slice(0, 24);
}

function movieLabelStyle() {
  return { fontSize: 10.5, letterSpacing: 0.8, textTransform: 'uppercase', color: window.VH_DIM2, fontWeight: 700, marginBottom: 4 };
}

function moviePrimaryBtnStyle(accent) {
  return { flex: 1, height: 46, borderRadius: 10, border: 'none', cursor: 'pointer', background: accent, color: '#fff', fontSize: 14, fontWeight: 750, boxShadow: `0 8px 22px ${accent}44, 0 1px 0 rgba(255,255,255,0.18) inset` };
}

function movieSecondaryBtnStyle() {
  return { flex: 1, height: 46, borderRadius: 10, cursor: 'pointer', background: 'rgba(255,255,255,0.06)', color: '#f5f5f7', border: '0.5px solid rgba(255,255,255,0.10)', fontSize: 14, fontWeight: 650 };
}

function movieDangerBtnStyle() {
  return { ...movieSecondaryBtnStyle(), color: '#fca5b1', background: 'rgba(225,29,72,0.12)', border: '0.5px solid rgba(225,29,72,0.35)' };
}

function movieRoundBtnStyle() {
  return { width: 38, height: 38, borderRadius: 99, border: `0.5px solid ${window.VH_HAIRLINE}`, background: 'rgba(0,0,0,0.32)', color: window.VH_TEXT, display: 'inline-flex', alignItems: 'center', justifyContent: 'center', cursor: 'pointer', backdropFilter: 'blur(12px)' };
}

function movieBadgeStyle(accent) {
  return { display: 'inline-flex', alignItems: 'center', height: 24, padding: '0 8px', borderRadius: 99, background: `${accent}18`, border: `0.5px solid ${accent}55`, color: accent, fontSize: 11, fontWeight: 800 };
}

function movieTabBtnStyle(active, accent) {
  return { height: 34, borderRadius: 9, border: active ? `0.5px solid ${accent}88` : 'none', background: active ? `${accent}24` : 'transparent', color: active ? '#fff' : window.VH_DIM, fontSize: 12.5, fontWeight: 800, cursor: 'pointer' };
}

function movieStatusButtonStyle(active, meta) {
  return {
    display: 'flex',
    flexDirection: 'column',
    alignItems: 'center',
    justifyContent: 'center',
    gap: 5,
    padding: '10px 4px',
    borderRadius: 14,
    border: 'none',
    cursor: 'pointer',
    fontFamily: 'inherit',
    background: active ? (meta?.accent + '28') : 'rgba(255,255,255,0.05)',
    boxShadow: active
      ? `0 0 0 1.5px ${meta?.accent}, 0 0 14px ${meta?.glow || meta?.accent + '44'}`
      : `inset 0 0 0 0.5px ${window.VH_HAIRLINE}`,
    transform: active ? 'translateY(-2px)' : 'none',
    transition: 'transform 140ms cubic-bezier(.2,.7,.2,1), box-shadow 180ms ease, background 180ms ease',
  };
}

Object.assign(window, {
  LibraryModeSwitch,
  MovieLibraryScreen,
  MovieSearchScreen,
  MovieBestRatedScreen,
  MovieBookmarksScreen,
  MovieDetailScreen,
  MovieAddModal,
});
