"use client";

import { LockKeyhole, Pause, Play } from "lucide-react";
import { useEffect, useRef, useState } from "react";

import { useCachedChatMediaUrl } from "@/lib/chat/use_cached_chat_media_url";
import styles from "./voice-bubble.module.css";

export interface VoiceBubbleProps {
  messageId?: string;
  audioUrl?: string | null;
  isFromAI: boolean;
  locked?: boolean;
  hint?: string | null;
  isUnlocking?: boolean;
  onUnlock?: () => void;
}

export function VoiceBubble({
  messageId,
  audioUrl,
  isFromAI,
  locked = false,
  hint,
  isUnlocking = false,
  onUnlock,
}: VoiceBubbleProps) {
  const audioRef = useRef<HTMLAudioElement>(null);
  const [isPlaying, setIsPlaying] = useState(false);
  const [errorMediaUrl, setErrorMediaUrl] = useState<string | null>(null);
  const hasAudio = audioUrl != null && audioUrl.length > 0;
  const { mediaUrl, isUsingCachedMedia, reportMediaError } =
    useCachedChatMediaUrl({
      messageId,
      remoteUrl: audioUrl,
      kind: "audio",
    });

  useEffect(() => {
    const audio = audioRef.current;
    if (!audio) return;

    const handleEnded = () => setIsPlaying(false);
    const handlePause = () => setIsPlaying(false);
    const handlePlay = () => setIsPlaying(true);
    const handleError = () => {
      if (isUsingCachedMedia) {
        reportMediaError();
        return;
      }
      setErrorMediaUrl(mediaUrl);
      setIsPlaying(false);
    };

    audio.addEventListener("ended", handleEnded);
    audio.addEventListener("pause", handlePause);
    audio.addEventListener("play", handlePlay);
    audio.addEventListener("error", handleError);
    return () => {
      audio.removeEventListener("ended", handleEnded);
      audio.removeEventListener("pause", handlePause);
      audio.removeEventListener("play", handlePlay);
      audio.removeEventListener("error", handleError);
    };
  }, [isUsingCachedMedia, mediaUrl, reportMediaError]);

  const hasError = errorMediaUrl === mediaUrl;

  const handleToggle = () => {
    if (locked || !hasAudio) return;

    const audio = audioRef.current;
    if (!audio || hasError) return;

    if (isPlaying) {
      audio.pause();
      return;
    }

    void audio.play().catch(() => {
      setErrorMediaUrl(mediaUrl);
      setIsPlaying(false);
    });
  };

  return (
    <div
      className={`${styles.bubble} ${
        isFromAI ? styles.bubbleAi : styles.bubbleUser
      } ${locked ? styles.locked : ""}`}
    >
      <button
        type="button"
        className={styles.playButton}
        onClick={handleToggle}
        disabled={locked || hasError || !hasAudio}
        aria-label={isPlaying ? "Pause voice message" : "Play voice message"}
      >
        {locked ? (
          <LockKeyhole size={18} />
        ) : isPlaying ? (
          <Pause size={18} />
        ) : (
          <Play size={18} />
        )}
      </button>
      <div className={styles.body}>
        <div className={styles.wave} aria-hidden="true">
          <span />
          <span />
          <span />
          <span />
          <span />
        </div>
        {hasError ? (
          <p className={styles.error}>Voice message failed to load.</p>
        ) : null}
        {locked ? (
          <>
            <p className={styles.hint}>
              {hint && hint.length > 0
                ? hint
                : "Elio has a locked voice message for you."}
            </p>
            <button
              type="button"
              className={styles.unlockButton}
              disabled={isUnlocking || !onUnlock}
              onClick={onUnlock}
            >
              {isUnlocking ? "Unlocking..." : "Unlock voice message"}
            </button>
          </>
        ) : null}
      </div>
      {!locked && hasAudio ? (
        <audio ref={audioRef} src={mediaUrl} preload="metadata" />
      ) : null}
    </div>
  );
}
