import clsx from "clsx";
import { t } from "i18next";
import { FC, useEffect, useRef, useState } from "react";

import { feedbackToast } from "@/utils/common";

import { IMessageItemProps } from ".";
import styles from "./message-item.module.scss";

const PLAYED_KEY = "chaglian_played_sounds";

const getPlayedMap = (): Record<string, boolean> => {
  try {
    return JSON.parse(localStorage.getItem(PLAYED_KEY) ?? "{}");
  } catch (error) {
    return {};
  }
};

const markPlayed = (clientMsgID: string) => {
  const map = getPlayedMap();
  map[clientMsgID] = true;
  localStorage.setItem(PLAYED_KEY, JSON.stringify(map));
};

const SoundIcon = ({ className }: { className?: string }) => (
  <svg width="18" height="18" viewBox="0 0 24 24" fill="none" className={className}>
    <path
      d="M4 9.5v5h3.5L12 18.5v-13L7.5 9.5H4Z"
      fill="currentColor"
    />
    <path
      d="M15 9.2a4 4 0 0 1 0 5.6M17.5 6.8a7.4 7.4 0 0 1 0 10.4"
      stroke="currentColor"
      strokeWidth="1.6"
      strokeLinecap="round"
    />
  </svg>
);

const SoundMessageRender: FC<IMessageItemProps> = ({ message, isSender }) => {
  const soundElem = message.soundElem;
  const duration = Math.max(1, Math.round(soundElem?.duration ?? 0));
  const [playing, setPlaying] = useState(false);
  const [played, setPlayed] = useState(
    () => Boolean(getPlayedMap()[message.clientMsgID]),
  );
  const audioRef = useRef<HTMLAudioElement>();

  useEffect(() => {
    return () => {
      audioRef.current?.pause();
      audioRef.current = undefined;
    };
  }, []);

  // 宽度随时长微变：60~180px
  const width = Math.min(180, 60 + duration * 6);

  const play = () => {
    const url = soundElem?.sourceUrl || soundElem?.soundPath;
    if (!url || playing) return;
    const audio = new Audio(url);
    audioRef.current = audio;
    setPlaying(true);
    audio.onended = () => setPlaying(false);
    audio.onerror = () => {
      setPlaying(false);
      feedbackToast({ msg: t("toast.accessFailed"), error: new Error("audio error") });
    };
    audio.play().catch(() => setPlaying(false));
    markPlayed(message.clientMsgID);
    setPlayed(true);
  };

  return (
    <div className="flex items-center">
      <div
        className={clsx(
          styles.bubble,
          "flex cursor-pointer items-center justify-between text-sm",
          isSender && "flex-row-reverse",
        )}
        style={{ width }}
        onClick={play}
      >
        <SoundIcon className="shrink-0" />
        <span className={clsx(isSender ? "mr-2" : "ml-2")}>{duration}″</span>
      </div>
      {!isSender && !played && (
        <span className="ml-2 h-2 w-2 shrink-0 rounded-full bg-[var(--warn-text)]" />
      )}
    </div>
  );
};

export default SoundMessageRender;
