/**
 * src/lib/pwa/pwa_install.svelte.ts
 *
 * Global PWA install prompt state using Svelte 5 universal reactivity.
 *
 * Usage:
 *   - Call `pwa_install.init()` once in the root +layout.svelte (browser $effect).
 *     init() handles dismiss state and standalone detection (needs localStorage/DOM).
 *   - Import `pwa_install` in any component to read state and trigger the prompt.
 *
 * Platform behaviour:
 *   - Chrome / Chromium / Android: intercepts `beforeinstallprompt` at module load time
 *     (critical — the event fires very early, before $effects run). Shows a custom button.
 *   - Firefox desktop: does NOT support `beforeinstallprompt`. Firefox provides its own
 *     install button in the address bar when a valid manifest + service worker are present.
 *   - iOS Safari: `beforeinstallprompt` never fires; we detect iOS + not-standalone
 *     and show manual "Share → Add to Home Screen" instructions instead.
 *   - If already running in standalone mode (i.e. already installed) → hide everything.
 *
 * Dismiss: persists for DISMISS_DAYS days via localStorage key `ae_pwa_install_dismissed`.
 */
import { browser } from '$app/environment';

// `BeforeInstallPromptEvent` is non-standard and not included in TypeScript's default lib.
interface BeforeInstallPromptEvent extends Event {
    prompt(): Promise<void>;
    userChoice: Promise<{
        outcome: 'accepted' | 'dismissed';
        platform: string;
    }>;
}

const DISMISS_KEY = 'ae_pwa_install_dismissed';
const DISMISS_DAYS = 7;

// --- Module-level reactive state (Svelte 5 universal reactivity) ---
let _deferred_prompt = $state<BeforeInstallPromptEvent | null>(null);
let _is_installed = $state(false);
let _is_dismissed = $state(false);
let _initialized = false; // plain boolean — not reactive, guards against double-init

// --- Early event capture (module load time) ---
// `beforeinstallprompt` fires within ~1 second of page load — before any $effect runs.
// Register here so we never miss it regardless of when init() is called.
if (browser) {
    window.addEventListener('beforeinstallprompt', (e) => {
        e.preventDefault();
        _deferred_prompt = e as BeforeInstallPromptEvent;
    });

    window.addEventListener('appinstalled', () => {
        _is_installed = true;
        _deferred_prompt = null;
    });
}

// --- Private helpers (SSR-safe) ---

function _in_standalone(): boolean {
    if (!browser) return false;
    return (
        window.matchMedia('(display-mode: standalone)').matches ||
        // iOS Safari sets navigator.standalone (non-standard)
        ('standalone' in window.navigator &&
            (window.navigator as any).standalone === true)
    );
}

function _is_ios(): boolean {
    if (!browser) return false;
    // Cover iPhone/iPod/iPad (incl. iPadOS 13+ which reports MacIntel with touch points)
    return (
        /iphone|ipad|ipod/i.test(navigator.userAgent) ||
        (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1)
    );
}

// --- Public API ---

export const pwa_install = {
    /**
     * True if the browser has captured a deferred install prompt
     * (Chrome / Android / PWA-capable desktop browsers).
     */
    get can_prompt(): boolean {
        return _deferred_prompt !== null && !_is_installed && !_is_dismissed;
    },

    /**
     * True if on iOS Safari and NOT already installed.
     * We cannot trigger a native prompt on iOS so we show manual instructions instead.
     */
    get is_ios_nudge(): boolean {
        return (
            _is_ios() && !_in_standalone() && !_is_dismissed && !_is_installed
        );
    },

    /** True if the install UI should be rendered at all. */
    get should_show(): boolean {
        return pwa_install.can_prompt || pwa_install.is_ios_nudge;
    },

    /** True once the app is confirmed installed (standalone mode or appinstalled event). */
    get is_installed(): boolean {
        return _is_installed;
    },

    /**
     * Finish initialisation after the layout mounts. Call ONCE from root +layout.svelte.
     * Handles dismiss state (needs localStorage) and standalone detection (needs DOM).
     * Event listeners for beforeinstallprompt/appinstalled are already registered at
     * module load time — this does NOT register them again.
     * Safe to call multiple times (idempotent).
     */
    init(): void {
        if (!browser || _initialized) return;
        _initialized = true;

        // Already running as installed PWA — nothing to prompt.
        if (_in_standalone()) {
            _is_installed = true;
            return;
        }

        // Restore dismiss state from localStorage (with expiry check).
        const raw = localStorage.getItem(DISMISS_KEY);
        if (raw) {
            const days_since = (Date.now() - parseInt(raw, 10)) / 86_400_000;
            if (days_since < DISMISS_DAYS) {
                _is_dismissed = true;
            } else {
                // Expired — clear so the nudge can reappear.
                localStorage.removeItem(DISMISS_KEY);
            }
        }
    },

    /** Trigger the native install prompt. No-op if no deferred prompt is available. */
    async prompt(): Promise<void> {
        if (!_deferred_prompt) return;
        // Grab and clear to prevent double-fire.
        const evt = _deferred_prompt;
        _deferred_prompt = null;
        await evt.prompt();
        const { outcome } = await evt.userChoice;
        if (outcome === 'accepted') {
            _is_installed = true;
        }
    },

    /** Dismiss the nudge; it will not re-appear for DISMISS_DAYS days. */
    dismiss(): void {
        _is_dismissed = true;
        if (browser) localStorage.setItem(DISMISS_KEY, Date.now().toString());
    }
};
