/**
 * SceneTile — 2-col 16:9 grid item używany w listach scen
 * (Scenes, SiteScenes, PerformerScenes, StudioScenes, TagScenes).
 *
 * Per impeccable.style/slop + Jan feedback "większe miniaturki, mniej tekstu":
 *   - Thumb wypełnia szerokość kolumny (aspect 16:9)
 *   - Title 1 linijka, weight 600, letter-spacing -0.2
 *   - Pod tytułem: 1 linia uppercase micro-meta (studio | performers | tag — wybór per ekran)
 *   - Overlay na thumb: fav (top-left), duration (bottom-right), NEW (top-right gdy seenSince),
 *     ✓watched (top-right gdy finished)
 *   - Long-press → animated preview (gdy playback_source ma animated_thumbnail_url)
 *
 * Zostawia Pressable do parenta dla custom onLongPress (np. delete-from-favorites) —
 * default onLongPress robi preview (jak w ScenesScreen).
 *
 * Used inline w 2-column FlatList:
 *   <FlatList
 *     numColumns={2}
 *     columnWrapperStyle={{ gap: 10, marginBottom: 14 }}
 *     renderItem={({ item }) => <SceneTile scene={item} secondLine="studio" />}
 *   />
 */
import { useNavigation } from '@react-navigation/native';
import type { NativeStackNavigationProp } from '@react-navigation/native-stack';
import React from 'react';
import { Pressable, StyleSheet, Text, View } from 'react-native';

import { useSceneActions } from '../SceneActionsContext';
import { isNewScene } from '../lib/newScenes';
import type { RootStackParamList } from '../navigation';
import { fonts, theme } from '../theme';
import type { SceneOut } from '../types';
import { Thumb } from './Thumb';

export type SecondLine = 'studio' | 'performers' | 'date' | 'none';

interface Props {
  scene: SceneOut;
  secondLine?: SecondLine;
  /**
   * Pokazuj NEW badge gdy scene.created_at > seenSince. Używane na ekranach
   * Performer/Studio scenes — gdy user owner'ował fav, last_seen_at z favorite
   * jest porównywany ze sceną.
   */
  seenSince?: string;
  /**
   * Custom long-press handler (np. removal from favorites). Default = animated
   * preview gdy thumb ma animated wariant.
   */
  onLongPress?: () => void;
}

function SceneTileBase({ scene, secondLine = 'studio', seenSince, onLongPress }: Props) {
  const navigation =
    useNavigation<NativeStackNavigationProp<RootStackParamList>>();
  const { isSelecting, pendingDuplicate, openActions, pickDuplicateTarget } = useSceneActions();

  // animated_thumbnail_url używamy tylko jako still-fallback gdy brak statycznej
  // (preview-on-hold usunięty — bug-report 5a6844db, gest nic nie robił).
  const displayUrl =
    scene.playback_sources.find((s) => s.thumbnail_url)?.thumbnail_url ??
    scene.playback_sources.find((s) => s.animated_thumbnail_url)?.animated_thumbnail_url;

  const isPending = pendingDuplicate?.id === scene.id;

  const handlePress = () => {
    // Tryb wyboru duplikatu: tap = wybierz oryginał (chyba że to ta sama kafelka).
    if (isSelecting && !isPending) {
      pickDuplicateTarget(scene);
      return;
    }
    navigation.navigate('SceneDetail', { id: scene.id });
  };

  const handleLongPress = () => {
    if (onLongPress) {
      onLongPress();
      return;
    }
    openActions(scene);
  };

  const dim = scene.finished === true;
  const isNew = isNewScene(scene, seenSince);
  const dur = scene.duration_sec;
  const durLabel =
    dur && dur > 0
      ? dur >= 3600
        ? `${Math.floor(dur / 3600)}h${String(Math.floor((dur % 3600) / 60)).padStart(2, '0')}`
        : `${Math.floor(dur / 60)}m`
      : null;

  const meta = (() => {
    if (secondLine === 'none') return null;
    if (secondLine === 'studio') return scene.studio?.name || null;
    if (secondLine === 'performers') {
      if (scene.performers.length === 0) return null;
      const names = scene.performers.slice(0, 2).map((p) => p.canonical_name).join(', ');
      return scene.performers.length > 2 ? `${names} +${scene.performers.length - 2}` : names;
    }
    if (secondLine === 'date') return scene.release_date;
    return null;
  })();

  return (
    <Pressable
      style={styles.tile}
      onPress={handlePress}
      onLongPress={handleLongPress}
      delayLongPress={300}
    >
      <View
        style={[
          styles.thumbWrap,
          dim && styles.thumbDim,
          isSelecting && !isPending && styles.thumbSelectable,
          isPending && styles.thumbPending,
        ]}
      >
        <Thumb url={displayUrl} style={styles.thumb} />
        {isPending ? (
          <View style={styles.dupBadge}>
            <Text style={styles.dupBadgeText}>DUPLIKAT</Text>
          </View>
        ) : null}
        {scene.is_favorite ? (
          <View style={styles.favBadge}>
            <Text style={styles.favBadgeText}>★</Text>
          </View>
        ) : null}
        {isNew ? (
          <View style={styles.newBadge}>
            <Text style={styles.newBadgeText}>NEW</Text>
          </View>
        ) : null}
        {dim ? (
          <View style={styles.watchedBadge}>
            <Text style={styles.watchedText}>✓</Text>
          </View>
        ) : null}
        {durLabel ? (
          <View style={styles.durBadge}>
            <Text style={styles.durText}>{durLabel}</Text>
          </View>
        ) : null}
        {/* Quick-play (user-request): tap ▶ = od razu graj najlepsze źródło (bez wchodzenia
            na SceneDetail). Autoplay resolvuje top-source na mount; z ustawioną domyślną
            jakością to 1 tap → wideo. Tap poza ▶ = szczegóły. Ukryte w trybie wyboru dup. */}
        {!isSelecting ? (
          <Pressable
            style={styles.playBtn}
            hitSlop={6}
            onPress={() => navigation.navigate('SceneDetail', { id: scene.id, autoplay: true })}
          >
            <Text style={styles.playBtnIcon}>▶</Text>
          </Pressable>
        ) : null}
      </View>
      <Text style={[styles.title, dim && styles.titleDim]} numberOfLines={1}>
        {scene.title}
      </Text>
      {meta ? (
        <Text style={styles.meta} numberOfLines={1}>
          {meta}
        </Text>
      ) : null}
    </Pressable>
  );
}

// Memoizowany — bez tego każda zmiana stanu parenta (np. pisanie w search-boxie na
// ScenesScreen) re-renderuje WSZYSTKIE zamontowane kafelki → jank klawiatury i scrolla
// (bug-report 5b7ca1e1). Props per item są stabilne (scene z react-query), więc shallow
// compare wystarcza.
export const SceneTile = React.memo(SceneTileBase);

const styles = StyleSheet.create({
  tile: { flex: 1, marginBottom: 14 },
  thumbWrap: {
    width: '100%',
    aspectRatio: 16 / 9,
    borderRadius: 6,
    overflow: 'hidden',
    position: 'relative',
    backgroundColor: theme.bgElevated,
  },
  thumb: { width: '100%', height: '100%' },
  thumbDim: { opacity: 0.45 },
  thumbSelectable: { borderWidth: 2, borderColor: theme.accent, opacity: 0.85 },
  thumbPending: { borderWidth: 2, borderColor: theme.fg, opacity: 0.55 },
  dupBadge: {
    position: 'absolute',
    top: 6,
    left: 6,
    backgroundColor: theme.accent,
    paddingHorizontal: 6,
    paddingVertical: 2,
    borderRadius: 4,
  },
  dupBadgeText: { color: theme.fg, fontSize: 9, fontWeight: '800', letterSpacing: 0.6 },
  favBadge: {
    position: 'absolute',
    top: 6,
    left: 6,
    backgroundColor: 'rgba(0,0,0,0.7)',
    paddingHorizontal: 5,
    paddingVertical: 1,
    borderRadius: 6,
  },
  favBadgeText: { color: theme.accent, fontSize: 11, fontWeight: '700' },
  newBadge: {
    position: 'absolute',
    top: 6,
    right: 6,
    backgroundColor: theme.accent,
    paddingHorizontal: 6,
    paddingVertical: 2,
    borderRadius: 4,
  },
  newBadgeText: { color: theme.fg, fontSize: 9, fontWeight: '800', letterSpacing: 0.6 },
  watchedBadge: {
    position: 'absolute',
    top: 6,
    right: 6,
    backgroundColor: 'rgba(0,0,0,0.78)',
    width: 20,
    height: 20,
    borderRadius: 999,
    alignItems: 'center',
    justifyContent: 'center',
  },
  watchedText: { color: theme.fg, fontSize: 11, fontWeight: '700' },
  durBadge: {
    position: 'absolute',
    bottom: 6,
    right: 6,
    backgroundColor: 'rgba(0,0,0,0.78)',
    paddingHorizontal: 6,
    paddingVertical: 2,
    borderRadius: 4,
  },
  playBtn: {
    position: 'absolute',
    left: '50%',
    top: '50%',
    marginLeft: -18,
    marginTop: -18,
    width: 36,
    height: 36,
    borderRadius: 18,
    backgroundColor: 'rgba(0,0,0,0.5)',
    borderWidth: 1,
    borderColor: 'rgba(255,255,255,0.35)',
    alignItems: 'center',
    justifyContent: 'center',
  },
  playBtnIcon: { color: '#fff', fontSize: 15, marginLeft: 2 },
  durText: {
    color: theme.fg,
    fontSize: 11,
    fontFamily: fonts.mono,
    fontVariant: ['tabular-nums'],
  },
  title: {
    color: theme.fg,
    fontSize: 14,
    fontFamily: fonts.display,
    marginTop: 8,
    letterSpacing: -0.2,
  },
  titleDim: { color: theme.muted },
  meta: {
    color: theme.muted,
    fontSize: 10,
    fontFamily: fonts.mono,
    marginTop: 3,
    letterSpacing: 0.5,
    textTransform: 'uppercase',
  },
});

/**
 * Props siatki scen dla danej liczby kolumn (1/2/3, z PreferencesContext).
 * `key` wymusza remount FlatListy przy zmianie numColumns (RN nie wspiera zmiany w locie).
 * columnWrapperStyle TYLKO gdy cols>1 — przy 1 kolumnie RN rzuca jeśli ustawione.
 */
export function sceneGridProps(cols: number) {
  return {
    key: `scenegrid-${cols}`,
    numColumns: cols,
    columnWrapperStyle: cols > 1 ? { gap: 10 } : undefined,
    // Perf (bug-report 5b7ca1e1): removeClippedSubviews zostaje false (inaczej expo-image
    // blankuje miniaturki po scrollu), więc okno renderowania ograniczamy ręcznie —
    // bez tego długa lista trzyma setki kafelków z obrazami → jank + obciążenie telefonu.
    // windowSize 7 ≈ ~3 ekrany w pamięci. Dotyczy wszystkich siatek scen.
    removeClippedSubviews: false,
    windowSize: 7,
    maxToRenderPerBatch: 8,
    initialNumToRender: 8,
    updateCellsBatchingPeriod: 50,
    // Anti-jank (report): sort=created_at desc → scrapery dosypują nowe sceny NA GÓRĘ.
    // Gdy refetch wstawi je nad viewportem, treść skacze/tearing pod palcem. RN pinuje
    // widoczny element (minIndexForVisible:0) i sam koryguje offset. autoscrollToTopThreshold:
    // gdy user jest przy samej górze (<48px), nowe wskakują normalnie; niżej lista stoi.
    maintainVisibleContentPosition: { minIndexForVisible: 0, autoscrollToTopThreshold: 48 },
  };
}
