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

import {
  approveDevice,
  denyAllPending,
  denyDevice,
  type PendingApproval,
  subscribePendingApprovals,
} from '../lib/deviceApproval';
import { LockIcon, SpinnerIcon, XIcon } from './icons';

// Sticky bottom-right banner stack (Discord-style). One tile per pending
// device-approval request. Visual language deliberately mirrors
// `BackupPromptBanner` — fixed positioning, rounded panel, subtle border
// accent — but uses the brand/accent palette to distinguish "security
// decision" from the amber "you should make a backup" nudge.
//
// Data flow:
//   1. `startDeviceApprovalListener` (mounted from AppShell) seeds the
//      pending list on connect + on realtime INSERTs.
//   2. This component subscribes to that module and re-renders.
//   3. On Genehmigen: calls `approveDevice` which re-uses the
//      `wrapForOneDevice` helper from conversationKeySync to write conv-key
//      bundles for the new device across every shared conversation.
//   4. On Ablehnen: persists the deviceId in localStorage so it doesn't
//      re-surface on app reload.
export function DeviceApprovalBanner() {
  const { t, i18n } = useTranslation(['app']);
  const [pending, setPending] = useState<PendingApproval[]>([]);
  const [busyId, setBusyId] = useState<string | null>(null);
  const [errorId, setErrorId] = useState<string | null>(null);

  useEffect(() => subscribePendingApprovals(setPending), []);

  const onApprove = useCallback(async (req: PendingApproval) => {
    setErrorId(null);
    setBusyId(req.deviceId);
    try {
      await approveDevice(req);
    } catch (err) {
      console.warn('deviceApproval: approve failed', err);
      setErrorId(req.deviceId);
    } finally {
      setBusyId((curr) => (curr === req.deviceId ? null : curr));
    }
  }, []);

  const onDeny = useCallback((deviceId: string) => {
    denyDevice(deviceId);
  }, []);

  if (pending.length === 0) return null;

  return (
    <div className="pointer-events-none fixed bottom-6 right-6 z-40 flex w-[min(92vw,420px)] flex-col gap-3">
      {pending.length > 1 && (
        <div className="pointer-events-auto flex items-center justify-between gap-3 rounded-xl border border-line bg-surface-3/80 px-4 py-2 text-xs text-fg-muted backdrop-blur-md">
          <span>
            {t('app:device_approval.bulk_count', {
              count: pending.length,
              defaultValue: '{{count}} Geräte warten auf Bestätigung',
            })}
          </span>
          <button
            type="button"
            onClick={() => denyAllPending()}
            disabled={busyId !== null}
            className="cursor-pointer rounded-md border border-line bg-transparent px-3 py-1 text-xs font-medium text-fg-muted transition hover:bg-surface-2 hover:text-fg disabled:opacity-50 focus:outline-none focus-visible:ring-2 focus-visible:ring-accent/40"
          >
            {t('app:device_approval.deny_all', { defaultValue: 'Alle ablehnen' })}
          </button>
        </div>
      )}
      {pending.map((req) => {
        const busy = busyId === req.deviceId;
        const errored = errorId === req.deviceId;
        return (
          <div
            key={req.deviceId}
            role="alertdialog"
            aria-labelledby={`device-approval-${req.deviceId}-title`}
            className="pointer-events-auto flex items-start gap-3 rounded-2xl border border-line bg-surface-3 p-4 text-sm text-fg shadow-xl backdrop-blur-md"
          >
            <LockIcon className="mt-0.5 h-5 w-5 shrink-0 text-accent" />
            <div className="min-w-0 flex-1">
              <p
                id={`device-approval-${req.deviceId}-title`}
                className="font-semibold"
              >
                {t('app:device_approval.title', {
                  defaultValue: 'Neues Gerät registriert',
                })}
              </p>
              <p className="mt-0.5 text-xs text-fg-muted">
                {formatDeviceLabel(req)} ·{' '}
                {formatRelativeTime(req.createdAt, i18n.language)}
              </p>
              <p className="mt-1 text-xs text-fg-muted">
                {t('app:device_approval.question', {
                  defaultValue: 'War das du?',
                })}
              </p>
              {errored && (
                <p className="mt-1 text-xs text-red-500">
                  {t('app:device_approval.error', {
                    defaultValue:
                      'Genehmigung fehlgeschlagen. Versuch es nochmal.',
                  })}
                </p>
              )}
              <div className="mt-3 flex flex-wrap items-center gap-2">
                <button
                  type="button"
                  disabled={busy}
                  onClick={() => void onApprove(req)}
                  className="inline-flex cursor-pointer items-center gap-1.5 rounded-md bg-accent px-3 py-1.5 text-xs font-semibold text-accent-fg transition hover:opacity-90 disabled:cursor-wait disabled:opacity-60"
                >
                  {busy && <SpinnerIcon className="h-3.5 w-3.5 animate-spin" />}
                  {t('app:device_approval.approve', {
                    defaultValue: 'Genehmigen',
                  })}
                </button>
                <button
                  type="button"
                  disabled={busy}
                  onClick={() => onDeny(req.deviceId)}
                  className="cursor-pointer rounded-md border border-line bg-transparent px-3 py-1.5 text-xs font-semibold text-fg-muted transition hover:bg-surface-2 disabled:cursor-not-allowed disabled:opacity-60"
                >
                  {t('app:device_approval.deny', {
                    defaultValue: 'Ablehnen',
                  })}
                </button>
              </div>
            </div>
            <button
              type="button"
              disabled={busy}
              onClick={() => onDeny(req.deviceId)}
              aria-label={t('app:device_approval.dismiss', {
                defaultValue: 'Schließen',
              })}
              className="cursor-pointer text-fg-muted transition hover:text-fg disabled:cursor-not-allowed disabled:opacity-60"
            >
              <XIcon className="h-4 w-4" />
            </button>
          </div>
        );
      })}
    </div>
  );
}

function formatDeviceLabel(req: PendingApproval): string {
  const platform = humanPlatform(req.platform);
  const name = (req.name ?? '').trim();
  if (name && platform) return `${platform} · ${name}`;
  if (name) return name;
  if (platform) return platform;
  return 'Unbekanntes Gerät';
}

function humanPlatform(p: string): string {
  switch (p) {
    case 'windows':
      return 'Windows';
    case 'macos':
      return 'macOS';
    case 'linux':
      return 'Linux';
    case 'ios':
      return 'iOS';
    case 'android':
      return 'Android';
    default:
      return p.length > 0 ? p.charAt(0).toUpperCase() + p.slice(1) : '';
  }
}

// Best-effort relative-time formatter using Intl.RelativeTimeFormat.
// Falls back to absolute timestamp if anything goes sideways.
function formatRelativeTime(iso: string, locale: string): string {
  try {
    const ts = Date.parse(iso);
    if (Number.isNaN(ts)) return iso;
    const diffSec = Math.round((ts - Date.now()) / 1000);
    const abs = Math.abs(diffSec);
    const rtf = new Intl.RelativeTimeFormat(locale || 'de', { numeric: 'auto' });
    if (abs < 60) return rtf.format(diffSec, 'second');
    if (abs < 3600) return rtf.format(Math.round(diffSec / 60), 'minute');
    if (abs < 86400) return rtf.format(Math.round(diffSec / 3600), 'hour');
    return rtf.format(Math.round(diffSec / 86400), 'day');
  } catch {
    return iso;
  }
}
