"use client";

import { useState, useMemo, useRef, useCallback } from "react";
import { Search, Clock, Users, Copy, Check, FileText, Download, Play, Pause, Loader2, SkipBack, SkipForward } from "lucide-react";
import { Input } from "@/components/ui/input";
import { Avatar, AvatarFallback } from "@/components/ui/avatar";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { ScrollArea } from "@/components/ui/scroll-area";
import { Separator } from "@/components/ui/separator";
import { SimpleTooltip } from "@/components/ui/tooltip";
import { cn, getInitials } from "@/lib/utils";
import type { TranscriptStatusData, TranscriptSegmentAPI } from "@/types/api";
import { downloadRecordingAudio, downloadFromS3 } from "@/lib/api/transcript.api";
import { useToast } from "@/store/toast.store";

// ─── Speaker color palette ────────────────────────────────────────────────────
const SPEAKER_COLORS = [
  { avatar: "bg-blue-100 text-blue-800 dark:bg-blue-900/60 dark:text-blue-300",   border: "border-l-blue-400 dark:border-l-blue-500" },
  { avatar: "bg-violet-100 text-violet-800 dark:bg-violet-900/60 dark:text-violet-300", border: "border-l-violet-400 dark:border-l-violet-500" },
  { avatar: "bg-emerald-100 text-emerald-800 dark:bg-emerald-900/60 dark:text-emerald-300", border: "border-l-emerald-400 dark:border-l-emerald-500" },
  { avatar: "bg-orange-100 text-orange-800 dark:bg-orange-900/60 dark:text-orange-300", border: "border-l-orange-400 dark:border-l-orange-500" },
  { avatar: "bg-pink-100 text-pink-800 dark:bg-pink-900/60 dark:text-pink-300",   border: "border-l-pink-400 dark:border-l-pink-500" },
];

function formatDuration(seconds: number): string {
  const h = Math.floor(seconds / 3600);
  const m = Math.floor((seconds % 3600) / 60);
  const s = Math.floor(seconds % 60);
  if (h > 0) return `${h}:${m.toString().padStart(2, "0")}:${s.toString().padStart(2, "0")}`;
  return `${m}:${s.toString().padStart(2, "0")}`;
}

// ─── Highlight matched text ───────────────────────────────────────────────────
function HighlightText({ text, query }: { text: string; query: string }) {
  if (!query.trim()) return <>{text}</>;

  const regex = new RegExp(`(${query.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")})`, "gi");
  const parts = text.split(regex);

  return (
    <>
      {parts.map((part, i) =>
        regex.test(part) ? (
          <mark
            key={i}
            className="bg-yellow-200 dark:bg-yellow-500/40 text-yellow-900 dark:text-yellow-200 rounded px-0.5 not-italic font-medium"
          >
            {part}
          </mark>
        ) : (
          <span key={i}>{part}</span>
        )
      )}
    </>
  );
}

interface TranscriptViewerProps {
  data: TranscriptStatusData;
}

export function TranscriptViewer({ data }: TranscriptViewerProps) {
  const [search, setSearch]         = useState("");
  const [copied, setCopied]         = useState(false);
  const [activeTab, setActiveTab]   = useState<"segments" | "fulltext">("segments");
  const [isPlaying, setIsPlaying]       = useState(false);
  const [audioLoading, setAudioLoading]  = useState(false);
  const [downloading, setDownloading]    = useState(false);
  const [currentTime, setCurrentTime]    = useState(0);
  const [duration, setDuration]          = useState(0);
  const audioRef                         = useRef<HTMLAudioElement | null>(null);
  const blobUrlRef                       = useRef<string | null>(null);
  const seekRef                          = useRef<HTMLInputElement | null>(null);
  const toast                            = useToast();

  const audio = data.audio;
  const hasPlayableAudio = !!(audio?.available && (audio.direct_url || audio.download_url));
  // Use direct S3 URL if available, otherwise fall back to backend proxy
  const isDirectS3 = !!(audio?.direct_url);

  const showAudioUnavailableToast = useCallback(() => {
    toast.warning(
      "Audio recording unavailable",
      "This older meeting does not include an audio download URL, so playback is disabled."
    );
  }, [toast]);

  async function fetchAudioBlob(): Promise<string> {
    if (!audio || !hasPlayableAudio) throw new Error("Audio recording is unavailable");
    if (blobUrlRef.current) return blobUrlRef.current;
    const url = isDirectS3 ? audio.direct_url! : `${process.env.NEXT_PUBLIC_API_BASE_URL}${audio.download_url}`;
    const fetchOptions: RequestInit = isDirectS3
      ? {}  // S3 pre-signed URL — no auth header
      : { headers: { Authorization: `Bearer ${sessionStorage.getItem("auth_token") || localStorage.getItem("auth_token") || ""}` } };
    const res = await fetch(url, fetchOptions);
    if (!res.ok) throw new Error("Failed to load audio");
    const blob = await res.blob();
    const blobUrl = URL.createObjectURL(blob);
    blobUrlRef.current = blobUrl;
    return blobUrl;
  }

  async function togglePlay() {
    const el = audioRef.current;
    if (!hasPlayableAudio) {
      showAudioUnavailableToast();
      return;
    }
    if (!el) return;
    if (isPlaying) { el.pause(); setIsPlaying(false); return; }
    try {
      setAudioLoading(true);
      const src = await fetchAudioBlob();
      if (!el.src || el.src !== src) { el.src = src; el.load(); }
      await el.play();
      setIsPlaying(true);
    } catch (e) {
      console.error("Audio playback failed", e);
    } finally {
      setAudioLoading(false);
    }
  }

  function skip(seconds: number) {
    if (!hasPlayableAudio) {
      showAudioUnavailableToast();
      return;
    }
    const el = audioRef.current;
    if (!el) return;
    el.currentTime = Math.min(Math.max(0, el.currentTime + seconds), el.duration || 0);
  }

  const handleSeek = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
    if (!hasPlayableAudio) {
      showAudioUnavailableToast();
      return;
    }
    const el = audioRef.current;
    if (!el) return;
    const val = Number(e.target.value);
    el.currentTime = val;
    setCurrentTime(val);
  }, [hasPlayableAudio, showAudioUnavailableToast]);

  function formatTime(s: number) {
    if (!s || isNaN(s)) return "0:00";
    const m = Math.floor(s / 60);
    const sec = Math.floor(s % 60);
    return `${m}:${sec.toString().padStart(2, "0")}`;
  }

  async function handleDownload() {
    if (!audio) return;
    setDownloading(true);
    try {
      const directDownloadUrl = audio.download_direct_url ?? audio.direct_url;
      const downloadFileName = audio.download_file_name ?? audio.file_name;

      if (directDownloadUrl) {
        await downloadFromS3(directDownloadUrl, downloadFileName);
      } else {
        await downloadRecordingAudio(audio.download_url, audio.file_name);
      }
    } finally {
      setDownloading(false);
    }
  }

  // Build speaker → color map
  const speakerColorMap = useMemo(() => {
    const map = new Map<string, typeof SPEAKER_COLORS[0]>();
    (data.participants ?? []).forEach((name, i) => {
      map.set(name, SPEAKER_COLORS[i % SPEAKER_COLORS.length]);
    });
    return map;
  }, [data.participants]);

  // Filter segments by search
  const filtered = useMemo(() => {
    const segments = data.transcript ?? [];
    if (!search.trim()) return segments;
    const q = search.toLowerCase();
    return segments.filter(
      (s) => s.text.toLowerCase().includes(q) || s.speaker.toLowerCase().includes(q)
    );
  }, [search, data.transcript]);

  const handleCopyFullText = () => {
    const text = data.full_text;
    if (navigator.clipboard && window.isSecureContext) {
      navigator.clipboard.writeText(text);
    } else {
      const el = document.createElement("textarea");
      el.value = text;
      el.style.position = "fixed";
      el.style.opacity = "0";
      document.body.appendChild(el);
      el.focus();
      el.select();
      document.execCommand("copy");
      document.body.removeChild(el);
    }
    setCopied(true);
    setTimeout(() => setCopied(false), 2000);
  };

  return (
    <div className="space-y-4">

      {/* ── Stats bar ── */}
      <div className="flex flex-wrap items-center gap-4 rounded-xl border border-gray-200 dark:border-gray-800 bg-gray-50 dark:bg-gray-800/50 px-4 py-3">
        <div className="flex items-center gap-2 text-sm text-gray-600 dark:text-gray-400">
          <Clock className="h-4 w-4 text-blue-500" />
          <span className="font-medium text-gray-900 dark:text-gray-100">{formatDuration(data.duration_seconds)}</span>
          <span>duration</span>
        </div>
        <Separator orientation="vertical" className="h-4 hidden sm:block" />
        <div className="flex items-center gap-2 text-sm text-gray-600 dark:text-gray-400">
          <Users className="h-4 w-4 text-blue-500" />
          <span className="font-medium text-gray-900 dark:text-gray-100">{data.participants?.length ?? 0}</span>
          <span>speakers</span>
        </div>
        <Separator orientation="vertical" className="h-4 hidden sm:block" />
        <div className="flex items-center gap-2 text-sm text-gray-600 dark:text-gray-400">
          <FileText className="h-4 w-4 text-blue-500" />
          <span className="font-medium text-gray-900 dark:text-gray-100">{data.transcript?.length ?? 0}</span>
          <span>segments</span>
        </div>

        {/* Speaker pills */}
        <div className="flex flex-wrap gap-1.5 ml-auto">
          {(data.participants ?? []).map((name) => {
            const color = speakerColorMap.get(name);
            return (
              <SimpleTooltip key={name} content={`Speaker: ${name}`}>
                <span
                  className={cn("inline-flex cursor-default items-center gap-1.5 rounded-full px-2.5 py-0.5 text-xs font-medium", color?.avatar)}
                >
                  <span className="h-1.5 w-1.5 rounded-full bg-current opacity-60" />
                  {name}
                </span>
              </SimpleTooltip>
            );
          })}
        </div>
      </div>

      {/* ── Audio player ── */}
      {audio && (
        <div className="rounded-xl border border-gray-200 dark:border-gray-800 bg-gray-50 dark:bg-gray-800/50 px-4 py-3 space-y-3">
          <audio
            ref={audioRef}
            onEnded={() => setIsPlaying(false)}
            onTimeUpdate={(e) => setCurrentTime(e.currentTarget.currentTime)}
            onLoadedMetadata={(e) => setDuration(e.currentTarget.duration)}
            className="hidden"
          />

          {/* File info + download */}
          <div className="flex items-center justify-between gap-3">
            <div className="min-w-0">
              <p className="text-xs font-medium text-gray-700 dark:text-gray-300 truncate">{audio.file_name}</p>
              <p className="text-[10px] text-gray-400 dark:text-gray-500 uppercase tracking-wide">
                {hasPlayableAudio ? audio.content_type.split("/")[1] : "Not available"}
              </p>
            </div>
            <SimpleTooltip content="Download recording video">
              <Button variant="outline" size="sm" onClick={handleDownload} disabled={downloading} className="gap-1.5 shrink-0">
                {downloading ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : <Download className="h-3.5 w-3.5" />}
                {downloading ? "Downloading…" : "Download"}
              </Button>
            </SimpleTooltip>
          </div>

          {/* Seek bar */}
          <div className="space-y-1">
            <SimpleTooltip content={`Seek audio: ${formatTime(currentTime)} / ${formatTime(duration)}`}>
              <input
                ref={seekRef}
                type="range"
                min={0}
                max={duration || 0}
                step={0.1}
                value={currentTime}
                onChange={handleSeek}
                disabled={!hasPlayableAudio}
                className={cn(
                  "w-full h-1.5 rounded-full appearance-none accent-blue-600 disabled:cursor-not-allowed disabled:opacity-60",
                  hasPlayableAudio && "cursor-pointer",
                  `
                  bg-gray-200 dark:bg-gray-700
                  [&::-webkit-slider-runnable-track]:rounded-full
                  [&::-webkit-slider-thumb]:w-3 [&::-webkit-slider-thumb]:h-3`
                )}
                style={{
                  background: hasPlayableAudio && duration
                    ? `linear-gradient(to right, rgb(37 99 235) ${(currentTime / duration) * 100}%, rgb(209 213 219) ${(currentTime / duration) * 100}%)`
                    : "rgb(209 213 219)",
                }}
              />
            </SimpleTooltip>
            <div className="flex justify-between text-[10px] text-gray-400 dark:text-gray-500 font-mono">
              <span>{formatTime(currentTime)}</span>
              <span>{formatTime(duration)}</span>
            </div>
          </div>

          {/* Controls */}
          <div className="flex items-center justify-center gap-4">
            <SimpleTooltip content="Rewind 10 seconds">
              <button
                onClick={() => skip(-10)}
                aria-disabled={!hasPlayableAudio}
                className={cn(
                  "flex flex-col items-center gap-0.5 text-gray-500 dark:text-gray-400 transition-colors",
                  hasPlayableAudio
                    ? "hover:text-gray-900 dark:hover:text-gray-100"
                    : "cursor-not-allowed opacity-50"
                )}
              >
                <SkipBack className="h-4 w-4" />
                <span className="text-[9px] font-medium">10s</span>
              </button>
            </SimpleTooltip>

            <SimpleTooltip content={!hasPlayableAudio ? "Audio recording unavailable" : isPlaying ? "Pause" : "Play"}>
              <button
                onClick={togglePlay}
                disabled={audioLoading}
                aria-disabled={!hasPlayableAudio}
                className={cn(
                  "flex h-10 w-10 items-center justify-center rounded-full text-white transition-colors shadow-sm disabled:opacity-60",
                  hasPlayableAudio
                    ? "bg-blue-600 hover:bg-blue-700"
                    : "cursor-not-allowed bg-gray-400 hover:bg-gray-400 dark:bg-gray-600 dark:hover:bg-gray-600"
                )}
              >
                {audioLoading
                  ? <Loader2 className="h-4 w-4 animate-spin" />
                  : isPlaying
                    ? <Pause className="h-4 w-4" />
                    : <Play className="h-4 w-4 translate-x-px" />}
              </button>
            </SimpleTooltip>

            <SimpleTooltip content="Forward 10 seconds">
              <button
                onClick={() => skip(10)}
                aria-disabled={!hasPlayableAudio}
                className={cn(
                  "flex flex-col items-center gap-0.5 text-gray-500 dark:text-gray-400 transition-colors",
                  hasPlayableAudio
                    ? "hover:text-gray-900 dark:hover:text-gray-100"
                    : "cursor-not-allowed opacity-50"
                )}
              >
                <SkipForward className="h-4 w-4" />
                <span className="text-[9px] font-medium">10s</span>
              </button>
            </SimpleTooltip>
          </div>
        </div>
      )}

      {/* ── Tab switcher ── */}
      <div className="flex items-center justify-between gap-3">
        <div className="flex rounded-lg border border-gray-200 dark:border-gray-700 p-0.5 bg-gray-50 dark:bg-gray-800">
          <SimpleTooltip content="View transcript organized by speaker">
            <button
              onClick={() => setActiveTab("segments")}
              className={cn(
                "px-3 py-1.5 text-sm font-medium rounded-md transition-colors",
                activeTab === "segments"
                  ? "bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100 shadow-sm"
                  : "text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300"
              )}
            >
              By Speaker
            </button>
          </SimpleTooltip>
          <SimpleTooltip content="View complete transcript as continuous text">
            <button
              onClick={() => setActiveTab("fulltext")}
              className={cn(
                "px-3 py-1.5 text-sm font-medium rounded-md transition-colors",
                activeTab === "fulltext"
                  ? "bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100 shadow-sm"
                  : "text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300"
              )}
            >
              Full Text
            </button>
          </SimpleTooltip>
        </div>

        {activeTab === "segments" && (
          <SimpleTooltip content="Search in transcript by word or speaker name">
            <div className="relative flex-1 max-w-xs">
              <Search className="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-gray-400 dark:text-gray-500" />
              <Input
                placeholder="Search transcript…"
                value={search}
                onChange={(e) => setSearch(e.target.value)}
                className="pl-9 h-9"
              />
            </div>
          </SimpleTooltip>
        )}

        {activeTab === "fulltext" && (
          <SimpleTooltip content={copied ? "Copied to clipboard" : "Copy all transcript text"}>
            <Button variant="outline" size="sm" onClick={handleCopyFullText} className="gap-1.5">
              {copied ? <Check className="h-3.5 w-3.5 text-green-500" /> : <Copy className="h-3.5 w-3.5" />}
              {copied ? "Copied" : "Copy all"}
            </Button>
          </SimpleTooltip>
        )}
      </div>

      {/* Search result count */}
      {search.trim() && activeTab === "segments" && (
        <p className="text-xs text-gray-500 dark:text-gray-400">
          {filtered.length === 0
            ? `No results for "${search}"`
            : `${filtered.length} segment${filtered.length !== 1 ? "s" : ""} matching "${search}"`}
        </p>
      )}

      {/* ── Segments view ── */}
      {activeTab === "segments" && (
        <ScrollArea className="h-[560px]">
          <div className="space-y-1 pr-3">
            {filtered.length === 0 ? (
              <div className="flex flex-col items-center justify-center py-16 text-center">
                <Search className="h-8 w-8 text-gray-300 dark:text-gray-600 mb-3" />
                <p className="text-sm text-gray-500 dark:text-gray-400">No results for &quot;{search}&quot;</p>
              </div>
            ) : (
              filtered.map((seg, i) => (
                <SegmentRow
                  key={i}
                  segment={seg}
                  color={speakerColorMap.get(seg.speaker)}
                  searchQuery={search}
                />
              ))
            )}
          </div>
        </ScrollArea>
      )}

      {/* ── Full text view ── */}
      {activeTab === "fulltext" && (
        <ScrollArea className="h-[560px]">
          <div className="pr-3">
            <p className="text-sm text-gray-700 dark:text-gray-300 leading-relaxed whitespace-pre-wrap">
              {data.full_text}
            </p>
          </div>
        </ScrollArea>
      )}
    </div>
  );
}

// ─── Single segment row ───────────────────────────────────────────────────────
function SegmentRow({
  segment,
  color,
  searchQuery,
}: {
  segment: TranscriptSegmentAPI;
  color?: typeof SPEAKER_COLORS[0];
  searchQuery: string;
}) {
  const [expanded, setExpanded] = useState(false);
  const isLong = segment.text.length > 200;

  return (
    <div
      className={cn(
        "group flex gap-3 rounded-xl p-3 border-l-2 transition-colors hover:bg-gray-50 dark:hover:bg-gray-800/50",
        color?.border ?? "border-l-gray-300 dark:border-l-gray-600"
      )}
    >
      {/* Avatar */}
      <Avatar className="h-8 w-8 shrink-0 mt-0.5">
        <AvatarFallback className={cn("text-xs font-semibold", color?.avatar)}>
          {getInitials(segment.speaker)}
        </AvatarFallback>
      </Avatar>

      {/* Content */}
      <div className="flex-1 min-w-0 space-y-1">
        <div className="flex items-center gap-2 flex-wrap">
          <span className="text-sm font-semibold text-gray-900 dark:text-gray-100">
            <HighlightText text={segment.speaker} query={searchQuery} />
          </span>
          <Badge variant="outline" className="text-[10px] py-0 font-mono">
            {segment.start_formatted}
          </Badge>
          <span className="text-[10px] text-gray-400 dark:text-gray-500">→ {segment.end_formatted}</span>
        </div>
        <p className={cn("text-sm text-gray-700 dark:text-gray-300 leading-relaxed", !expanded && isLong && "line-clamp-3")}>
          <HighlightText text={segment.text} query={searchQuery} />
        </p>
        {isLong && (
          <button
            onClick={() => setExpanded(!expanded)}
            className="text-xs text-blue-600 dark:text-blue-400 hover:underline"
          >
            {expanded ? "Show less" : "Show more"}
          </button>
        )}
      </div>
    </div>
  );
}
