// Lista filmów (paradisehill + mirrory). Grid plakatów + tytuł/rok/studio.
import { useNavigation } from '@react-navigation/native';
import type { NativeStackNavigationProp } from '@react-navigation/native-stack';
import { useInfiniteQuery } from '@tanstack/react-query';
import React from 'react';
import {
  ActivityIndicator,
  AppState,
  AppStateStatus,
  FlatList,
  Pressable,
  StyleSheet,
  Text,
  TextInput,
  View,
} from 'react-native';
import { useClient } from '../ClientContext';
import {
  DEFAULT_MOVIE_FILTERS,
  isDefaultFilters,
  MovieFilters,
  MovieFiltersSheet,
} from '../components/MovieFiltersSheet';
import { MoviePosterCard } from '../components/MoviePosterCard';
import { getLastSeen, markSeen } from '../lib/seenStore';
import type { RootStackParamList } from '../navigation';
import { theme } from '../theme';

const PER_PAGE = 30;
// 3 kolumny — plakaty 2:3 mieszczą się dobrze i widać 50% więcej filmów na ekran
// (user-report 0200956f: lepiej wykorzystać przestrzeń). Karta ma flex:1, skaluje się.
const NUM_COLS = 3;

export function MoviesScreen() {
  const client = useClient();
  const navigation = useNavigation<NativeStackNavigationProp<RootStackParamList, 'Movies'>>();
  const [q, setQ] = React.useState('');
  const [debouncedQ, setDebouncedQ] = React.useState('');
  const [filters, setFilters] = React.useState<MovieFilters>(DEFAULT_MOVIE_FILTERS);
  const [filtersOpen, setFiltersOpen] = React.useState(false);
  // seenSince: ISO timestamp ostatniego "kompletnie obejrzanej listy". Movies
  // z created_at > seenSince mają NEW badge. Ładujemy z SecureStore raz
  // przy mount; aktualizujemy gdy app idzie do tła (user widzi NEW przez
  // całą sesję, dopiero next session wymaga rotacji).
  const [seenSince, setSeenSince] = React.useState<string | null>(null);

  React.useEffect(() => {
    let mounted = true;
    getLastSeen('movies').then((v) => {
      if (mounted) setSeenSince(v);
    });
    return () => {
      mounted = false;
    };
  }, []);

  React.useEffect(() => {
    const sub = AppState.addEventListener('change', (next: AppStateStatus) => {
      if (next === 'background' || next === 'inactive') {
        markSeen('movies').catch(() => {});
      }
    });
    return () => sub.remove();
  }, []);

  React.useEffect(() => {
    const t = setTimeout(() => setDebouncedQ(q), 350);
    return () => clearTimeout(t);
  }, [q]);

  const {
    data,
    isLoading,
    error,
    refetch,
    isRefetching,
    fetchNextPage,
    hasNextPage,
    isFetchingNextPage,
  } = useInfiniteQuery({
    queryKey: ['movies', debouncedQ, filters],
    queryFn: ({ pageParam = 1 }) =>
      client.listMovies({
        q: debouncedQ || undefined,
        sort: filters.sort,
        year_from: filters.year_from ?? undefined,
        year_to: filters.year_to ?? undefined,
        has_playback: filters.has_playback || undefined,
        tags: filters.tag_slugs.length ? filters.tag_slugs : undefined,
        studio_slugs: filters.studio_slugs.length ? filters.studio_slugs : undefined,
        performer_ids: filters.performer_ids.length ? filters.performer_ids : undefined,
        page: pageParam,
        per_page: PER_PAGE,
      }),
    initialPageParam: 1,
    getNextPageParam: (last) => {
      const loaded = last.page * last.per_page;
      return loaded < last.total ? last.page + 1 : undefined;
    },
  });

  const items = data?.pages.flatMap((p) => p.items) ?? [];
  const total = data?.pages[0]?.total ?? 0;

  return (
    <View style={styles.container}>
      <View style={styles.toolbar}>
        <TextInput
          style={[styles.search, { flex: 1 }]}
          placeholder="search movies"
          placeholderTextColor={theme.muted}
          value={q}
          onChangeText={setQ}
          autoCorrect={false}
          autoCapitalize="none"
          returnKeyType="search"
        />
        <Pressable
          style={[styles.filterBtn, !isDefaultFilters(filters) && styles.filterBtnActive]}
          onPress={() => setFiltersOpen(true)}
        >
          <Text style={styles.filterBtnText}>Filter{!isDefaultFilters(filters) ? '·' : ''}</Text>
        </Pressable>
      </View>
      <MovieFiltersSheet
        visible={filtersOpen}
        value={filters}
        onChange={setFilters}
        onClose={() => setFiltersOpen(false)}
      />

      {isLoading && <ActivityIndicator color={theme.fg} style={{ marginTop: 24 }} />}
      {error instanceof Error && <Text style={styles.error}>{error.message}</Text>}

      <FlatList
        data={items}
        numColumns={NUM_COLS}
        keyExtractor={(m) => m.id}
        // Android removeClippedSubviews=true blankuje plakaty po scrollu (expo-image
        // nie re-renderuje odpiętych) — ten sam bug co "znikające miniaturki" scen.
        removeClippedSubviews={false}
        renderItem={({ item }) => (
          <MoviePosterCard
            movie={item}
            isNew={!!(item.created_at && seenSince && item.created_at > seenSince)}
            onPress={() => navigation.navigate('MovieDetail', { id: item.id })}
          />
        )}
        refreshing={isRefetching}
        onRefresh={refetch}
        ListHeaderComponent={
          total > 0 ? <Text style={styles.subtitle}>{total} films</Text> : null
        }
        ListEmptyComponent={!isLoading ? <Text style={styles.muted}>no movies</Text> : null}
        contentContainerStyle={{ paddingBottom: 24, paddingHorizontal: 6 }}
        columnWrapperStyle={{ gap: 8 }}
        onEndReached={() => {
          if (hasNextPage && !isFetchingNextPage) fetchNextPage();
        }}
        onEndReachedThreshold={0.3}
        ListFooterComponent={
          isFetchingNextPage ? <ActivityIndicator color={theme.fg} style={{ margin: 16 }} /> : null
        }
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: { flex: 1, backgroundColor: theme.bg },
  toolbar: {
    flexDirection: 'row',
    alignItems: 'center',
    gap: 8,
    paddingHorizontal: 12,
    paddingTop: 8,
    paddingBottom: 4,
  },
  filterBtn: {
    height: 40,
    paddingHorizontal: 14,
    borderRadius: 10,
    backgroundColor: theme.card,
    borderWidth: 1,
    borderColor: theme.border,
    alignItems: 'center',
    justifyContent: 'center',
  },
  filterBtnActive: {
    backgroundColor: theme.accentDeep,
    borderColor: theme.accent,
  },
  filterBtnText: { color: theme.fg, fontSize: 13, fontWeight: '600' },
  search: {
    backgroundColor: theme.card,
    borderColor: theme.border,
    borderWidth: 1,
    borderRadius: 10,
    color: theme.fg,
    paddingHorizontal: 12,
    paddingVertical: 8,
    fontSize: 14,
  },
  subtitle: { color: theme.muted, fontSize: 12, paddingHorizontal: 4, paddingTop: 6, paddingBottom: 8 },
  error: { color: theme.bad, padding: 12 },
  muted: { color: theme.muted, textAlign: 'center', marginTop: 24 },
});
