// Lista tube źródeł — top-level tab obok Scenes/Movies. Tap → SiteScenes.
// Bug-report 2026-05-24 (ea6f05f9): user chce wybierać "pages" obok Scenes
// i Movies, widzieć najnowsze sceny z konkretnego scrapowanego site'u.
//
// Layout: chip-grid analogiczny do TagsScreen — krótkie nazwy (domena.tld)
// plus scene_count + relative-time "Xh temu" scraped, jeśli świeży.
import { useNavigation } from '@react-navigation/native';
import type { NativeStackNavigationProp } from '@react-navigation/native-stack';
import { useQuery } from '@tanstack/react-query';
import React, { useMemo, useState } from 'react';
import {
  ActivityIndicator,
  FlatList,
  Modal,
  Pressable,
  ScrollView,
  StyleSheet,
  Text,
  TextInput,
  View,
} from 'react-native';
import { useClient } from '../ClientContext';
import type { RootStackParamList } from '../navigation';
import { theme } from '../theme';
import type { SourceOut, SourceRating } from '../types';

type Order = 'popular' | 'recent';

export function SitesScreen() {
  const client = useClient();
  const navigation =
    useNavigation<NativeStackNavigationProp<RootStackParamList, 'Sites'>>();
  const [q, setQ] = useState('');
  const [debouncedQ, setDebouncedQ] = useState('');
  const [order, setOrder] = useState<Order>('popular');
  const [searchFocused, setSearchFocused] = useState(false);
  // Źródło którego rozkład oceny pokazujemy w modalu (tap w gwiazdki).
  const [detail, setDetail] = useState<SourceOut | null>(null);

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

  const { data, isLoading, error, refetch, isRefetching } = useQuery({
    queryKey: ['sources'],
    queryFn: () => client.listSources(),
    staleTime: 60_000,
  });

  // Sort + filter client-side — lista ma <50 entries, nie warto roundtripować.
  // Backend zwraca pre-sorted po scene_count DESC, więc dla 'popular' kolejność
  // zachowana. Dla 'recent' sortujemy po last_scraped_at DESC.
  const items = useMemo<SourceOut[]>(() => {
    const all = data?.items ?? [];
    const filtered = debouncedQ
      ? all.filter(
          (s) =>
            s.display_name.toLowerCase().includes(debouncedQ.toLowerCase()) ||
            s.sitetag.toLowerCase().includes(debouncedQ.toLowerCase()),
        )
      : all;
    if (order === 'recent') {
      return [...filtered].sort((a, b) => {
        if (!a.last_scraped_at && !b.last_scraped_at) return 0;
        if (!a.last_scraped_at) return 1;
        if (!b.last_scraped_at) return -1;
        return b.last_scraped_at.localeCompare(a.last_scraped_at);
      });
    }
    return filtered;
  }, [data?.items, debouncedQ, order]);

  return (
    <View style={styles.container}>
      <View style={styles.headerRow}>
        <Text style={styles.headerLabel}>Sites</Text>
        <Text style={styles.headerCount}>{items.length}</Text>
      </View>
      <Text style={styles.hint}>tap a tube → newest scenes · tap the ★ → rating breakdown</Text>

      <View style={styles.toolbar}>
        <TextInput
          style={[styles.search, searchFocused && styles.searchFocused]}
          value={q}
          onChangeText={setQ}
          onFocus={() => setSearchFocused(true)}
          onBlur={() => setSearchFocused(false)}
          placeholder="search site…"
          placeholderTextColor={theme.mutedDim}
          autoCapitalize="none"
        />
      </View>

      <View style={styles.segment}>
        <SegButton
          active={order === 'popular'}
          onPress={() => setOrder('popular')}
          label="Top"
        />
        <SegButton
          active={order === 'recent'}
          onPress={() => setOrder('recent')}
          label="Recent"
        />
      </View>

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

      <FlatList
        data={items}
        keyExtractor={(s) => s.origin}
        numColumns={2}
        columnWrapperStyle={styles.gridRow}
        renderItem={({ item }) => (
          <SiteChip
            source={item}
            onPress={() =>
              navigation.navigate('SiteScenes', {
                origin: item.origin,
                name: prettySiteName(item.display_name),
              })
            }
            onShowRating={() => setDetail(item)}
          />
        )}
        refreshing={isRefetching}
        onRefresh={refetch}
        ListEmptyComponent={
          !isLoading ? <Text style={styles.emptyText}>no sites</Text> : null
        }
        contentContainerStyle={{ paddingBottom: 24 }}
      />

      <RatingModal source={detail} onClose={() => setDetail(null)} />
    </View>
  );
}

function SegButton({
  active,
  onPress,
  label,
}: {
  active: boolean;
  onPress: () => void;
  label: string;
}) {
  return (
    <Pressable
      onPress={onPress}
      style={[styles.segButton, active && styles.segButtonActive]}
    >
      <Text style={[styles.segButtonText, active && styles.segButtonTextActive]}>
        {label}
      </Text>
    </Pressable>
  );
}

// Lista Sites pokazuje display_name = domena (hqporner.com). User-report 18105d14:
// pozbyć się suffixów com/org/itp. Strip końcowego TLD → czysta nazwa.
function prettySiteName(name: string): string {
  return name.replace(/\.[a-z]{2,5}$/i, '').trim() || name;
}

function formatRelativeTime(iso: string | null): string | null {
  if (!iso) return null;
  const ts = Date.parse(iso);
  if (Number.isNaN(ts)) return null;
  const diffSec = (Date.now() - ts) / 1000;
  if (diffSec < 60) return 'just now';
  if (diffSec < 3600) return `${Math.floor(diffSec / 60)}m ago`;
  if (diffSec < 86400) return `${Math.floor(diffSec / 3600)}h ago`;
  const days = Math.floor(diffSec / 86400);
  if (days < 30) return `${days}d ago`;
  return null;
}

// Rząd gwiazdek 0-5. 0 = offline (czerwony label zamiast gwiazdek). Brak oceny → null.
function Stars({ value, size = 13 }: { value: number | null | undefined; size?: number }) {
  if (value == null) return <Text style={[styles.starsDim, { fontSize: size }]}>— not rated</Text>;
  if (value <= 0) return <Text style={[styles.starsOffline, { fontSize: size }]}>● OFFLINE</Text>;
  const full = '★'.repeat(value);
  const empty = '☆'.repeat(5 - value);
  return (
    <Text style={[styles.starsRow, { fontSize: size }]}>
      <Text style={styles.starsFull}>{full}</Text>
      <Text style={styles.starsEmpty}>{empty}</Text>
    </Text>
  );
}

function SiteChip({
  source,
  onPress,
  onShowRating,
}: {
  source: SourceOut;
  onPress: () => void;
  onShowRating: () => void;
}) {
  const rel = formatRelativeTime(source.last_scraped_at);
  const stars = source.rating?.stars;
  return (
    <Pressable
      style={({ pressed }) => [styles.chip, pressed && styles.chipPressed]}
      onPress={onPress}
    >
      <View style={styles.chipTopRow}>
        <View style={styles.chipMain}>
          <Text style={styles.chipName} numberOfLines={1}>
            {prettySiteName(source.display_name)}
          </Text>
          {rel ? <Text style={styles.chipRel}>{rel}</Text> : null}
        </View>
        <View style={styles.chipCountWrap}>
          <Text style={styles.chipCount}>{source.scene_count}</Text>
        </View>
      </View>
      <Pressable
        onPress={onShowRating}
        hitSlop={8}
        style={({ pressed }) => [styles.starsTap, pressed && { opacity: 0.6 }]}
      >
        <Stars value={stars} />
      </Pressable>
    </Pressable>
  );
}

function AxisBar({ label, value }: { label: string; value: number | null }) {
  const v = value ?? 0;
  const pct = Math.max(0, Math.min(100, (v / 5) * 100));
  return (
    <View style={styles.axisRow}>
      <Text style={styles.axisLabel}>{label}</Text>
      <View style={styles.axisTrack}>
        <View style={[styles.axisFill, { width: `${pct}%` }]} />
      </View>
      <Text style={styles.axisVal}>{value == null ? '—' : `${value}/5`}</Text>
    </View>
  );
}

const _PCT_LABELS: Record<string, string> = {
  thumb: 'Thumbnails',
  tag: 'Tags',
  perf: 'Performers',
  desc: 'Descriptions',
  studio: 'Studio',
  dur: 'Duration',
};

function RatingModal({ source, onClose }: { source: SourceOut | null; onClose: () => void }) {
  const r: SourceRating | null | undefined = source?.rating;
  const pct = r?.components?.pct ?? {};
  const basis = r?.health_basis ?? r?.components?.health_basis;
  const attempts = r?.components?.pb_attempts_7d ?? 0;
  const successRate = r?.components?.pb_success_rate;
  return (
    <Modal visible={!!source} transparent animationType="fade" onRequestClose={onClose}>
      <Pressable style={styles.modalBackdrop} onPress={onClose}>
        <Pressable style={styles.modalCard} onPress={() => {}}>
          <ScrollView>
            <Text style={styles.modalTitle}>{source ? prettySiteName(source.display_name) : ''}</Text>
            {!r ? (
              <Text style={styles.modalMuted}>Not rated yet — check back soon.</Text>
            ) : (
              <>
                <View style={styles.modalStarsBig}>
                  <Stars value={r.stars} size={22} />
                </View>
                <AxisBar label="Freshness" value={r.freshness} />
                <AxisBar label="Metadata" value={r.richness} />
                <AxisBar label="Plays" value={r.health} />

                <Text style={styles.modalSection}>Metadata coverage</Text>
                {Object.keys(_PCT_LABELS).map((k) => (
                  <View key={k} style={styles.pctRow}>
                    <Text style={styles.pctLabel}>{_PCT_LABELS[k]}</Text>
                    <Text style={styles.pctVal}>{pct[k] != null ? `${pct[k]}%` : '—'}</Text>
                  </View>
                ))}

                <Text style={styles.modalSection}>Playback</Text>
                <Text style={styles.modalMuted}>
                  {basis === 'telemetry'
                    ? `Measured from real playback: ${successRate ?? 0}% success over ${attempts} plays (7d).`
                    : 'Estimated from how this source streams (no playback data yet — collecting).'}
                </Text>
              </>
            )}
            <Pressable style={styles.modalClose} onPress={onClose}>
              <Text style={styles.modalCloseText}>Close</Text>
            </Pressable>
          </ScrollView>
        </Pressable>
      </Pressable>
    </Modal>
  );
}

const styles = StyleSheet.create({
  container: { flex: 1, backgroundColor: theme.bg, paddingHorizontal: 16, paddingTop: 12 },

  headerRow: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'space-between',
    paddingBottom: 4,
  },
  headerLabel: {
    color: theme.muted,
    fontSize: 12,
    textTransform: 'uppercase',
    letterSpacing: 1.2,
    fontWeight: '700',
  },
  headerCount: { color: theme.fg, fontSize: 22, fontWeight: '800' },
  hint: { color: theme.mutedDim, fontSize: 11, marginBottom: 12 },

  toolbar: { flexDirection: 'row', gap: 12, marginBottom: 10 },
  search: {
    flex: 1,
    backgroundColor: theme.card,
    borderColor: theme.border,
    borderWidth: 1.5,
    borderRadius: 12,
    color: theme.fg,
    padding: 12,
    fontSize: 16,
  },
  searchFocused: { borderColor: theme.borderFocus },

  segment: {
    flexDirection: 'row',
    backgroundColor: theme.bgElevated,
    borderColor: theme.border,
    borderWidth: 1,
    borderRadius: 12,
    padding: 4,
    marginBottom: 14,
    alignSelf: 'flex-start',
  },
  segButton: { paddingHorizontal: 14, paddingVertical: 6, borderRadius: 8 },
  segButtonActive: {
    backgroundColor: theme.accent,
    shadowColor: theme.accent,
    shadowOffset: { width: 0, height: 0 },
    shadowOpacity: 0.4,
    shadowRadius: 6,
    elevation: 2,
  },
  segButtonText: { color: theme.muted, fontWeight: '700', fontSize: 13 },
  segButtonTextActive: { color: theme.fg },

  gridRow: { gap: 10, marginBottom: 10 },
  chip: {
    flex: 1,
    gap: 8,
    backgroundColor: theme.card,
    borderColor: theme.border,
    borderWidth: 1,
    borderRadius: 12,
    paddingHorizontal: 12,
    paddingVertical: 10,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 1 },
    shadowOpacity: 0.18,
    shadowRadius: 3,
    elevation: 2,
  },
  chipTopRow: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'space-between',
    gap: 8,
  },
  chipPressed: { borderColor: theme.borderFocus, backgroundColor: theme.bgElevated },
  chipMain: { flex: 1, gap: 2 },
  chipName: {
    color: theme.fg,
    fontWeight: '600',
    fontSize: 14,
  },
  chipRel: {
    color: theme.mutedDim,
    fontSize: 10,
  },
  chipCountWrap: {
    backgroundColor: `${theme.accentSecondary}1F`,
    borderColor: `${theme.accentSecondary}55`,
    borderWidth: 1,
    borderRadius: 8,
    paddingHorizontal: 8,
    paddingVertical: 2,
    minWidth: 36,
    alignItems: 'center',
  },
  chipCount: {
    color: theme.accentSecondary,
    fontSize: 12,
    fontWeight: '700',
  },

  emptyText: { color: theme.muted, textAlign: 'center', marginTop: 48, fontSize: 16 },
  error: { color: theme.bad, padding: 16 },

  starsTap: { alignSelf: 'flex-start', paddingVertical: 2, paddingRight: 8 },
  starsRow: { letterSpacing: 1 },
  starsFull: { color: '#f5c518' }, // złoto
  starsEmpty: { color: theme.mutedDim },
  starsDim: { color: theme.mutedDim, fontStyle: 'italic' },
  starsOffline: { color: theme.bad, fontWeight: '700', fontSize: 11 },

  modalBackdrop: {
    flex: 1,
    backgroundColor: 'rgba(0,0,0,0.6)',
    justifyContent: 'center',
    padding: 24,
  },
  modalCard: {
    backgroundColor: theme.card,
    borderColor: theme.border,
    borderWidth: 1,
    borderRadius: 16,
    padding: 18,
    maxHeight: '80%',
  },
  modalTitle: { color: theme.fg, fontSize: 20, fontWeight: '800', marginBottom: 8 },
  modalStarsBig: { marginBottom: 14 },
  modalSection: {
    color: theme.muted,
    fontSize: 11,
    textTransform: 'uppercase',
    letterSpacing: 1,
    fontWeight: '700',
    marginTop: 16,
    marginBottom: 8,
  },
  modalMuted: { color: theme.mutedDim, fontSize: 13, lineHeight: 18 },

  axisRow: { flexDirection: 'row', alignItems: 'center', gap: 10, marginBottom: 8 },
  axisLabel: { color: theme.fg, fontSize: 13, width: 80 },
  axisTrack: {
    flex: 1,
    height: 8,
    backgroundColor: theme.bgElevated,
    borderRadius: 4,
    overflow: 'hidden',
  },
  axisFill: { height: 8, backgroundColor: theme.accent, borderRadius: 4 },
  axisVal: { color: theme.muted, fontSize: 12, width: 30, textAlign: 'right' },

  pctRow: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    paddingVertical: 3,
  },
  pctLabel: { color: theme.muted, fontSize: 13 },
  pctVal: { color: theme.fg, fontSize: 13, fontWeight: '600' },

  modalClose: {
    marginTop: 20,
    backgroundColor: theme.accent,
    borderRadius: 10,
    paddingVertical: 10,
    alignItems: 'center',
  },
  modalCloseText: { color: theme.fg, fontWeight: '700', fontSize: 14 },
});
