import { useCallback, useEffect, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';

import { playNotificationTone } from '../lib/notificationSound';
import {
  clearCustomNotificationSound,
  getCustomNotificationSoundMeta,
  MAX_NOTIFICATION_SOUND_BYTES,
  type NotificationSoundEntry,
  setCustomNotificationSound,
  subscribeNotificationSoundChanges,
} from '../lib/notificationSoundStorage';
import { SpinnerIcon, TrashIcon } from './icons';

interface Props {
  disabled?: boolean;
}

const BYTES_PER_MB = 1024 * 1024;

// UI for the custom new-message notification chime. Single file slot.
// Preview button calls playNotificationTone() directly so the user
// hears exactly what a real incoming message will sound like (same
// AudioContext, same volume curve).
export function NotificationSoundSettings({ disabled = false }: Props) {
  const { t } = useTranslation(['app']);
  const inputRef = useRef<HTMLInputElement | null>(null);
  const [current, setCurrent] = useState<NotificationSoundEntry | null>(null);
  const [busy, setBusy] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const refresh = useCallback(async () => {
    try {
      const meta = await getCustomNotificationSoundMeta();
      setCurrent(meta);
    } catch (err: unknown) {
      console.error('getCustomNotificationSoundMeta failed', err);
    }
  }, []);

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

  async function handleFile(file: File): Promise<void> {
    setError(null);
    setBusy(true);
    try {
      await setCustomNotificationSound(file);
      // refresh fires via subscribeNotificationSoundChanges
    } catch (err: unknown) {
      const code = err instanceof Error ? err.message : 'upload_failed';
      if (code === 'sound_too_large') {
        setError(
          t('app:settings.notif_sound_error_too_large', {
            defaultValue: 'Datei zu groß (max {{max}} MB).',
            max: MAX_NOTIFICATION_SOUND_BYTES / BYTES_PER_MB,
          }),
        );
      } else if (code === 'sound_not_audio') {
        setError(
          t('app:settings.notif_sound_error_not_audio', {
            defaultValue: 'Nur Audio-Dateien werden unterstützt.',
          }),
        );
      } else if (code === 'empty_file') {
        setError(
          t('app:settings.notif_sound_error_empty', {
            defaultValue: 'Leere Datei.',
          }),
        );
      } else {
        setError(
          t('app:settings.notif_sound_error_generic', {
            defaultValue: 'Ton konnte nicht gespeichert werden.',
          }),
        );
      }
    } finally {
      setBusy(false);
      if (inputRef.current) inputRef.current.value = '';
    }
  }

  async function handleReset(): Promise<void> {
    setError(null);
    setBusy(true);
    try {
      await clearCustomNotificationSound();
      // refresh fires via subscribeNotificationSoundChanges
    } catch (err: unknown) {
      console.error('clearCustomNotificationSound failed', err);
    } finally {
      setBusy(false);
    }
  }

  function handlePreview(): void {
    // Same code path as a real notification — user hears exactly what
    // peers triggering a message will cause.
    playNotificationTone();
  }

  const hasCustom = current !== null;
  const sizeMb = current ? (current.size / BYTES_PER_MB).toFixed(2) : null;
  const interactionsDisabled = disabled || busy;

  return (
    <div className="flex flex-col gap-3">
      <div className="flex items-start justify-between gap-4">
        <div className="min-w-0 flex-1">
          <div className="text-sm font-medium text-fg">
            {t('app:settings.notif_sound_title', { defaultValue: 'Benachrichtigungston' })}
          </div>
          <div className="mt-1 text-xs text-fg-muted">
            {hasCustom && current
              ? t('app:settings.notif_sound_custom_active', {
                  defaultValue: '{{name}} · {{size}} MB',
                  name: current.filename,
                  size: sizeMb,
                })
              : t('app:settings.notif_sound_default_active', {
                  defaultValue: 'Standard (Zwei-Ton-Chime)',
                })}
          </div>
        </div>

        <div className="flex shrink-0 items-center gap-2">
          <button
            type="button"
            onClick={handlePreview}
            disabled={interactionsDisabled}
            className="cursor-pointer rounded-lg border border-line bg-surface-3 px-3 py-1.5 text-xs font-semibold text-fg transition hover:brightness-95 disabled:cursor-not-allowed disabled:opacity-50"
          >
            {t('app:settings.notif_sound_preview', { defaultValue: 'Probe hören' })}
          </button>
          <input
            ref={inputRef}
            type="file"
            accept="audio/*"
            className="hidden"
            onChange={(e) => {
              const f = e.target.files?.[0];
              if (f) void handleFile(f);
            }}
          />
          <button
            type="button"
            onClick={() => inputRef.current?.click()}
            disabled={interactionsDisabled}
            className="inline-flex cursor-pointer items-center gap-1.5 rounded-lg bg-accent px-3 py-1.5 text-xs font-semibold text-accent-fg transition hover:brightness-110 disabled:cursor-not-allowed disabled:opacity-50"
          >
            {busy && <SpinnerIcon className="h-3.5 w-3.5" />}
            <span>
              {hasCustom
                ? t('app:settings.notif_sound_replace', { defaultValue: 'Ersetzen' })
                : t('app:settings.notif_sound_upload', { defaultValue: 'Hochladen' })}
            </span>
          </button>
          {hasCustom && (
            <button
              type="button"
              onClick={() => void handleReset()}
              disabled={interactionsDisabled}
              aria-label={t('app:settings.notif_sound_reset', { defaultValue: 'Zurücksetzen' })}
              title={t('app:settings.notif_sound_reset', { defaultValue: 'Zurücksetzen' })}
              className="flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg border border-rose-500/40 bg-rose-500/10 text-rose-600 transition hover:bg-rose-500/20 disabled:cursor-not-allowed disabled:opacity-50 dark:text-rose-300"
            >
              <TrashIcon className="h-4 w-4" />
            </button>
          )}
        </div>
      </div>

      {error && (
        <p className="rounded-md border border-rose-500/30 bg-rose-500/10 px-3 py-2 text-xs text-rose-600 dark:text-rose-300">
          {error}
        </p>
      )}

      <p className="text-[11px] text-fg-muted">
        {t('app:settings.notif_sound_hint', {
          defaultValue:
            'MP3, WAV, OGG oder M4A bis 1 MB. Spielt bei neuen Nachrichten in Chats die du nicht aktiv ansiehst.',
        })}
      </p>
    </div>
  );
}
