import React, { useEffect, useMemo, useRef, useState } from "react";
import {
  StyleSheet,
  Text,
  View,
  TextInput,
  TouchableOpacity,
  FlatList,
  Alert,
  Image,
  Modal,
  Animated,
  Easing,
} from "react-native";
import { router } from "expo-router";
import { Ionicons } from "@expo/vector-icons";
import { useMedia, type MediaItem, type Playlist } from "../../context/MediaContext";
import { useViewMode } from "../../hooks/useViewMode";
import { useMiniPlayerInset } from "../../hooks/useMiniPlayerInset";

type SortMode = "recent" | "date-desc" | "name-asc" | "name-desc";

const SORT_OPTIONS: { mode: SortMode; label: string; icon: keyof typeof Ionicons.glyphMap }[] = [
  { mode: "recent", label: "Recently played", icon: "play-outline" },
  { mode: "date-desc", label: "Newest first", icon: "time-outline" },
  { mode: "name-asc", label: "Name (A–Z)", icon: "text-outline" },
  { mode: "name-desc", label: "Name (Z–A)", icon: "text-outline" },
];

function sortPlaylists(playlists: Playlist[], mode: SortMode): Playlist[] {
  const sorted = [...playlists];
  switch (mode) {
    case "name-asc":
      return sorted.sort((a, b) => a.name.localeCompare(b.name));
    case "name-desc":
      return sorted.sort((a, b) => b.name.localeCompare(a.name));
    case "date-desc":
      return sorted.sort((a, b) => (b.createdAt ?? 0) - (a.createdAt ?? 0));
    case "recent":
      // Never-played playlists sink to the bottom (in creation order among
      // themselves) rather than being scattered — 0 sorts as "oldest".
      return sorted.sort((a, b) => (b.lastPlayedAt ?? 0) - (a.lastPlayedAt ?? 0));
  }
}

/** A single-line text that scrolls horizontally on a loop, but only if it's
 * actually wider than the space it's given — a short subtitle just sits
 * still like normal text. */
function MarqueeText({ text, style }: { text: string; style?: any }) {
  const [translateX] = useState(() => new Animated.Value(0));
  const [textWidth, setTextWidth] = useState(0);
  const [containerWidth, setContainerWidth] = useState(0);

  useEffect(() => {
    if (textWidth <= containerWidth || containerWidth === 0) return;
    const distance = textWidth - containerWidth + 16;
    const anim = Animated.loop(
      Animated.sequence([
        Animated.delay(1200),
        Animated.timing(translateX, {
          toValue: -distance,
          duration: distance * 35,
          easing: Easing.linear,
          useNativeDriver: true,
        }),
        Animated.delay(1200),
        Animated.timing(translateX, {
          toValue: 0,
          duration: distance * 35,
          easing: Easing.linear,
          useNativeDriver: true,
        }),
      ]),
    );
    anim.start();
    return () => anim.stop();
  }, [textWidth, containerWidth, translateX]);

  return (
    <View
      style={{ overflow: "hidden" }}
      onLayout={(e) => setContainerWidth(e.nativeEvent.layout.width)}
    >
      <Animated.Text
        style={[style, { transform: [{ translateX }], width: "auto", alignSelf: "flex-start" }]}
        numberOfLines={1}
        onLayout={(e) => setTextWidth(e.nativeEvent.layout.width)}
      >
        {text}
      </Animated.Text>
    </View>
  );
}

export default function PlaylistsScreen() {
  const { playlists, downloads, createPlaylist, deletePlaylist, playMedia } =
    useMedia();
  const [name, setName] = useState("");
  const [sortMode, setSortMode] = useState<SortMode>("recent");
  const [showSortSheet, setShowSortSheet] = useState(false);
  const [viewMode, setViewMode] = useViewMode("@playlists_view_mode");
  const miniPlayerInset = useMiniPlayerInset();
  const [searchOpen, setSearchOpen] = useState(false);
  const [searchQuery, setSearchQuery] = useState("");
  const [searchWidth] = useState(() => new Animated.Value(0));
  const searchInputRef = useRef<TextInput>(null);

  const toggleSearch = () => {
    const opening = !searchOpen;
    setSearchOpen(opening);
    if (!opening) setSearchQuery("");
    Animated.timing(searchWidth, {
      toValue: opening ? 1 : 0,
      duration: 220,
      easing: Easing.out(Easing.cubic),
      useNativeDriver: false,
    }).start();
    if (opening) setTimeout(() => searchInputRef.current?.focus(), 250);
    else searchInputRef.current?.blur();
  };

  const handleCreate = () => {
    if (!name.trim()) return;
    createPlaylist(name);
    setName("");
  };

  const handlePlayPlaylist = async (playlistId: string) => {
    const playlist = playlists.find((p) => p.id === playlistId);
    if (!playlist) return;
    const tracks = playlist.mediaIds
      .map((mid) => downloads.find((d) => d.id === mid))
      .filter((d): d is MediaItem => Boolean(d));
    if (tracks.length === 0) return;
    // Playing from here makes this playlist's own track order the
    // next/previous queue, so shuffle/repeat/skip stay within it. Passing
    // the playlist id keeps the Player screen's filter chip in sync with
    // what's actually playing instead of defaulting to "All", and updates
    // this playlist's lastPlayedAt for the "Recently played" sort.
    await playMedia(tracks[0], tracks, playlistId);
    router.push("/(tabs)/player");
  };

  const confirmDelete = (id: string, playlistName: string) => {
    Alert.alert(
      "Delete Playlist",
      `Remove "${playlistName}"? Your downloaded media won't be deleted.`,
      [
        { text: "Cancel", style: "cancel" },
        { text: "Delete", style: "destructive", onPress: () => deletePlaylist(id) },
      ],
    );
  };

  const tracksFor = (playlist: Playlist): MediaItem[] =>
    playlist.mediaIds
      .map((mid) => downloads.find((d) => d.id === mid))
      .filter((d): d is MediaItem => Boolean(d));

  const filteredSorted = useMemo(() => {
    const q = searchQuery.trim().toLowerCase();
    const filtered = q
      ? playlists.filter((p) => p.name.toLowerCase().includes(q))
      : playlists;
    return sortPlaylists(filtered, sortMode);
  }, [playlists, searchQuery, sortMode]);

  const renderListRow = (item: Playlist) => {
    const tracks = tracksFor(item);
    const thumb = tracks[0]?.thumbnail;
    const subtitleNames = tracks.slice(0, 3).map((t) => t.title).join("  •  ");
    return (
      <TouchableOpacity
        style={styles.row}
        onPress={() => router.push({ pathname: "/playlist/[id]", params: { id: item.id } })}
      >
        {thumb ? (
          <Image source={{ uri: thumb }} style={styles.rowThumb} />
        ) : (
          <View style={[styles.rowThumb, styles.rowThumbFallback]}>
            <Ionicons name="albums-outline" size={22} color="#1DB954" />
          </View>
        )}
        <View style={{ flex: 1, marginLeft: 12 }}>
          <Text style={styles.rowTitle} numberOfLines={1}>
            {item.name}
          </Text>
          <Text style={styles.rowSub}>
            {item.mediaIds.length} {item.mediaIds.length === 1 ? "track" : "tracks"}
          </Text>
          {subtitleNames ? (
            <MarqueeText text={subtitleNames} style={styles.marqueeText} />
          ) : null}
        </View>
        {item.mediaIds.length > 0 && (
          <TouchableOpacity
            style={styles.rowAction}
            onPress={() => handlePlayPlaylist(item.id)}
          >
            <Ionicons name="play-circle" size={26} color="#1DB954" />
          </TouchableOpacity>
        )}
        <TouchableOpacity
          style={styles.rowAction}
          onPress={() => confirmDelete(item.id, item.name)}
        >
          <Ionicons name="trash-outline" size={20} color="#FF5252" />
        </TouchableOpacity>
      </TouchableOpacity>
    );
  };

  const renderGridCard = (item: Playlist) => {
    const tracks = tracksFor(item);
    const thumb = tracks[0]?.thumbnail;
    return (
      <TouchableOpacity
        style={styles.gridCard}
        onPress={() => router.push({ pathname: "/playlist/[id]", params: { id: item.id } })}
      >
        {thumb ? (
          <Image source={{ uri: thumb }} style={styles.gridThumb} />
        ) : (
          <View style={[styles.gridThumb, styles.rowThumbFallback]}>
            <Ionicons name="albums-outline" size={28} color="#1DB954" />
          </View>
        )}
        <Text style={styles.gridTitle} numberOfLines={1}>
          {item.name}
        </Text>
        <Text style={styles.gridSub}>
          {item.mediaIds.length} {item.mediaIds.length === 1 ? "track" : "tracks"}
        </Text>
      </TouchableOpacity>
    );
  };

  return (
    <View style={styles.container}>
      <View style={styles.inputRow}>
        <TextInput
          style={styles.input}
          placeholder="New playlist name..."
          placeholderTextColor="#666"
          value={name}
          onChangeText={setName}
          onSubmitEditing={handleCreate}
          returnKeyType="done"
        />
        <TouchableOpacity style={styles.addBtn} onPress={handleCreate}>
          <Ionicons name="add" size={22} color="#FFF" />
        </TouchableOpacity>
      </View>

      <View style={styles.toolbarRow}>
        <Text style={styles.toolbarTitle}>
          {playlists.length} playlist{playlists.length === 1 ? "" : "s"}
        </Text>
        <View style={styles.toolbarIcons}>
          <TouchableOpacity onPress={toggleSearch} style={styles.toolbarIconBtn}>
            <Ionicons name={searchOpen ? "close" : "search-outline"} size={19} color="#FFF" />
          </TouchableOpacity>
          <TouchableOpacity onPress={() => setShowSortSheet(true)} style={styles.toolbarIconBtn}>
            <Ionicons name="funnel-outline" size={18} color="#FFF" />
          </TouchableOpacity>
          <TouchableOpacity
            onPress={() => setViewMode(viewMode === "list" ? "grid" : "list")}
            style={styles.toolbarIconBtn}
          >
            <Ionicons name={viewMode === "list" ? "grid-outline" : "list-outline"} size={19} color="#FFF" />
          </TouchableOpacity>
        </View>
      </View>

      <Animated.View
        style={{
          height: searchWidth.interpolate({ inputRange: [0, 1], outputRange: [0, 44] }),
          opacity: searchWidth,
          overflow: "hidden",
        }}
      >
        <TextInput
          ref={searchInputRef}
          style={styles.searchInput}
          placeholder="Search playlists..."
          placeholderTextColor="#666"
          value={searchQuery}
          onChangeText={setSearchQuery}
        />
      </Animated.View>

      {viewMode === "grid" ? (
        <FlatList
          // FlatList doesn't support changing numColumns on an already-
          // mounted instance ("Changing numColumns on the fly is not
          // supported" — confirmed live) — the key forces a fresh instance
          // whenever list/grid toggles, instead of trying to update the
          // existing one in place.
          key="grid"
          data={filteredSorted}
          keyExtractor={(p) => p.id}
          numColumns={2}
          columnWrapperStyle={styles.gridRow}
          renderItem={({ item }) => renderGridCard(item)}
          contentContainerStyle={{ paddingBottom: miniPlayerInset }}
          ListEmptyComponent={
            <Text style={styles.emptyText}>
              {searchQuery
                ? "No matches."
                : "No playlists yet. Create one above, then add tracks from the Downloads tab."}
            </Text>
          }
        />
      ) : (
        <FlatList
          key="list"
          data={filteredSorted}
          keyExtractor={(p) => p.id}
          renderItem={({ item }) => renderListRow(item)}
          contentContainerStyle={{ paddingBottom: miniPlayerInset }}
          ListEmptyComponent={
            <Text style={styles.emptyText}>
              {searchQuery
                ? "No matches."
                : "No playlists yet. Create one above, then add tracks from the Downloads tab."}
            </Text>
          }
        />
      )}

      <Modal
        visible={showSortSheet}
        transparent
        animationType="slide"
        onRequestClose={() => setShowSortSheet(false)}
      >
        <TouchableOpacity
          style={styles.modalOverlay}
          activeOpacity={1}
          onPress={() => setShowSortSheet(false)}
        >
          <View style={styles.bottomSheet} onStartShouldSetResponder={() => true}>
            <View style={styles.sheetHeader}>
              <Text style={styles.sheetTitle}>Sort by</Text>
              <TouchableOpacity onPress={() => setShowSortSheet(false)}>
                <Ionicons name="close" size={24} color="#FFF" />
              </TouchableOpacity>
            </View>
            {SORT_OPTIONS.map((opt) => (
              <TouchableOpacity
                key={opt.mode}
                style={styles.sortOptionRow}
                onPress={() => {
                  setSortMode(opt.mode);
                  setShowSortSheet(false);
                }}
              >
                <Ionicons name={opt.icon} size={18} color="#1DB954" />
                <Text style={styles.sortOptionText}>{opt.label}</Text>
                {sortMode === opt.mode && (
                  <Ionicons name="checkmark" size={18} color="#1DB954" style={{ marginLeft: "auto" }} />
                )}
              </TouchableOpacity>
            ))}
          </View>
        </TouchableOpacity>
      </Modal>
    </View>
  );
}

const styles = StyleSheet.create({
  container: { flex: 1, backgroundColor: "#121212", padding: 16 },
  inputRow: { flexDirection: "row", marginBottom: 16 },
  input: {
    flex: 1,
    backgroundColor: "#1E1E1E",
    color: "#FFF",
    padding: 12,
    borderRadius: 6,
    marginRight: 8,
  },
  addBtn: {
    backgroundColor: "#1DB954",
    width: 46,
    borderRadius: 6,
    alignItems: "center",
    justifyContent: "center",
  },
  toolbarRow: {
    flexDirection: "row",
    alignItems: "center",
    justifyContent: "space-between",
    marginBottom: 8,
  },
  toolbarTitle: { color: "#888", fontSize: 12 },
  toolbarIcons: { flexDirection: "row" },
  toolbarIconBtn: { marginLeft: 14 },
  searchInput: {
    backgroundColor: "#1E1E1E",
    color: "#FFF",
    borderRadius: 8,
    paddingHorizontal: 12,
    height: 40,
    marginBottom: 4,
  },
  row: {
    flexDirection: "row",
    alignItems: "center",
    backgroundColor: "#1E1E1E",
    padding: 12,
    borderRadius: 6,
    marginBottom: 8,
  },
  rowThumb: { width: 48, height: 48, borderRadius: 6, backgroundColor: "#2A2A2A" },
  rowThumbFallback: { alignItems: "center", justifyContent: "center" },
  rowTitle: { color: "#FFF", fontSize: 14, fontWeight: "600" },
  rowSub: { color: "#888", fontSize: 12, marginTop: 2 },
  marqueeText: { color: "#1DB954", fontSize: 11, marginTop: 2 },
  rowAction: { marginLeft: 12 },
  emptyText: { color: "#666", fontSize: 13, textAlign: "center", marginTop: 40 },

  gridRow: { justifyContent: "space-between" },
  gridCard: {
    width: "48%",
    backgroundColor: "#1E1E1E",
    borderRadius: 8,
    padding: 8,
    marginBottom: 12,
  },
  gridThumb: {
    width: "100%",
    aspectRatio: 16 / 9,
    borderRadius: 6,
    backgroundColor: "#2A2A2A",
  },
  gridTitle: { color: "#FFF", fontSize: 12, fontWeight: "600", marginTop: 6 },
  gridSub: { color: "#888", fontSize: 10, marginTop: 2 },

  modalOverlay: {
    flex: 1,
    backgroundColor: "rgba(0,0,0,0.6)",
    justifyContent: "flex-end",
  },
  bottomSheet: {
    backgroundColor: "#1E1E1E",
    borderTopLeftRadius: 16,
    borderTopRightRadius: 16,
    padding: 16,
    maxHeight: "80%",
  },
  sheetHeader: {
    flexDirection: "row",
    justifyContent: "space-between",
    alignItems: "center",
    marginBottom: 12,
  },
  sheetTitle: { color: "#FFF", fontSize: 16, fontWeight: "bold", flex: 1, marginRight: 12 },
  sortOptionRow: {
    flexDirection: "row",
    alignItems: "center",
    paddingVertical: 12,
    borderBottomWidth: 1,
    borderBottomColor: "#2A2A2A",
  },
  sortOptionText: { color: "#FFF", fontSize: 14, marginLeft: 10 },
});
