import {
  type DeviceRecord,
  restoreDeviceFromServerRecord,
} from '@chat-app/shared/auth';
import { useCallback, useState } from 'react';
import { useTranslation } from 'react-i18next';

import {
  decodePrivateKeyFromBackup,
  importDeviceBackup,
  normalizeRecoveryCode,
} from '../lib/deviceBackup';
import { devLocalSecretStore } from '../lib/secretStore';
import { supabase } from '../lib/supabase';
import { writeLocalDeviceId } from '../lib/device';
import { AlertIcon, ArrowRightIcon, LockIcon, ShieldIcon, SpinnerIcon } from './icons';

interface Props {
  userId: string;
  onRestored: (device: DeviceRecord) => void;
}

// Restores a device from a user-provided backup string. The backup embeds
// userId + deviceId + X25519 private key; we verify userId matches the current
// session, confirm the device row still exists server-side, and then re-seed
// the local vault + cached deviceId so the app treats this install as the
// original device (conv-key bundles stay valid, no "awaiting" state).
export function DeviceRestore({ userId, onRestored }: Props) {
  const { t } = useTranslation(['app', 'errors']);
  const [backup, setBackup] = useState('');
  const [passphrase, setPassphrase] = useState('');
  const [mode, setMode] = useState<'passphrase' | 'recovery'>('passphrase');
  const [busy, setBusy] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const handleSubmit = useCallback(
    async (e: React.FormEvent) => {
      e.preventDefault();
      if (!backup.trim() || passphrase.length < 1 || busy) return;
      setBusy(true);
      setError(null);
      let privateKey: Uint8Array | null = null;
      try {
        const secret =
          mode === 'recovery' ? normalizeRecoveryCode(passphrase) : passphrase;
        const payload = await importDeviceBackup(backup.trim(), secret);
        privateKey = decodePrivateKeyFromBackup(payload);

        const device = await restoreDeviceFromServerRecord({
          client: supabase,
          secretStore: devLocalSecretStore,
          userId: payload.userId,
          deviceId: payload.deviceId,
          privateKey,
        });

        // Cache deviceId locally so findExistingDevice picks it up on next load.
        writeLocalDeviceId(userId, device.id);

        onRestored(device);
      } catch (err: unknown) {
        setError(err instanceof Error ? err.message : String(err));
      } finally {
        if (privateKey) {
          for (let i = 0; i < privateKey.length; i++) privateKey[i] = 0;
        }
        setBusy(false);
      }
    },
    [backup, passphrase, mode, userId, onRestored, busy],
  );

  return (
    <form
      onSubmit={handleSubmit}
      className="w-full max-w-md animate-slide-up rounded-2xl border border-white/10 bg-ink-900/70 p-7 shadow-glow backdrop-blur-xl sm:p-8"
    >
      <div className="flex items-center gap-3">
        <div className="flex h-10 w-10 items-center justify-center rounded-lg bg-emerald-500/20 ring-1 ring-emerald-400/30">
          <ShieldIcon className="h-5 w-5 text-emerald-300" />
        </div>
        <div>
          <h2 className="font-display text-lg font-semibold text-white">
            {t('app:backup.restore_title', { defaultValue: 'Backup wiederherstellen' })}
          </h2>
          <p className="text-xs text-neutral-400">
            {t('app:backup.restore_subtitle', {
              defaultValue: 'Bringe einen zuvor erstellten Backup-String + Passphrase mit.',
            })}
          </p>
        </div>
      </div>

      <div className="mt-6 space-y-3">
        <div className="space-y-1">
          <label className="block text-xs font-medium uppercase tracking-wide text-neutral-400">
            {t('app:backup.backup_string', { defaultValue: 'Backup-String' })}
          </label>
          <textarea
            required
            rows={5}
            value={backup}
            onChange={(e) => setBackup(e.target.value)}
            placeholder="chatapp-backup-v1…"
            className="w-full resize-none rounded-lg border border-white/10 bg-ink-800 px-3 py-2.5 font-mono text-[11px] leading-relaxed text-white placeholder-neutral-500 transition focus:border-brand-400 focus:outline-none focus:ring-2 focus:ring-brand-500/40"
          />
        </div>
        <div className="space-y-1">
          <div className="flex items-center justify-between">
            <label className="block text-xs font-medium uppercase tracking-wide text-neutral-400">
              {mode === 'passphrase' ? 'Passphrase' : 'Recovery-Code'}
            </label>
            <button
              type="button"
              onClick={() => {
                setMode((m) => (m === 'passphrase' ? 'recovery' : 'passphrase'));
                setPassphrase('');
                setError(null);
              }}
              className="cursor-pointer text-[11px] font-semibold text-brand-300 hover:underline"
            >
              {mode === 'passphrase'
                ? 'Passphrase vergessen? Recovery-Code nutzen'
                : 'Stattdessen Passphrase eingeben'}
            </button>
          </div>
          <input
            type={mode === 'passphrase' ? 'password' : 'text'}
            required
            value={passphrase}
            onChange={(e) => setPassphrase(e.target.value)}
            placeholder={mode === 'recovery' ? 'XXXXXX-XXXXXX-XXXXXX-XXXXXX' : ''}
            spellCheck={false}
            autoComplete={mode === 'recovery' ? 'off' : 'current-password'}
            className={
              'w-full rounded-lg border border-white/10 bg-ink-800 px-3 py-2.5 text-sm text-white placeholder-neutral-500 transition focus:border-brand-400 focus:outline-none focus:ring-2 focus:ring-brand-500/40 ' +
              (mode === 'recovery' ? 'font-mono tracking-widest' : '')
            }
          />
          {mode === 'recovery' && (
            <p className="text-[11px] text-neutral-500">
              Stattdessen den Recovery-Backup-String oben einfügen.
            </p>
          )}
        </div>
      </div>

      <div className="mt-5 rounded-lg border border-brand-500/20 bg-brand-500/10 p-3 text-xs text-brand-100">
        <div className="flex items-start gap-2">
          <LockIcon className="mt-0.5 h-4 w-4 shrink-0 text-brand-300" />
          <span className="min-w-0 flex-1 break-words">
            {t('app:backup.restore_hint', {
              defaultValue:
                'Nach Wiederherstellung übernimmt dieses Gerät die alte Identität — existierende Nachrichten sind wieder entschlüsselbar.',
            })}
          </span>
        </div>
      </div>

      <button
        type="submit"
        disabled={busy || backup.trim().length === 0 || passphrase.length === 0}
        aria-busy={busy}
        className="group mt-6 inline-flex w-full cursor-pointer items-center justify-center gap-2 rounded-lg bg-gradient-to-br from-emerald-400 to-emerald-600 px-4 py-3 text-sm font-semibold text-white shadow-glow transition hover:from-emerald-300 hover:to-emerald-500 focus:outline-none focus:ring-2 focus:ring-emerald-400/60 focus:ring-offset-2 focus:ring-offset-ink-900 disabled:cursor-not-allowed disabled:opacity-60"
      >
        {busy ? (
          <>
            <SpinnerIcon className="h-4 w-4" />
            <span>{t('app:backup.restoring', { defaultValue: 'Wiederherstellen…' })}</span>
          </>
        ) : (
          <>
            <span>{t('app:backup.restore_cta', { defaultValue: 'Gerät wiederherstellen' })}</span>
            <ArrowRightIcon className="h-4 w-4 transition group-hover:translate-x-0.5" />
          </>
        )}
      </button>

      {error && (
        <div
          role="alert"
          className="mt-4 flex items-start gap-3 rounded-lg border border-rose-500/20 bg-rose-500/10 p-3 text-sm text-rose-100"
        >
          <AlertIcon className="mt-0.5 h-5 w-5 shrink-0 text-rose-400" />
          <p className="min-w-0 flex-1 break-words">{error}</p>
        </div>
      )}
    </form>
  );
}
