import { useContext, useEffect, useState } from "react";
import { API_URL } from "../config/api.ts";
import type { Dump } from "../model.ts";
import { formatBytes } from "../utils/format.ts";
import { IconPause, IconPlay, MediaPlayer } from "./MediaPlayer.tsx";
import { PlayerContext } from "../contexts/PlayerContext.ts";
import {
  BAR_GAP,
  BAR_W,
  extractPeaks,
  NUM_BARS,
  VIEWBOX_W,
  WAVEFORM_H,
} from "../utils/waveform.ts";

interface FilePreviewProps {
  dump: Dump;
  compact?: boolean;
  global?: boolean;
}

// Waveform preview for the dump detail page — routes to global player,
// reflects live play state and position from PlayerContext.
function AudioFilePreview(
  { fileUrl, mime, dump }: { fileUrl: string; mime: string; dump: Dump },
) {
  const { current, playing, currentTime, duration, play, togglePlay, seekTo } =
    useContext(PlayerContext);
  const [peaks, setPeaks] = useState<Float32Array | null>(null);
  const isActive = current?.kind === "file" && current.fileUrl === fileUrl;
  const progress = isActive && duration > 0 ? currentTime / duration : 0;

  useEffect(() => {
    let cancelled = false;
    extractPeaks(fileUrl, NUM_BARS)
      .then((p) => {
        if (!cancelled) setPeaks(p);
      })
      .catch(() => {});
    return () => {
      cancelled = true;
    };
  }, [fileUrl]);

  const handlePlayBtn = () => {
    if (isActive) togglePlay();
    else play({ kind: "file", fileUrl, mimeType: mime, title: dump.title });
  };

  const handleWaveformClick = (e: React.MouseEvent<Element>) => {
    const rect = e.currentTarget.getBoundingClientRect();
    const ratio = Math.max(
      0,
      Math.min(1, (e.clientX - rect.left) / rect.width),
    );
    if (isActive) {
      seekTo(ratio * duration);
    } else {
      // Start playing and seek once it loads — seekTo after play() is a no-op
      // until MediaPlayer mounts; the fraction is best-effort on first click
      play({ kind: "file", fileUrl, mimeType: mime, title: dump.title });
    }
  };

  const isPlaying = isActive && playing;

  return (
    <div
      className={`audio-file-preview${
        isActive ? " audio-file-preview--active" : ""
      }`}
    >
      <button
        type="button"
        className="audio-player-btn"
        onClick={handlePlayBtn}
        aria-label={isPlaying ? "Pause" : "Play"}
      >
        {isPlaying ? <IconPause /> : <IconPlay />}
      </button>
      {peaks
        ? (
          <svg
            viewBox={`0 0 ${VIEWBOX_W} ${WAVEFORM_H}`}
            preserveAspectRatio="none"
            className="waveform-svg"
            onClick={handleWaveformClick}
          >
            {Array.from(peaks).map((p, i) => {
              const barH = Math.max(p * WAVEFORM_H, 2);
              const x = i * (BAR_W + BAR_GAP);
              const y = (WAVEFORM_H - barH) / 2;
              const played = i / NUM_BARS <= progress;
              return (
                <rect
                  key={i}
                  x={x}
                  y={y}
                  width={BAR_W}
                  height={barH}
                  className={`waveform-bar${
                    played ? " waveform-bar--played" : ""
                  }`}
                />
              );
            })}
          </svg>
        )
        : (
          <div className="waveform-skeleton" onClick={handleWaveformClick}>
            <div
              className="waveform-skeleton-fill"
              style={{ width: `${progress * 100}%` }}
            />
          </div>
        )}
    </div>
  );
}

function VideoThumb({ src, fallback }: { src: string; fallback: string }) {
  const [failed, setFailed] = useState(false);
  if (failed) {
    return <span className="rich-content-compact-icon">{fallback}</span>;
  }
  return (
    <img
      src={src}
      alt=""
      className="rich-content-compact-thumbnail"
      onError={() => setFailed(true)}
    />
  );
}

function mimeIcon(mime: string): string {
  if (mime.startsWith("video/")) return "🎬";
  if (mime.startsWith("audio/")) return "🎵";
  if (mime === "application/pdf") return "📄";
  if (mime.startsWith("text/")) return "📝";
  return "📁";
}

export default function FilePreview(
  { dump, compact = false, global: useGlobal = false }: FilePreviewProps,
) {
  const { current, playing, play, togglePlay } = useContext(PlayerContext);
  const fileUrl = `${API_URL}/api/files/${dump.id}?v=${dump.fileSize ?? 0}`;
  const mime = dump.fileMime ?? "";
  const isPlaying = current?.kind === "file" && current.fileUrl === fileUrl;

  if (compact) {
    if (mime.startsWith("image/")) {
      return (
        <img
          src={fileUrl}
          alt={dump.fileName}
          className="rich-content-compact-thumbnail"
          onError={(e) => {
            (e.target as HTMLImageElement).style.display = "none";
          }}
        />
      );
    }
    if (mime.startsWith("video/")) {
      const thumbUrl = `${API_URL}/api/thumbnails/${dump.id}`;
      return (
        <button
          type="button"
          className={`rich-content-thumbnail-btn${
            isPlaying ? " is-playing" : ""
          }`}
          onClick={(e) => {
            e.preventDefault();
            e.stopPropagation();
            play({ kind: "file", fileUrl, mimeType: mime, title: dump.title });
          }}
        >
          <VideoThumb src={thumbUrl} fallback={mimeIcon(mime)} />
          <span className="rich-content-play-overlay">▶</span>
        </button>
      );
    }
    if (mime.startsWith("audio/")) {
      return (
        <button
          type="button"
          className={`rich-content-thumbnail-btn${
            isPlaying ? " is-playing" : ""
          }`}
          onClick={(e) => {
            e.preventDefault();
            e.stopPropagation();
            play({ kind: "file", fileUrl, mimeType: mime, title: dump.title });
          }}
        >
          <span className="rich-content-compact-icon">{mimeIcon(mime)}</span>
        </button>
      );
    }
    return <span className="rich-content-compact-icon">{mimeIcon(mime)}</span>;
  }

  if (mime.startsWith("image/")) {
    return (
      <img src={fileUrl} alt={dump.fileName} className="file-preview-image" />
    );
  }

  if (mime.startsWith("video/")) {
    if (useGlobal) {
      const videoActive = isPlaying;
      const videoPlaying = videoActive && playing;
      return (
        <button
          type="button"
          className={`file-preview-play-btn${videoActive ? " is-playing" : ""}`}
          onClick={() =>
            videoActive ? togglePlay() : play({
              kind: "file",
              fileUrl,
              mimeType: mime,
              title: dump.title,
            })}
        >
          <video
            src={fileUrl}
            preload="none"
            className="file-preview-video-thumb"
            muted
          />
          <span className="rich-content-play-overlay">
            {videoPlaying ? "⏸" : "▶"}
          </span>
        </button>
      );
    }
    return <MediaPlayer src={fileUrl} kind="video" mime={mime} />;
  }

  if (mime.startsWith("audio/")) {
    if (useGlobal) {
      return <AudioFilePreview fileUrl={fileUrl} mime={mime} dump={dump} />;
    }
    return <MediaPlayer src={fileUrl} kind="audio" mime={mime} />;
  }

  if (mime === "application/pdf") {
    return (
      <embed
        src={fileUrl}
        type="application/pdf"
        className="file-preview-pdf"
      />
    );
  }

  return (
    <a href={fileUrl} download={dump.fileName} className="file-download-link">
      {mimeIcon(mime)} Download {dump.fileName}
      {dump.fileSize != null && ` (${formatBytes(dump.fileSize)})`}
    </a>
  );
}
