import { useAudioPlayer } from "expo-audio";
import { Image as ExpoImage } from "expo-image";
import React, { useEffect, useMemo, useRef, useState } from "react";
import {
  Pressable,
  Image as RNImage,
  ScrollView,
  StyleSheet,
  Text,
  View,
} from "react-native";
import { SheetManager } from "react-native-actions-sheet";
import {
  responsiveHeight,
  responsiveWidth,
} from "react-native-responsive-dimensions";
import { useGlobal } from "reactn";
import { background, icons } from "../../assets";
import Slider from "../../components/Slider";
import {
  arrayRemove,
  arrayUnion,
  increment,
  projectsRef,
  usersRef,
} from "../../config/firebase";
import useDataFromRef from "../../hooks/useDataFromRef";
import Page from "../../layouts/Page";
import { Palette } from "../../styles";
import { FONT_FAMILY } from "../../styles/Fonts";
import Style, { gutters, size } from "../../styles/Style";

// 20 secondes
const timeBeforeIncrement = 20000;

const MusicDetails = ({ route }) => {
  const { params } = route || {};
  const action = params?.action;
  const projectId = params?.projectId || null;
  const [fav, setFav] = useState(false);
  const [currentUID] = useGlobal("currentUID");
  const [isPlaying, setIsPlaying] = useState(false);
  const [progressInfo, setProgressInfo] = useState({ pos: 0, dur: 0 });
  const wasPlayingBeforeSeek = React.useRef(false);
  const listenedMsRef = React.useRef(0);
  const incrementDoneRef = React.useRef(false);
  const timerRef = React.useRef(null);

  const { data: project } = useDataFromRef({
    ref: projectId ? projectsRef.doc(projectId) : null,
    simpleRef: true,
    listener: true,
    condition: !!projectId,
  });

  const { data: owner } = useDataFromRef({
    ref: project?.userId ? usersRef.doc(project.userId) : null,
    simpleRef: true,
    listener: true,
    condition: !!project?.userId,
  });

  useEffect(() => {
    if (project && currentUID) {
      const liked = Array.isArray(project?.likedBy)
        ? project.likedBy.includes(currentUID)
        : false;
      setFav(liked);
    }
  }, [project?.likedBy, currentUID]);

  const title = project?.title || "Sans titre";
  const artist = owner?.userName || "MusicLand";
  const coverUrl = project?.coverUrl || null;
  const songUrl = project?.songUrl || null;

  const player = useAudioPlayer(songUrl ? { uri: songUrl } : undefined);

  // Karaoke aligned words (from timestamps)
  const alignedWords = useMemo(() => {
    try {
      const idx = Number(project?.songIndex) || 0;
      const ts = project?.musicTimestamps?.[idx];
      const arr = Array.isArray(ts?.alignedWords) ? ts.alignedWords : [];
      return arr.map((w) => ({
        word: String(w?.word ?? ""),
        startS: Number(w?.startS ?? 0),
        endS: Number(w?.endS ?? 0),
      }));
    } catch (e) {
      return [];
    }
  }, [project?.musicTimestamps, project?.songIndex]);

  // Reset counters when the track changes
  useEffect(() => {
    listenedMsRef.current = 0;
    incrementDoneRef.current = false;
  }, [songUrl]);

  // Poll player state to update progress and play state
  useEffect(() => {
    const id = setInterval(() => {
      const dur = (player?.duration || 0) * 1000;
      const pos = (player?.currentTime || 0) * 1000;
      setProgressInfo({ pos, dur });
      setIsPlaying(!!player?.playing);
    }, 300);
    return () => clearInterval(id);
  }, [player]);

  // Start/stop a timer to accumulate listened milliseconds while playing
  useEffect(() => {
    const clearTimer = () => {
      if (timerRef.current) {
        global.clearInterval(timerRef.current);
        timerRef.current = null;
      }
    };
    if (isPlaying && projectId) {
      if (!timerRef.current) {
        timerRef.current = global.setInterval(async () => {
          try {
            listenedMsRef.current += 500;
            if (
              !incrementDoneRef.current &&
              listenedMsRef.current >= timeBeforeIncrement &&
              projectId
            ) {
              incrementDoneRef.current = true;
              await projectsRef
                .doc(projectId)
                .set({ views: increment(1) }, { merge: true });
            }
          } catch (e) {
            // Silent fail for counter
          }
        }, 500);
      }
    } else {
      clearTimer();
    }
    return clearTimer;
  }, [isPlaying, projectId]);

  const fmt = (ms) => {
    const total = Math.max(0, Math.floor((ms || 0) / 1000));
    const m = Math.floor(total / 60)
      .toString()
      .padStart(1, "0");
    const s = (total % 60).toString().padStart(2, "0");
    return `${m}:${s}`;
  };

  const togglePlay = async () => {
    if (!player || !songUrl) return;
    try {
      if (player.playing) {
        await player.pause?.();
        setIsPlaying(false);
      } else {
        await player.play?.();
        setIsPlaying(true);
      }
    } catch (e) {
      console.log("MusicDetails audio error", e?.message);
    }
  };

  const onSeek = async (ratio) => {
    try {
      const dur = progressInfo.dur || 0;
      const pos = Math.floor(dur * ratio);
      if (player && dur > 0) {
        await player.seekTo?.(Math.floor((pos || 0) / 1000));
      }
    } catch (e) {
      console.log("MusicDetails seek error", e?.message);
    }
  };

  const seekBy = async (deltaSeconds) => {
    try {
      const cur = Math.floor((progressInfo.pos || 0) / 1000);
      const next = Math.max(0, cur + deltaSeconds);
      if (player) await player.seekTo?.(next);
    } catch (e) {
      console.log("MusicDetails seekBy error", e?.message);
    }
  };
  const description = useMemo(() => {
    // Build a readable text from lyrics with section labels
    if (Array.isArray(project?.lyrics)) {
      return project.lyrics
        .map((s) => {
          const body = (s?.lyrics || "").trim();
          if (!body) return null;
          const t = (s?.type || "").toLowerCase();
          const label = t === "refrain" ? "Refrain" : "Couplet";
          return `[${label}]\n${body}`;
        })
        .filter(Boolean)
        .join("\n\n");
    }
    const c = project?.lyrics?.couplet;
    const r = project?.lyrics?.refrain;
    const parts = [
      c ? `[Couplet]\n${c}` : null,
      r ? `[Refrain]\n${r}` : null,
    ].filter(Boolean);
    return parts.length ? parts.join("\n\n") : "";
  }, [project]);

  // Current time in seconds for highlighting
  const currentTimeS = useMemo(
    () => Math.max(0, (progressInfo.pos || 0) / 1000),
    [progressInfo.pos]
  );
  // Preview lead: show words 0.5s earlier
  const visibleTimeS = useMemo(
    () => Math.max(0, currentTimeS + 0.5),
    [currentTimeS]
  );
  // Group words into timed lines (similar to KaraokeLyrics)
  const groupAlignedWordsToLines = (words = [], { removeTags = true } = {}) => {
    const out = [];
    let buf = [];
    let start = null;
    const clean = (txt) =>
      String(txt || "")
        .replace(/\s+/g, " ")
        .trim();
    const isSentenceEnd = (txt) => /[.!?]$/.test((txt || "").trim());
    const isSectionTag = (txt) =>
      /^\s*\[[^\]]+\]\s*$/i.test((txt || "").trim());

    for (let i = 0; i < words.length; i++) {
      const w = words[i] || {};
      const original = String(w.word || "");
      const textNoNewline = original.replace(/\n/g, " ");
      const textNoTag = removeTags
        ? textNoNewline.replace(/^\s*\[[^\]]+\]\s*/i, "")
        : textNoNewline;
      const next = words[i + 1] || null;
      const gapToNext = next
        ? Math.max(0, Number(next.startS || 0) - Number(w.endS || 0))
        : 0;

      if (buf.length === 0) start = Number(w.startS || 0);

      if (isSectionTag(textNoNewline)) {
        if (!removeTags) {
          const joined = clean(textNoNewline);
          if (joined)
            out.push({
              text: joined,
              startS: start ?? Number(w.startS || 0),
              endS: Number(w.endS || 0),
            });
        }
        buf = [];
        start = null;
        continue;
      }

      if (!clean(textNoTag)) continue;

      buf.push({
        text: textNoTag,
        startS: Number(w.startS || 0),
        endS: Number(w.endS || 0),
      });

      const eolByNewline = /\n/.test(original);
      const eolByPause = gapToNext >= 0.6; // logical break
      const eolByPunct = isSentenceEnd(textNoTag);
      const isLast = i === words.length - 1;

      if (eolByNewline || eolByPause || eolByPunct || isLast) {
        const joined = clean(buf.map((b) => b.text).join(" "));
        if (joined)
          out.push({
            text: joined,
            startS: start ?? Number(w.startS || 0),
            endS: Number(w.endS || 0),
            words: buf,
          });
        buf = [];
        start = null;
      }
    }
    return out;
  };

  const lines = useMemo(
    () => groupAlignedWordsToLines(alignedWords, { removeTags: true }),
    [alignedWords]
  );
  const currentLineIdx = useMemo(() => {
    if (!lines || lines.length === 0) return -1;
    for (let i = 0; i < lines.length; i++) {
      const L = lines[i];
      if (visibleTimeS >= (L.startS || 0) && visibleTimeS <= (L.endS || 0))
        return i;
    }
    if (visibleTimeS > (lines[lines.length - 1]?.endS || 0))
      return lines.length - 1;
    return -1;
  }, [lines, visibleTimeS]);

  // Auto-scroll lyrics to keep the current line visible
  const lyricsRef = useRef(null);
  const lineYRef = useRef({});
  useEffect(() => {
    const y = lineYRef.current?.[currentLineIdx];
    if (lyricsRef.current && typeof y === "number") {
      try {
        lyricsRef.current.scrollTo({ y: Math.max(0, y - 80), animated: true });
      } catch (e) {}
    }
  }, [currentLineIdx]);

  return (
    <Page
      headerType="NAVIGATION"
      title={action === "userProfile" ? "Mon profil" : "Détail musique"}
      backgroundImg={
        action === "userProfile" ? background.profileBG : background.libraryBG2
      }
      {...(action === "userProfile" && {
        containerStyle: {
          backgroundColor: "#0000004D",
        },
        rightComponent: () => (
          <Pressable onPress={() => SheetManager.show("DeleteAudio")}>
            <RNImage source={icons.trash} />
          </Pressable>
        ),
      })}
    >
      <View style={{ flex: 1, paddingTop: 20, paddingBottom: gutters * 2 }}>
        <View style={{ gap: 28 }}>
          {coverUrl && (
            <ExpoImage
              source={{ uri: coverUrl }}
              cachePolicy="memory-disk"
              priority="high"
              contentFit="cover"
              transition={150}
              style={styles.img}
            />
          )}
          <View style={{ ...Style.containerSpaceBetween }}>
            <View>
              <Text style={styles.title}>{title}</Text>
              <Text style={styles.name}>{artist}</Text>
            </View>
            <View style={{ ...Style.containerRow, gap: 12 }}>
              <Pressable
                onPress={async () => {
                  if (!projectId || !currentUID) return;
                  const next = !fav;
                  setFav(next);
                  try {
                    await projectsRef.doc(projectId).update({
                      likedBy: next
                        ? arrayUnion(currentUID)
                        : arrayRemove(currentUID),
                    });
                  } catch (e) {
                    setFav(!next);
                  }
                }}
              >
                <RNImage
                  source={fav ? icons.heart : icons.heartOutline}
                  style={{ ...size({ size: 24 }) }}
                  resizeMode="contain"
                />
              </Pressable>
              <Pressable
                onPress={() =>
                  SheetManager.show("Playlist", { payload: { projectId } })
                }
              >
                <RNImage
                  source={icons.more}
                  style={{ ...size({ size: 24 }) }}
                  resizeMode="contain"
                />
              </Pressable>
            </View>
          </View>
        </View>
        {songUrl && (
          <View style={{ paddingTop: 22 }}>
            <Slider
              value={fmt(progressInfo.pos)}
              maxValue={fmt(progressInfo.dur)}
              progress={
                progressInfo.dur
                  ? (progressInfo.pos || 0) / progressInfo.dur
                  : 0
              }
              seekEnabled={!!songUrl}
              onSeekStart={async () => {
                try {
                  wasPlayingBeforeSeek.current = !!player?.playing;
                  if (player?.playing) {
                    await player.pause?.();
                    setIsPlaying(false);
                  }
                } catch (e) {
                  console.log("Pause on seek start error", e?.message);
                }
              }}
              onSeek={onSeek}
              onSeekEnd={async () => {
                try {
                  if (player && wasPlayingBeforeSeek.current) {
                    await player.play?.();
                    setIsPlaying(true);
                  }
                  wasPlayingBeforeSeek.current = false;
                } catch (e) {
                  console.log("Resume after seek error", e?.message);
                }
              }}
            />
            <View
              style={{ ...Style.containerRow, gap: 24, alignSelf: "center" }}
            >
              {/* Previous (rewind 10s) */}
              <Pressable onPress={() => seekBy(-10)}>
                <RNImage
                  source={icons.forward}
                  style={{
                    ...size({ size: 30 }),
                  }}
                />
              </Pressable>
              {/* Play / Pause */}
              <Pressable
                style={{
                  ...size({ size: 40 }),
                  alignItems: "center",
                  justifyContent: "center",
                }}
                onPress={togglePlay}
              >
                <RNImage
                  resizeMode={"contain"}
                  source={isPlaying ? icons.pause : icons.play}
                  style={size({ size: 34 })}
                />
              </Pressable>
              {/* Next (forward 10s) */}
              <Pressable onPress={() => seekBy(10)}>
                <RNImage
                  source={icons.forward}
                  style={{
                    ...size({ size: 30 }),
                    transform: [{ rotate: "180deg" }],
                  }}
                />
              </Pressable>
            </View>
          </View>
        )}
        <View style={{ flex: 1, marginTop: 20 }}>
          {lines?.length ? (
            <ScrollView
              ref={lyricsRef}
              style={{ flex: 1 }}
              contentContainerStyle={{ paddingBottom: 40 }}
            >
              {lines.map((L, i) => (
                <View
                  key={`line-${i}`}
                  onLayout={(e) => {
                    lineYRef.current[i] = e.nativeEvent.layout.y;
                  }}
                  style={{
                    marginBottom: 8,
                    flexDirection: "row",
                    flexWrap: "wrap",
                    // justifyContent: "",
                  }}
                >
                  {(L.words || []).map((w, j) => (
                    <Text
                      key={`w-${i}-${j}`}
                      style={
                        visibleTimeS >= (w.startS || 0)
                          ? styles.karaokeWordActive
                          : styles.karaokeWord
                      }
                    >
                      {w.text}
                      {j < (L.words?.length || 1) - 1 ? " " : ""}
                    </Text>
                  ))}
                </View>
              ))}
            </ScrollView>
          ) : description?.length > 0 ? (
            <ScrollView
              style={{ flex: 1 }}
              contentContainerStyle={{ paddingBottom: 40 }}
            >
              <Text
                style={{
                  fontSize: 16,
                  color: Palette.white,
                  fontFamily: FONT_FAMILY.InterRegular,
                }}
              >
                {description}
              </Text>
            </ScrollView>
          ) : null}
        </View>
      </View>
    </Page>
  );
};

export default MusicDetails;

const styles = StyleSheet.create({
  img: {
    width: 160,
    height: 160,
    borderRadius: 24,
    alignSelf: "center",
  },
  title: {
    fontSize: 20,
    color: Palette.white,
    fontFamily: FONT_FAMILY.HelveticaNeueMedium,
    width: responsiveWidth(70),
    marginBottom: responsiveHeight(1),
  },
  name: {
    fontSize: 16,
    color: Palette.white,
    fontFamily: FONT_FAMILY.HelveticaNeueRegular,
  },
  karaokeContainer: {
    fontSize: 16,
    color: Palette.white,
    fontFamily: FONT_FAMILY.InterRegular,
    lineHeight: 24,
  },
  karaokeWord: {
    color: Palette.white,
    fontFamily: FONT_FAMILY.InterRegular,
  },
  karaokeWordActive: {
    color: Palette.primary,
    fontFamily: FONT_FAMILY.InterBold,
  },
});
