/**
 * SettingsSheet — master notifications toggle (D-09).
 *
 * A bottom sheet opened by tapping the user avatar in AppNav.
 * Contains a single master on/off toggle for all FamilySync push notifications.
 *
 * UI-SPEC §Surface 2:
 *   - Bottom sheet, role="dialog", aria-modal, zIndex 301 (backdrop 300)
 *   - Heading "Settings" + X close button
 *   - Section label "Notifications" (uppercase, muted)
 *   - Bell icon + toggle row
 *   - Permission-denied hint when Notification.permission === 'denied'
 *
 * Toggle behavior:
 *   on → off: DELETE subscription + localStorage.notificationsEnabled='0'
 *   off → on (permission granted): silently subscribe (no OS dialog)
 *   off → on (permission default): triggers tap-gated subscribe() (OS dialog)
 *   off → on (permission denied): no-op, shows permission-denied hint inline
 *
 * Accessibility: role="switch", aria-checked, 44px touch targets, Escape closes.
 * Security: T-05-24 — all copy is plain-text JSX children, no dangerouslySetInnerHTML.
 */

import { useEffect, useRef, useState } from 'react';
import { X, Bell, AlertCircle, Loader2 } from 'lucide-react';
import { usePushSubscription } from '../hooks/usePushSubscription.js';
import { InstructionSheet } from './InstructionSheet.js';

// CR-04: fetch VAPID key (from sessionStorage cache if available) for the
// tap-gated subscribe() path.  Same logic as PushPermissionPrompt.
async function fetchVapidKeyForSettings(): Promise<string | null> {
  try {
    const cached = sessionStorage.getItem('vapidPublicKey');
    if (cached) return cached;
    const res = await fetch('/api/push/vapid-public-key', { credentials: 'include' });
    if (!res.ok) return null;
    const data = (await res.json()) as { publicKey: string };
    if (data.publicKey) {
      sessionStorage.setItem('vapidPublicKey', data.publicKey);
    }
    return data.publicKey ?? null;
  } catch {
    return null;
  }
}

interface SettingsSheetProps {
  isOpen: boolean;
  onClose: () => void;
}

export function SettingsSheet({ isOpen, onClose }: SettingsSheetProps) {
  const { subscribe, permission, isSubscribed, setEnabled } = usePushSubscription();
  const [isTogglingOn, setIsTogglingOn] = useState(false);
  const [instructionsOpen, setInstructionsOpen] = useState(false);
  // CR-04: pre-fetch the VAPID key into state so the toggle tap handler can call
  // subscribe(registration, vapidKey) without any network await before pushManager.subscribe().
  const [vapidKey, setVapidKey] = useState<string | null>(null);
  // NEW-CR-01: Pre-resolve the ServiceWorkerRegistration into state so the toggle
  // tap handler has ZERO awaits between the user gesture and pushManager.subscribe().
  const [swRegistration, setSwRegistration] = useState<ServiceWorkerRegistration | null>(null);
  const closeButtonRef = useRef<HTMLButtonElement>(null);

  // Compute initial toggle on/off state per UI-SPEC toggle initial state rule:
  // on when notificationsEnabled !== '0' AND permission === 'granted' AND isSubscribed
  const isOn = permission === 'granted' && isSubscribed;

  // Escape key listener (CreateListSheet pattern)
  useEffect(() => {
    if (!isOpen) return;
    const onKeyDown = (e: KeyboardEvent) => {
      if (e.key === 'Escape') onClose();
    };
    document.addEventListener('keydown', onKeyDown);
    return () => document.removeEventListener('keydown', onKeyDown);
  }, [isOpen, onClose]);

  // Focus close button on open (a11y)
  useEffect(() => {
    if (isOpen && closeButtonRef.current) {
      closeButtonRef.current.focus();
    }
  }, [isOpen]);

  // CR-04: Pre-fetch the VAPID key while the sheet is open so the OS-dialog path
  // (permission === 'default') has the key ready before the user taps.
  useEffect(() => {
    if (!isOpen) return;
    if (permission === 'denied') return;
    void fetchVapidKeyForSettings().then((key) => {
      if (key) setVapidKey(key);
    });
  }, [isOpen, permission]);

  // NEW-CR-01: Pre-resolve the ServiceWorkerRegistration into state so the toggle
  // tap handler never needs to await navigator.serviceWorker.ready. Any await
  // between the tap gesture and pushManager.subscribe() breaks iOS.
  useEffect(() => {
    if (!isOpen) return;
    if (permission === 'denied') return;
    if (!navigator.serviceWorker) return;
    void navigator.serviceWorker.ready.then((reg) => {
      setSwRegistration(reg);
    });
  }, [isOpen, permission]);

  if (!isOpen) return null;

  const handleToggle = async () => {
    if (permission === 'denied') return; // no-op — show hint below

    if (isOn) {
      // on → off: unsubscribe
      await setEnabled(false);
    } else if (permission === 'granted') {
      // off → on, permission already granted: silent subscribe
      setIsTogglingOn(true);
      try {
        await setEnabled(true);
      } finally {
        setIsTogglingOn(false);
      }
    } else {
      // off → on, permission 'default': needs tap-gated subscribe with OS dialog
      // The toggle click IS the tap gesture — call subscribe() directly here.
      // NEW-CR-01: Both vapidKey AND swRegistration are pre-resolved into state
      // (useEffects above). There is ZERO await between the tap and
      // registration.pushManager.subscribe() — iOS gesture gate satisfied.
      if (!vapidKey || !swRegistration) return; // not ready — useEffects still resolving
      const resolvedVapidKey = vapidKey;
      const resolvedRegistration = swRegistration;
      setIsTogglingOn(true);
      try {
        await subscribe(resolvedRegistration, resolvedVapidKey);
      } catch {
        // Permission denied by OS or error — permission state will update reactively
      } finally {
        setIsTogglingOn(false);
      }
    }
  };

  const isDisabled = permission === 'denied';

  return (
    <>
      {/* Backdrop */}
      <div
        onClick={onClose}
        aria-hidden="true"
        style={{
          position: 'fixed',
          inset: 0,
          background: 'var(--color-overlay, rgba(0,0,0,0.32))',
          zIndex: 300,
        }}
      />

      {/* Sheet */}
      <div
        role="dialog"
        aria-modal="true"
        aria-label="Settings"
        style={{
          position: 'fixed',
          bottom: 0,
          left: 0,
          right: 0,
          background: 'var(--color-surface-raised, #ffffff)',
          borderRadius: '12px 12px 0 0',
          boxShadow: '0 -4px 24px rgba(0,0,0,0.15)',
          padding: 'var(--space-6, 24px)',
          zIndex: 301,
          fontFamily: 'var(--font-family-base, system-ui, sans-serif)',
          maxWidth: '480px',
          margin: '0 auto',
        }}
      >
        {/* Heading row */}
        <div
          style={{
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'space-between',
            marginBottom: 'var(--space-6, 24px)',
          }}
        >
          <h2
            style={{
              margin: 0,
              fontSize: 'var(--text-heading-size, 18px)',
              fontWeight: 600,
              lineHeight: 'var(--text-heading-line-height, 1.25)',
              color: 'var(--color-text-primary, #111318)',
            }}
          >
            Settings
          </h2>
          <button
            ref={closeButtonRef}
            onClick={onClose}
            aria-label="Close settings"
            style={{
              background: 'none',
              border: 'none',
              cursor: 'pointer',
              minWidth: '44px',
              minHeight: '44px',
              display: 'flex',
              alignItems: 'center',
              justifyContent: 'center',
              color: 'var(--color-text-secondary, #5c6472)',
              borderRadius: 'var(--space-1, 4px)',
            }}
          >
            <X size={20} aria-hidden="true" />
          </button>
        </div>

        {/* Section label */}
        <div
          style={{
            fontSize: 'var(--text-label-size, 13px)',
            fontWeight: 600,
            color: 'var(--color-text-muted, #9CA3AF)',
            textTransform: 'uppercase',
            letterSpacing: '0.06em',
            marginBottom: 'var(--space-2, 8px)',
          }}
        >
          Notifications
        </div>

        {/* Toggle row */}
        <div
          style={{
            display: 'flex',
            alignItems: 'center',
            gap: 'var(--space-3, 12px)',
            padding: 'var(--space-2, 8px) 0',
          }}
        >
          <Bell
            size={20}
            aria-hidden="true"
            style={{
              color: 'var(--color-text-secondary, #5c6472)',
              flexShrink: 0,
            }}
          />

          {/* Label column */}
          <div style={{ flex: 1, minWidth: 0 }}>
            <div
              style={{
                fontSize: 'var(--text-body-size, 15px)',
                fontWeight: 400,
                color: 'var(--color-text-primary, #111318)',
                lineHeight: 1.4,
              }}
            >
              FamilySync Notifications
            </div>
            <div
              style={{
                fontSize: 'var(--text-label-size, 13px)',
                color: 'var(--color-text-secondary, #5c6472)',
                lineHeight: 1.4,
                marginTop: '2px',
              }}
            >
              Reminders, event changes, list updates
            </div>
          </div>

          {/* Toggle switch or spinner */}
          {isTogglingOn ? (
            <Loader2
              size={20}
              aria-hidden="true"
              style={{
                color: 'var(--color-text-secondary, #5c6472)',
                animation: 'spin 1s linear infinite',
                flexShrink: 0,
              }}
            />
          ) : (
            <button
              role="switch"
              aria-checked={isOn}
              aria-label={isOn ? 'FamilySync Notifications, on' : 'FamilySync Notifications, off'}
              onClick={() => {
                void handleToggle();
              }}
              disabled={isDisabled}
              style={{
                // 44px touch target
                minWidth: '44px',
                minHeight: '44px',
                display: 'flex',
                alignItems: 'center',
                justifyContent: 'center',
                background: 'none',
                border: 'none',
                cursor: isDisabled ? 'default' : 'pointer',
                padding: 0,
                flexShrink: 0,
                opacity: isDisabled ? 0.5 : 1,
              }}
            >
              {/* Toggle track */}
              <div
                style={{
                  width: '44px',
                  height: '24px',
                  borderRadius: '12px',
                  background: isOn
                    ? 'var(--color-member-0, #4A90D9)'
                    : 'var(--color-border, #E2E4E9)',
                  position: 'relative',
                  transition: 'background 0.15s ease',
                  pointerEvents: 'none',
                }}
              >
                {/* Toggle thumb */}
                <div
                  style={{
                    position: 'absolute',
                    top: '2px',
                    left: isOn ? '22px' : '2px',
                    width: '20px',
                    height: '20px',
                    borderRadius: '50%',
                    background: '#ffffff',
                    boxShadow: '0 1px 3px rgba(0,0,0,0.2)',
                    transition: 'left 0.15s ease',
                  }}
                />
              </div>
            </button>
          )}
        </div>

        {/* Permission-denied hint — only when OS permission === 'denied' */}
        {permission === 'denied' && (
          <div
            style={{
              display: 'flex',
              alignItems: 'flex-start',
              gap: 'var(--space-2, 8px)',
              marginTop: 'var(--space-2, 8px)',
              padding: 'var(--space-3, 12px)',
              background: 'var(--color-surface-dim, #F7F7F8)',
              borderRadius: 'var(--space-1, 4px)',
            }}
          >
            <AlertCircle
              size={16}
              aria-hidden="true"
              style={{
                color: 'var(--color-destructive, #DC2626)',
                flexShrink: 0,
                marginTop: '1px',
              }}
            />
            <div>
              <span
                style={{
                  fontSize: 'var(--text-label-size, 13px)',
                  color: 'var(--color-text-secondary, #5c6472)',
                  lineHeight: 1.4,
                }}
              >
                Notifications are blocked in your browser settings.{' '}
              </span>
              <button
                onClick={() => setInstructionsOpen(true)}
                style={{
                  background: 'none',
                  border: 'none',
                  padding: 0,
                  cursor: 'pointer',
                  fontSize: 'var(--text-label-size, 13px)',
                  color: 'var(--color-focus-ring, #4A90D9)',
                  textDecoration: 'underline',
                  fontFamily: 'inherit',
                }}
              >
                How to enable
              </button>
            </div>
          </div>
        )}
      </div>

      {instructionsOpen && <InstructionSheet onClose={() => setInstructionsOpen(false)} />}
    </>
  );
}
