import { Mic, Pause, Upload } from 'lucide-react';
import { useRef, useState } from 'react';

import {
  type CreativeAudioAsset,
  readCreativeAudioFileAsAsset,
} from './creativeAudioFileAsset';

type CreativeAudioInputPanelProps<TAsset extends CreativeAudioAsset> = {
  disabled?: boolean;
  title: string;
  defaultLabel: string;
  limitLabel?: string;
  asset: TAsset | null;
  buildRecordedFileName: () => string;
  onAssetChange: (asset: TAsset | null) => void;
  onError: (message: string | null) => void;
  readFileAsAsset?: (
    file: File,
    source: 'uploaded' | 'recorded',
  ) => Promise<TAsset>;
};

export function CreativeAudioInputPanel<TAsset extends CreativeAudioAsset>({
  disabled = false,
  title,
  defaultLabel,
  limitLabel,
  asset,
  buildRecordedFileName,
  onAssetChange,
  onError,
  readFileAsAsset = readCreativeAudioFileAsAsset,
}: CreativeAudioInputPanelProps<TAsset>) {
  const [isRecording, setIsRecording] = useState(false);
  const recorderRef = useRef<MediaRecorder | null>(null);
  const chunksRef = useRef<BlobPart[]>([]);

  const startRecording = async () => {
    if (disabled || isRecording) {
      return;
    }

    try {
      if (
        typeof navigator === 'undefined' ||
        !navigator.mediaDevices?.getUserMedia ||
        typeof MediaRecorder === 'undefined'
      ) {
        throw new Error('当前浏览器不支持录音。');
      }
      const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
      const recorder = new MediaRecorder(stream);
      chunksRef.current = [];
      recorder.ondataavailable = (event) => {
        if (event.data.size > 0) {
          chunksRef.current.push(event.data);
        }
      };
      recorder.onstop = () => {
        const blob = new Blob(chunksRef.current, {
          type: recorder.mimeType || 'audio/webm',
        });
        stream.getTracks().forEach((track) => track.stop());
        const file = new File([blob], buildRecordedFileName(), {
          type: blob.type,
        });
        void readFileAsAsset(file, 'recorded')
          .then(onAssetChange)
          .catch((caughtError) => {
            onError(
              caughtError instanceof Error
                ? caughtError.message
                : '录音保存失败。',
            );
          });
      };
      recorderRef.current = recorder;
      recorder.start();
      setIsRecording(true);
      onError(null);
    } catch (caughtError) {
      onError(
        caughtError instanceof Error ? caughtError.message : '录音启动失败。',
      );
    }
  };

  const stopRecording = () => {
    recorderRef.current?.stop();
    recorderRef.current = null;
    setIsRecording(false);
  };

  return (
    <section className="platform-subpanel rounded-[1.25rem] p-4">
      <div className="mb-3 flex items-center justify-between gap-3">
        <div className="flex min-w-0 items-center gap-2">
          <div className="text-sm font-black text-[var(--platform-text-strong)]">
            {title}
          </div>
          {limitLabel ? (
            <div className="rounded-full bg-white/70 px-2 py-1 text-[11px] font-black text-[var(--platform-text-soft)]">
              {limitLabel}
            </div>
          ) : null}
        </div>
        {asset ? (
          <button
            type="button"
            onClick={() => onAssetChange(null)}
            disabled={disabled}
            className="platform-button platform-button--ghost min-h-0 px-3 py-2 text-xs"
          >
            重置
          </button>
        ) : null}
      </div>
      <div className="mt-3 flex flex-wrap items-center gap-2">
        <label
          className={`platform-button platform-button--secondary min-h-10 cursor-pointer gap-2 px-3 py-2 text-sm ${
            disabled ? 'pointer-events-none opacity-55' : ''
          }`}
        >
          <Upload className="h-4 w-4" />
          上传
          <input
            type="file"
            accept="audio/*"
            disabled={disabled}
            className="sr-only"
            onChange={(event) => {
              const file = event.currentTarget.files?.[0] ?? null;
              event.currentTarget.value = '';
              if (!file) {
                return;
              }
              void readFileAsAsset(file, 'uploaded')
                .then((nextAsset) => {
                  onError(null);
                  onAssetChange(nextAsset);
                })
                .catch((caughtError) => {
                  onError(
                    caughtError instanceof Error
                      ? caughtError.message
                      : '音频读取失败。',
                  );
                });
            }}
          />
        </label>
        <button
          type="button"
          disabled={disabled}
          onClick={() => {
            if (isRecording) {
              stopRecording();
              return;
            }
            void startRecording();
          }}
          className="platform-button platform-button--ghost min-h-10 gap-2 px-3 py-2 text-sm"
        >
          {isRecording ? (
            <Pause className="h-4 w-4" />
          ) : (
            <Mic className="h-4 w-4" />
          )}
          {isRecording ? '停止' : '录音'}
        </button>
        {asset?.audioSrc ? (
          <audio controls src={asset.audioSrc} className="h-10 max-w-full" />
        ) : (
          <div className="text-xs font-bold text-[var(--platform-text-soft)]">
            {asset ? '音效已选择' : defaultLabel}
          </div>
        )}
      </div>
    </section>
  );
}

export default CreativeAudioInputPanel;
