import { useEffect, useRef, useCallback, useState, useMemo } from "react";
import WaveSurfer from "wavesurfer.js";
import { ChevronDown, GripVertical, Check } from "lucide-react";
import type { TimelineSegment } from "@/features/home/model/useTimelineEditor";
import type { Material } from "@/shared/types/material";
import { SelectPopover } from "@/shared/ui/SelectPopover";

interface TimelineEditorProps {
  audioDuration: number;
  audioUrl: string;
  segments: TimelineSegment[];
  materials: Material[];
  outputAspectRatio: "9:16" | "16:9";
  onOutputAspectRatioChange: (ratio: "9:16" | "16:9") => void;
  onReorderSegment: (fromIdx: number, toIdx: number) => void;
  onClickSegment: (segment: TimelineSegment) => void;
  embedded?: boolean;
}

function formatTime(sec: number): string {
  const m = Math.floor(sec / 60);
  const s = sec % 60;
  return `${String(m).padStart(2, "0")}:${s.toFixed(1).padStart(4, "0")}`;
}

export function TimelineEditor({
  audioDuration,
  audioUrl,
  segments,
  materials,
  outputAspectRatio,
  onOutputAspectRatioChange,
  onReorderSegment,
  onClickSegment,
  embedded = false,
}: TimelineEditorProps) {
  const waveRef = useRef<HTMLDivElement>(null);
  const wsRef = useRef<WaveSurfer | null>(null);
  const [waveReady, setWaveReady] = useState(false);
  const [isPlaying, setIsPlaying] = useState(false);

  // Refs for high-frequency DOM updates (avoid 60fps re-renders)
  const playheadRef = useRef<HTMLDivElement>(null);
  const timeRef = useRef<HTMLSpanElement>(null);
  const audioDurationRef = useRef(audioDuration);

  useEffect(() => {
    audioDurationRef.current = audioDuration;
  }, [audioDuration]);

  // Drag-to-reorder state
  const [dragFromIdx, setDragFromIdx] = useState<number | null>(null);
  const [dragOverIdx, setDragOverIdx] = useState<number | null>(null);

  // Aspect ratio options
  const ratioOptions = [
    { value: "9:16" as const, label: "竖屏 9:16" },
    { value: "16:9" as const, label: "横屏 16:9" },
  ];
  const currentRatioLabel =
    ratioOptions.find((opt) => opt.value === outputAspectRatio)?.label ?? "竖屏 9:16";

  // Create / recreate wavesurfer when audioUrl changes
  useEffect(() => {
    if (!waveRef.current || !audioUrl) return;

    const playheadEl = playheadRef.current;
    const timeEl = timeRef.current;

    // Destroy previous instance
    if (wsRef.current) {
      wsRef.current.destroy();
      wsRef.current = null;
    }

    const ws = WaveSurfer.create({
      container: waveRef.current,
      height: 56,
      waveColor: "#6d28d9",
      progressColor: "#a855f7",
      barWidth: 2,
      barGap: 1,
      barRadius: 2,
      cursorWidth: 1,
      cursorColor: "#e879f9",
      interact: true,
      normalize: true,
    });

    // Click waveform → seek + auto-play
    ws.on("interaction", () => ws.play());
    ws.on("play", () => setIsPlaying(true));
    ws.on("pause", () => setIsPlaying(false));
    ws.on("finish", () => {
      setIsPlaying(false);
      if (playheadRef.current) playheadRef.current.style.display = "none";
    });
    // High-frequency: update playhead + time via refs (no React re-render)
    ws.on("timeupdate", (time: number) => {
      const dur = audioDurationRef.current;
      if (playheadRef.current && dur > 0) {
        playheadRef.current.style.left = `${(time / dur) * 100}%`;
        playheadRef.current.style.display = "block";
      }
      if (timeRef.current) {
        timeRef.current.textContent = formatTime(time);
      }
    });

    ws.load(audioUrl);
    wsRef.current = ws;

    return () => {
      ws.destroy();
      wsRef.current = null;
      setIsPlaying(false);
      if (playheadEl) playheadEl.style.display = "none";
      if (timeEl) timeEl.textContent = formatTime(0);
    };
  }, [audioUrl, waveReady]);

  // Callback ref to detect when waveRef div mounts
  const waveCallbackRef = useCallback((node: HTMLDivElement | null) => {
    (waveRef as React.MutableRefObject<HTMLDivElement | null>).current = node;
    setWaveReady(!!node);
  }, []);

  const handlePlayPause = useCallback(() => {
    wsRef.current?.playPause();
  }, []);

  // Drag-to-reorder handlers
  const handleDragStart = useCallback((idx: number, e: React.DragEvent) => {
    setDragFromIdx(idx);
    e.dataTransfer.effectAllowed = "move";
    e.dataTransfer.setData("text/plain", String(idx));
  }, []);

  const handleDragOver = useCallback((idx: number, e: React.DragEvent) => {
    e.preventDefault();
    e.dataTransfer.dropEffect = "move";
    setDragOverIdx(idx);
  }, []);

  const handleDragLeave = useCallback(() => {
    setDragOverIdx(null);
  }, []);

  const handleDrop = useCallback((toIdx: number, e: React.DragEvent) => {
    e.preventDefault();
    const fromIdx = parseInt(e.dataTransfer.getData("text/plain"), 10);
    if (!isNaN(fromIdx) && fromIdx !== toIdx) {
      onReorderSegment(fromIdx, toIdx);
    }
    setDragFromIdx(null);
    setDragOverIdx(null);
  }, [onReorderSegment]);

  const handleDragEnd = useCallback(() => {
    setDragFromIdx(null);
    setDragOverIdx(null);
  }, []);

  // Filter visible vs overflow segments
  const visibleSegments = useMemo(() => segments.filter((s) => s.start < audioDuration), [segments, audioDuration]);
  const overflowSegments = useMemo(() => segments.filter((s) => s.start >= audioDuration), [segments, audioDuration]);
  const hasSegments = visibleSegments.length > 0;

  const content = (
    <>
      <div className="flex items-center justify-between mb-3">
        {!embedded ? (
          <h2 className="text-base sm:text-lg font-semibold text-white flex items-center gap-2">
            时间轴编辑
          </h2>
        ) : (
          <h3 className="text-sm font-medium text-gray-400">时间轴编辑</h3>
        )}
        <div className="flex items-center gap-2 text-xs text-gray-400">
          <div className="shrink-0">
            <SelectPopover
              sheetTitle="设置输出画面比例"
              trigger={({ open, toggle }) => (
                <button
                  type="button"
                  onClick={toggle}
                  className="rounded-lg border border-white/10 bg-black/25 px-2.5 py-1.5 text-left transition-colors hover:border-white/30"
                  title="设置输出画面比例"
                >
                  <span className="flex items-center justify-between gap-2">
                    <span className="truncate text-xs text-white">画面: {currentRatioLabel}</span>
                    <ChevronDown className={`h-3.5 w-3.5 text-gray-300 transition-transform ${open ? "rotate-180" : ""}`} />
                  </span>
                </button>
              )}
            >
              {({ close }) => (
                <div className="space-y-1">
                  {ratioOptions.map((opt) => {
                    const isSelected = outputAspectRatio === opt.value;
                    return (
                      <button
                        key={opt.value}
                        type="button"
                        data-popover-selected={isSelected ? "true" : undefined}
                        onClick={() => {
                          onOutputAspectRatioChange(opt.value);
                          close();
                        }}
                        className={`flex w-full items-center justify-between rounded-lg border px-3 py-2 text-left transition-colors ${isSelected
                          ? "border-purple-500 bg-purple-500/20"
                          : "border-white/10 bg-white/5 hover:border-white/30"
                          }`}
                      >
                        <span className="text-xs text-white">{opt.label}</span>
                        {isSelected && <Check className="h-3.5 w-3.5 text-purple-300" />}
                      </button>
                    );
                  })}
                </div>
              )}
            </SelectPopover>
          </div>

          {audioUrl && (
            <>
              <button
                onClick={handlePlayPause}
                className="w-7 h-7 flex items-center justify-center rounded-full bg-white/10 hover:bg-white/20 text-white transition-colors"
                title={isPlaying ? "暂停" : "播放"}
              >
                {isPlaying ? "⏸" : "▶"}
              </button>
              <span ref={timeRef} className="tabular-nums">00:00.0</span>
              <span className="text-gray-600">/</span>
              <span className="tabular-nums">{formatTime(audioDuration)}</span>
            </>
          )}
        </div>
      </div>

      {/* Waveform — always rendered so ref stays mounted */}
      <div className="relative mb-1">
        <div ref={waveCallbackRef} className="rounded-lg overflow-hidden bg-black/20 cursor-pointer" style={{ minHeight: 56 }} />
      </div>

      {/* Segment blocks or empty placeholder */}
      {hasSegments ? (
        <>
          <div className="relative h-14 flex select-none">
            {/* Playhead — syncs with audio playback */}
            <div
              ref={playheadRef}
              className="absolute top-0 h-full w-0.5 bg-fuchsia-400 z-10 pointer-events-none"
              style={{ display: "none", left: "0%" }}
            />
            {visibleSegments.map((seg, i) => {
              const left = (seg.start / audioDuration) * 100;
              const width = ((seg.end - seg.start) / audioDuration) * 100;
              const segDur = seg.end - seg.start;
              const isDragTarget = dragOverIdx === i && dragFromIdx !== i;

              // Compute loop portion for the last visible segment
              const isLastVisible = i === visibleSegments.length - 1;
              let loopPercent = 0;
              if (isLastVisible && audioDuration > 0) {
                const mat = materials.find((m) => m.id === seg.materialId);
                const matDur = mat?.duration_sec ?? 0;
                const effDur = (seg.sourceEnd > seg.sourceStart)
                  ? (seg.sourceEnd - seg.sourceStart)
                  : Math.max(matDur - seg.sourceStart, 0);
                if (effDur > 0 && segDur > effDur + 0.1) {
                  loopPercent = ((segDur - effDur) / segDur) * 100;
                }
              }

              return (
                <div key={seg.id} className="absolute top-0 h-full" style={{ left: `${left}%`, width: `${width}%` }}>
                  <button
                    draggable
                    onDragStart={(e) => handleDragStart(i, e)}
                    onDragOver={(e) => handleDragOver(i, e)}
                    onDragLeave={handleDragLeave}
                    onDrop={(e) => handleDrop(i, e)}
                    onDragEnd={handleDragEnd}
                    onClick={() => onClickSegment(seg)}
                    className={`relative w-full h-full rounded-lg flex flex-col items-center justify-center overflow-hidden cursor-grab active:cursor-grabbing transition-all border ${
                      isDragTarget
                        ? "ring-2 ring-purple-400 border-purple-400 scale-[1.02]"
                        : dragFromIdx === i
                        ? "opacity-50 border-white/10"
                        : "hover:opacity-90 border-white/10"
                    }`}
                    style={{ backgroundColor: seg.color + "33", borderColor: isDragTarget ? undefined : seg.color + "66" }}
                    title={`拖拽可调换顺序 · 点击设置截取范围\n${seg.materialName}\n${segDur.toFixed(1)}s${loopPercent > 0 ? ` (含循环 ${(segDur * loopPercent / 100).toFixed(1)}s)` : ""}`}
                  >
                    <GripVertical className="absolute top-0.5 left-0.5 h-3 w-3 text-white/30 z-[1]" />
                    <span className="text-[11px] text-white/90 truncate max-w-full px-1 leading-tight z-[1]">
                      {seg.materialName}
                    </span>
                    <span className="text-[10px] text-white/60 leading-tight z-[1]">
                      {segDur.toFixed(1)}s
                    </span>
                    {seg.sourceStart > 0 && (
                      <span className="text-[9px] text-amber-400/80 leading-tight z-[1]">
                        ✂ {seg.sourceStart.toFixed(1)}s
                      </span>
                    )}
                    {/* Loop fill stripe overlay */}
                    {loopPercent > 0 && (
                      <div
                        className="absolute top-0 right-0 h-full pointer-events-none flex items-center justify-center"
                        style={{
                          width: `${loopPercent}%`,
                          background: `repeating-linear-gradient(-45deg, transparent, transparent 3px, rgba(255,255,255,0.07) 3px, rgba(255,255,255,0.07) 6px)`,
                          borderLeft: "1px dashed rgba(255,255,255,0.25)",
                        }}
                      >
                        <span className="text-[9px] text-white/30">循环</span>
                      </div>
                    )}
                  </button>
                </div>
              );
            })}
          </div>

          {/* Overflow segments — shown as gray chips */}
          {overflowSegments.length > 0 && (
            <div className="flex flex-wrap items-center gap-1.5 mt-1.5">
              <span className="text-[10px] text-gray-500">未使用:</span>
              {overflowSegments.map((seg) => (
                <span
                  key={seg.id}
                  className="text-[10px] text-gray-500 bg-white/5 border border-white/10 rounded px-1.5 py-0.5"
                >
                  {seg.materialName}
                </span>
              ))}
            </div>
          )}

          <p className="text-[10px] text-gray-500 mt-1.5">
            点击波形定位播放 · 拖拽色块调换顺序 · 点击色块设置截取范围
          </p>
        </>
      ) : (
        <>
          <div className="h-14 bg-white/5 rounded-lg" />
          <p className="text-[10px] text-gray-500 mt-1.5">
            选中配音和素材后可编辑时间轴
          </p>
        </>
      )}
    </>
  );

  if (embedded) return content;

  return (
    <div className="bg-white/5 rounded-2xl p-4 sm:p-6 border border-white/10 backdrop-blur-sm">
      {content}
    </div>
  );
}
