/**
 * InstallPrompt — PWA install guidance for iOS and Android (PWA-01, PWA-02).
 *
 * Behaviors:
 *   - Renders nothing when the app is already installed (display-mode: standalone
 *     or navigator.standalone — iOS PWA).
 *   - iOS Safari non-standalone: shows a dismissible banner with a "How to install"
 *     link that opens a full-screen 5-step walkthrough sheet.
 *   - Android (Chrome/Edge): shows a banner with an "Install" button only when the
 *     `beforeinstallprompt` event has fired and canInstall is true.
 *   - Neither surface shows when the app is already installed.
 *
 * localStorage key: `installPromptDismissed` — persists banner dismissal.
 *
 * Security: T-02d-01 — all text is plain-text JSX children; no dangerouslySetInnerHTML.
 * Accessibility: role="banner", dismiss aria-label="Dismiss install prompt", 44px touch targets.
 *
 * CLAUDE.md PWA constraints:
 *   - iOS 16.4+ minimum; Home-Screen install required for push.
 *   - pushManager.subscribe() must be in a tap handler (enforced in Phase 5).
 *   - EU DMA iOS 17.4+ caveat: PWA may open in Safari tabs; install guide addresses this.
 */

import { useState, useEffect } from 'react';
import { Smartphone, X } from 'lucide-react';
import { PushPermissionPrompt } from './PushPermissionPrompt.js';

// ── iOS detection ──────────────────────────────────────────────────────────

/**
 * Returns true when the browser is iOS Safari in non-standalone (browser-tab) mode.
 * Returns false when already installed (navigator.standalone === true) or on non-iOS.
 *
 * Detection logic:
 *   1. Check for iPad/iPhone/iPod in UA (standard iOS Safari UA; excludes Android Chrome
 *      which also contains "Safari").
 *   2. Exclude IE/Edge for IE (MSStream property) — belt-and-suspenders.
 *   3. Check navigator.standalone is NOT true (standalone = already installed).
 */
export function isIOSSafariNonStandalone(): boolean {
  const ua = navigator.userAgent;
  const isIOS =
    /iPad|iPhone|iPod/.test(ua) && !(window as unknown as { MSStream?: unknown }).MSStream;
  const isStandalone = (navigator as unknown as { standalone?: boolean }).standalone === true;
  return isIOS && !isStandalone;
}

// ── Installed state check ──────────────────────────────────────────────────

/**
 * Returns true when the app is running in standalone mode (already installed).
 * Covers both Android (display-mode media query) and iOS (navigator.standalone).
 */
function isInstalled(): boolean {
  return (
    window.matchMedia('(display-mode: standalone)').matches ||
    (navigator as unknown as { standalone?: boolean }).standalone === true
  );
}

// ── Android beforeinstallprompt hook ─────────────────────────────────────

interface BeforeInstallPromptEvent extends Event {
  prompt(): Promise<void>;
  userChoice: Promise<{ outcome: 'accepted' | 'dismissed' }>;
}

/**
 * Captures the browser's `beforeinstallprompt` event and exposes it as a hook.
 * Only fires on Chrome/Edge on Android — never on iOS.
 *
 * Returns:
 *   canInstall: true when the event has been captured and install is available
 *   triggerInstall: function that calls prompt() on the deferred event
 */
export function useAndroidInstallPrompt() {
  const [deferredPrompt, setDeferredPrompt] = useState<BeforeInstallPromptEvent | null>(null);
  // justInstalled: set to true when the appinstalled event fires, enabling the
  // post-install push permission prompt trigger (D-08).
  const [justInstalled, setJustInstalled] = useState(false);

  useEffect(() => {
    const handler = (e: Event) => {
      e.preventDefault();
      setDeferredPrompt(e as BeforeInstallPromptEvent);
    };
    const installedHandler = () => {
      setDeferredPrompt(null);
      setJustInstalled(true);
    };

    window.addEventListener('beforeinstallprompt', handler);
    window.addEventListener('appinstalled', installedHandler);

    return () => {
      window.removeEventListener('beforeinstallprompt', handler);
      window.removeEventListener('appinstalled', installedHandler);
    };
  }, []);

  const triggerInstall = async () => {
    if (!deferredPrompt) return;
    await deferredPrompt.prompt();
    const { outcome } = await deferredPrompt.userChoice;
    if (outcome === 'accepted') {
      setDeferredPrompt(null);
    }
  };

  return { canInstall: deferredPrompt !== null, triggerInstall, justInstalled };
}

// ── iOS Walkthrough Sheet ─────────────────────────────────────────────────

const IOS_STEPS = [
  'Open FamilySync in Safari',
  'Tap the Share button',
  "Scroll down and tap 'Add to Home Screen'",
  "Tap 'Add' in the top right",
  'Open FamilySync from your Home Screen — it opens without the browser bar',
];

interface WalkthroughSheetProps {
  onClose: () => void;
}

function WalkthroughSheet({ onClose }: WalkthroughSheetProps) {
  return (
    <div
      role="dialog"
      aria-modal="true"
      aria-label="Add to Home Screen walkthrough"
      style={{
        position: 'fixed',
        inset: 0,
        background: 'var(--color-overlay, rgba(0,0,0,0.5))',
        display: 'flex',
        flexDirection: 'column',
        justifyContent: 'flex-end',
        zIndex: 1000,
      }}
      onClick={(e) => {
        // Close on backdrop click
        if (e.target === e.currentTarget) onClose();
      }}
    >
      <div
        style={{
          background: 'var(--color-surface, #ffffff)',
          borderRadius: '12px 12px 0 0',
          padding: 'var(--space-6, 24px)',
          maxHeight: '90dvh',
          overflowY: 'auto',
          display: 'flex',
          flexDirection: 'column',
          gap: 'var(--space-4, 16px)',
        }}
      >
        {/* Header */}
        <div
          style={{
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'space-between',
          }}
        >
          <h2
            style={{
              margin: 0,
              fontSize: 'var(--text-heading-size, 18px)',
              fontWeight: 'var(--text-heading-weight, 600)',
              lineHeight: 'var(--text-heading-line-height, 1.25)',
              color: 'var(--color-text-primary, #111318)',
              fontFamily: 'var(--font-family-base, system-ui, sans-serif)',
            }}
          >
            Add to Home Screen
          </h2>
          <button
            onClick={onClose}
            aria-label="Close walkthrough"
            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>

        {/* Steps */}
        <ol
          style={{
            margin: 0,
            padding: 0,
            listStyle: 'none',
            display: 'flex',
            flexDirection: 'column',
            gap: 'var(--space-4, 16px)',
          }}
        >
          {IOS_STEPS.map((step, i) => (
            <li
              key={i}
              style={{
                display: 'flex',
                alignItems: 'flex-start',
                gap: 'var(--space-3, 12px)',
              }}
            >
              {/* Step number with accent color annotation (#F5A623 — --color-member-2) */}
              <span
                style={{
                  flexShrink: 0,
                  width: '28px',
                  height: '28px',
                  borderRadius: '50%',
                  background: '#F5A623',
                  color: '#ffffff',
                  display: 'flex',
                  alignItems: 'center',
                  justifyContent: 'center',
                  fontSize: '13px',
                  fontWeight: 600,
                  fontFamily: 'var(--font-family-base, system-ui, sans-serif)',
                }}
              >
                {i + 1}
              </span>
              <span
                style={{
                  fontSize: 'var(--text-body-size, 15px)',
                  lineHeight: 'var(--text-body-line-height, 1.5)',
                  color: 'var(--color-text-primary, #111318)',
                  fontFamily: 'var(--font-family-base, system-ui, sans-serif)',
                  paddingTop: '4px',
                }}
              >
                {step}
              </span>
            </li>
          ))}
        </ol>

        {/* Done button */}
        <button
          onClick={onClose}
          style={{
            background: 'var(--color-text-primary, #111318)',
            color: '#ffffff',
            border: 'none',
            borderRadius: 'var(--space-1, 4px)',
            minHeight: '44px',
            padding: '0 var(--space-4, 16px)',
            fontSize: 'var(--text-label-size, 13px)',
            fontWeight: 600,
            cursor: 'pointer',
            fontFamily: 'var(--font-family-base, system-ui, sans-serif)',
            alignSelf: 'stretch',
          }}
        >
          Done
        </button>
      </div>
    </div>
  );
}

// ── InstallPrompt ─────────────────────────────────────────────────────────

/**
 * InstallPrompt renders the appropriate install surface based on platform:
 *   - iOS Safari non-standalone: dismissible banner + optional walkthrough sheet
 *   - Android (beforeinstallprompt available): install banner with native prompt button
 *   - Already installed / desktop: nothing
 *
 * Mount this at the top level of CalendarShell, below the nav bar.
 */
// IN-03: localStorage access is guarded — in private-mode / SSR contexts the API can
// throw on read or write. Mirrors calendarStore.ts's pattern so a storage failure
// degrades gracefully (treated as "not dismissed") instead of crashing the component.
function readDismissed(): boolean {
  try {
    return localStorage.getItem('installPromptDismissed') === '1';
  } catch {
    return false;
  }
}

function persistDismissed(): void {
  try {
    localStorage.setItem('installPromptDismissed', '1');
  } catch {
    // Ignore write failures (private mode / storage disabled)
  }
}

export function InstallPrompt() {
  const [dismissed, setDismissed] = useState<boolean>(readDismissed);
  const [walkthroughOpen, setWalkthroughOpen] = useState(false);
  const { canInstall, triggerInstall, justInstalled } = useAndroidInstallPrompt();

  // Re-check isInstalled on mount — matchMedia is only available in the browser
  const [installed, setInstalled] = useState(false);
  useEffect(() => {
    setInstalled(isInstalled());
  }, []);

  // Show post-install permission prompt (D-08) immediately after the appinstalled event
  // fires — before the page knows it is in standalone mode. This covers Android Chrome
  // where the page stays loaded after install without a reload.
  if (justInstalled) {
    return <PushPermissionPrompt />;
  }

  // Nothing to show when already installed (App.tsx mounts PushPermissionPrompt there)
  if (installed) return null;

  function dismiss() {
    persistDismissed();
    setDismissed(true);
  }

  // ── iOS banner ──────────────────────────────────────────────────────────

  if (isIOSSafariNonStandalone() && !dismissed) {
    return (
      <>
        <div
          role="banner"
          style={{
            display: 'flex',
            alignItems: 'center',
            gap: 'var(--space-3, 12px)',
            padding: 'var(--space-3, 12px) var(--space-4, 16px)',
            background: 'var(--color-surface-raised, #ffffff)',
            borderBottom: '1px solid var(--color-border, #e2e4e9)',
            fontFamily: 'var(--font-family-base, system-ui, sans-serif)',
          }}
        >
          {/* Icon */}
          <Smartphone
            size={24}
            aria-hidden="true"
            style={{ color: 'var(--color-text-secondary, #5c6472)', flexShrink: 0 }}
          />

          {/* Text content */}
          <div style={{ flex: 1, minWidth: 0 }}>
            <div
              style={{
                fontSize: '13px',
                fontWeight: 600,
                color: 'var(--color-text-primary, #111318)',
                lineHeight: 1.4,
              }}
            >
              Install FamilySync
            </div>
            <div
              style={{
                fontSize: '13px',
                color: 'var(--color-text-secondary, #5c6472)',
                lineHeight: 1.4,
              }}
            >
              Add to your Home Screen for the best experience.{' '}
              <button
                onClick={() => setWalkthroughOpen(true)}
                style={{
                  background: 'none',
                  border: 'none',
                  padding: 0,
                  cursor: 'pointer',
                  fontSize: '13px',
                  color: 'var(--color-focus-ring, #4A90D9)',
                  textDecoration: 'underline',
                  fontFamily: 'inherit',
                }}
              >
                How to install
              </button>
            </div>
          </div>

          {/* Dismiss */}
          <button
            onClick={dismiss}
            aria-label="Dismiss install prompt"
            style={{
              background: 'none',
              border: 'none',
              cursor: 'pointer',
              minWidth: '44px',
              minHeight: '44px',
              display: 'flex',
              alignItems: 'center',
              justifyContent: 'center',
              color: 'var(--color-text-secondary, #5c6472)',
              flexShrink: 0,
              borderRadius: 'var(--space-1, 4px)',
            }}
          >
            <X size={16} aria-hidden="true" />
          </button>
        </div>

        {walkthroughOpen && <WalkthroughSheet onClose={() => setWalkthroughOpen(false)} />}
      </>
    );
  }

  // ── Android banner ──────────────────────────────────────────────────────

  if (canInstall && !dismissed) {
    return (
      <div
        role="banner"
        style={{
          display: 'flex',
          alignItems: 'center',
          gap: 'var(--space-3, 12px)',
          padding: 'var(--space-3, 12px) var(--space-4, 16px)',
          background: 'var(--color-surface-raised, #ffffff)',
          borderBottom: '1px solid var(--color-border, #e2e4e9)',
          fontFamily: 'var(--font-family-base, system-ui, sans-serif)',
        }}
      >
        {/* Icon */}
        <Smartphone
          size={24}
          aria-hidden="true"
          style={{ color: 'var(--color-text-secondary, #5c6472)', flexShrink: 0 }}
        />

        {/* Text content */}
        <div style={{ flex: 1, minWidth: 0 }}>
          <div
            style={{
              fontSize: '13px',
              color: 'var(--color-text-secondary, #5c6472)',
              lineHeight: 1.4,
            }}
          >
            Install FamilySync to your Home Screen for the best experience.
          </div>
        </div>

        {/* Install CTA */}
        <button
          onClick={() => {
            void triggerInstall().then(() => dismiss());
          }}
          style={{
            background: 'var(--color-text-primary, #111318)',
            color: '#ffffff',
            border: 'none',
            borderRadius: 'var(--space-1, 4px)',
            minHeight: '44px',
            padding: '0 var(--space-4, 16px)',
            fontSize: '13px',
            fontWeight: 600,
            cursor: 'pointer',
            fontFamily: 'inherit',
            flexShrink: 0,
            whiteSpace: 'nowrap',
          }}
        >
          Install
        </button>

        {/* Dismiss */}
        <button
          onClick={dismiss}
          aria-label="Dismiss install prompt"
          style={{
            background: 'none',
            border: 'none',
            cursor: 'pointer',
            minWidth: '44px',
            minHeight: '44px',
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'center',
            color: 'var(--color-text-secondary, #5c6472)',
            flexShrink: 0,
            borderRadius: 'var(--space-1, 4px)',
          }}
        >
          <X size={16} aria-hidden="true" />
        </button>
      </div>
    );
  }

  // Nothing applicable — desktop, already installed, or dismissed
  return null;
}
