"use client";

import { useSession } from "@/auth/session-provider";
import { getLiveKitWsUrl } from "@/lib/livekit/publicUrl";
import { useTranslations } from "next-intl";
import {
  useCallback,
  useEffect,
  useRef,
  useState,
} from "react";
import { Headphones, Loader2, Radio, Square, Volume2, VolumeX } from "lucide-react";

type ConnState = "idle" | "connecting" | "connected" | "error";

export default function YearlyVoiceStreamControl({
  streamToken,
  auctionState,
  className = "",
}: {
  streamToken?: string | null;
  auctionState?: string | null;
  className?: string;
}) {
  const session = useSession();
  const t = useTranslations("YEARLY_AUCTION_LIVE.voice");

  const [conn, setConn] = useState<ConnState>("idle");
  const [playbackMuted, setPlaybackMuted] = useState(false);
  const [errorHint, setErrorHint] = useState<string | null>(null);

  const roomRef = useRef<import("livekit-client").Room | null>(null);
  const audioElsRef = useRef<HTMLAudioElement[]>([]);
  const playbackMutedRef = useRef(false);

  const wsUrl = getLiveKitWsUrl();
  const token =
    typeof streamToken === "string" ? streamToken.trim() : "";
  const isLive =
    String(auctionState || "").toLowerCase() === "live";

  const canConnect = Boolean(token && isLive && wsUrl);

  const unavailableReason = !isLive
    ? t("not_live")
    : !wsUrl
      ? t("misconfigured")
      : !token
        ? session?.access_token
          ? t("no_token")
          : t("login_required")
        : null;

  const detachAndClearAudio = useCallback(() => {
    for (const el of audioElsRef.current) {
      try {
        el.pause();
        el.remove();
        el.srcObject = null;
      } catch {
        /* ignore */
      }
    }
    audioElsRef.current = [];
  }, []);

  const disconnectRoom = useCallback(async () => {
    const room = roomRef.current;
    roomRef.current = null;
    detachAndClearAudio();
    if (room) {
      try {
        await room.disconnect();
      } catch {
        /* ignore */
      }
    }
    setConn("idle");
    setErrorHint(null);
  }, [detachAndClearAudio]);

  useEffect(() => {
    playbackMutedRef.current = playbackMuted;
    for (const el of audioElsRef.current) {
      el.muted = playbackMuted;
    }
  }, [playbackMuted]);

  useEffect(() => {
    return () => {
      void disconnectRoom();
    };
  }, [disconnectRoom]);

  useEffect(() => {
    if (!canConnect && (conn === "connected" || conn === "connecting")) {
      void disconnectRoom();
    }
  }, [canConnect, conn, disconnectRoom]);

  const connect = useCallback(async () => {
    if (!canConnect) return;
    setErrorHint(null);
    setConn("connecting");

    let room: import("livekit-client").Room | null = null;

    try {
      const { Room, RoomEvent, Track } = await import("livekit-client");

      room = new Room({
        adaptiveStream: true,
        dynacast: true,
        disconnectOnPageLeave: true,
      });
      roomRef.current = room;

      const onTrackSubscribed = (
        track: import("livekit-client").RemoteTrack,
      ) => {
        if (track.kind !== Track.Kind.Audio) return;
        const el = track.attach() as HTMLAudioElement;
        el.setAttribute("playsinline", "true");
        el.style.display = "none";
        el.muted = playbackMutedRef.current;
        document.body.appendChild(el);
        audioElsRef.current.push(el);
        void el.play().catch(() => {});
      };

      const onTrackUnsubscribed = (
        track: import("livekit-client").RemoteTrack,
      ) => {
        if (track.kind !== Track.Kind.Audio) return;
        try {
          track.detach();
        } catch {
          /* ignore */
        }
        const attached = track.attachedElements;
        audioElsRef.current = audioElsRef.current.filter(
          (e) => !attached.includes(e),
        );
      };

      const onDisconnected = () => {
        detachAndClearAudio();
        if (roomRef.current === room) {
          roomRef.current = null;
        }
        setConn("idle");
      };

      room.on(RoomEvent.TrackSubscribed, onTrackSubscribed);
      room.on(RoomEvent.TrackUnsubscribed, onTrackUnsubscribed);
      room.on(RoomEvent.Disconnected, onDisconnected);

      await room.connect(wsUrl, token, { autoSubscribe: true });
      setConn("connected");
    } catch (e) {
      console.error("[YearlyVoiceStreamControl] connect failed", e);
      setErrorHint(t("connect_failed"));
      setConn("error");
      if (room) {
        try {
          await room.disconnect();
        } catch {
          /* ignore */
        }
      }
      roomRef.current = null;
      detachAndClearAudio();
    }
  }, [canConnect, detachAndClearAudio, token, t, wsUrl]);

  const stop = useCallback(() => {
    void disconnectRoom();
  }, [disconnectRoom]);

  if (!canConnect) {
    return (
      <div
        className={`inline-flex items-center gap-2 rounded-full border border-white/25 bg-white/10 px-3 py-1.5 text-xs font-medium text-white/90 ${className}`}
        title={unavailableReason || undefined}
      >
        <Headphones className="h-3.5 w-3.5 shrink-0 opacity-70" aria-hidden />
        <span className="max-w-[200px] truncate sm:max-w-none">
          {t("unavailable_short")}
        </span>
      </div>
    );
  }

  if (conn === "error") {
    return (
      <div
        className={`flex flex-wrap items-center gap-2 rounded-full border border-red-300/40 bg-red-950/30 px-3 py-1.5 text-xs text-white ${className}`}
      >
        <span className="font-medium">{errorHint || t("connect_failed")}</span>
        <button
          type="button"
          onClick={() => void connect()}
          className="rounded-full bg-white/15 px-2.5 py-0.5 font-semibold hover:bg-white/25"
        >
          {t("retry")}
        </button>
      </div>
    );
  }

  if (conn === "idle") {
    return (
      <div className={`flex items-center gap-2 ${className}`}>
        <button
          type="button"
          onClick={() => void connect()}
          className="inline-flex items-center gap-1.5 rounded-full border border-emerald-300/50 bg-emerald-600/90 px-3 py-1.5 text-xs font-bold text-white shadow-sm hover:bg-emerald-500/90"
        >
          <Radio className="h-3.5 w-3.5" aria-hidden />
          {t("listen")}
        </button>
      </div>
    );
  }

  if (conn === "connecting") {
    return (
      <div
        className={`inline-flex items-center gap-2 rounded-full border border-white/25 bg-white/10 px-3 py-1.5 text-xs font-medium text-white ${className}`}
      >
        <Loader2 className="h-3.5 w-3.5 animate-spin" aria-hidden />
        {t("connecting")}
      </div>
    );
  }

  return (
    <div
      className={`flex flex-wrap items-center gap-2 rounded-full border border-white/25 bg-white/10 px-2 py-1 sm:px-3 sm:py-1.5 ${className}`}
    >
      <span className="inline-flex items-center gap-1 px-1 text-xs font-bold text-white">
        <span className="relative flex h-2 w-2">
          <span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-emerald-400 opacity-60" />
          <span className="relative inline-flex h-2 w-2 rounded-full bg-emerald-400" />
        </span>
        {t("listening")}
      </span>
      <button
        type="button"
        onClick={() => setPlaybackMuted((m) => !m)}
        className="inline-flex items-center gap-1 rounded-full bg-white/15 px-2.5 py-1 text-xs font-semibold text-white hover:bg-white/25"
        aria-pressed={playbackMuted}
      >
        {playbackMuted ? (
          <VolumeX className="h-3.5 w-3.5" aria-hidden />
        ) : (
          <Volume2 className="h-3.5 w-3.5" aria-hidden />
        )}
        {playbackMuted ? t("unmute") : t("mute")}
      </button>
      <button
        type="button"
        onClick={stop}
        className="inline-flex items-center gap-1 rounded-full bg-white/10 px-2 py-1 text-xs font-medium text-white/90 hover:bg-white/20"
      >
        <Square className="h-3 w-3 fill-current" aria-hidden />
        {t("stop")}
      </button>
    </div>
  );
}
