// notifications.jsx — Local notifications + PWA bootstrap
// Foreground scheduling via setTimeout; falls back to direct Notification() if
// service worker isn't registered. Designed for ADHD-friendly reminders:
// - Medicatie at user-set time
// - Top-3 morning kick-off
// - Bills N days before due

const NOTIF_DEBUG_KEY = '__maud_notif_lastrun';

// ─── PWA install hint ───────────────────────────────────────────
function isStandalone() {
  return window.matchMedia?.('(display-mode: standalone)').matches
      || window.navigator.standalone === true;
}

function isIOS() {
  return /iPhone|iPad|iPod/i.test(navigator.userAgent || '');
}

// ─── Service worker registration ────────────────────────────────
async function registerServiceWorker() {
  if (!('serviceWorker' in navigator)) return null;
  try {
    const reg = await navigator.serviceWorker.register('./service-worker.js', { scope: './' });
    return reg;
  } catch (e) {
    console.warn('SW registration failed', e);
    return null;
  }
}

// ─── Permission ─────────────────────────────────────────────────
async function requestNotificationPermission() {
  if (!('Notification' in window)) {
    return { granted: false, reason: 'Notificaties worden niet ondersteund door deze browser' };
  }
  if (Notification.permission === 'granted') return { granted: true };
  if (Notification.permission === 'denied')  return { granted: false, reason: 'Permissie geweigerd — schakel handmatig aan in browserinstellingen' };
  try {
    const r = await Notification.requestPermission();
    return { granted: r === 'granted', reason: r === 'denied' ? 'Permissie geweigerd' : null };
  } catch (e) {
    return { granted: false, reason: e.message || 'Fout bij vragen permissie' };
  }
}

// ─── Show notification (SW-preferred, fallback to Notification API) ─
async function showNotification(title, body, tag) {
  if (!('Notification' in window) || Notification.permission !== 'granted') return false;
  try {
    const reg = await navigator.serviceWorker?.ready;
    if (reg) {
      reg.active?.postMessage({ type: 'show-notification', title, body, tag });
      return true;
    }
  } catch (e) {}
  try {
    new Notification(title, { body, tag, icon: './icon.svg' });
    return true;
  } catch (e) { return false; }
}

// ─── Compute today's pending notification times ────────────────
function buildTodaysSchedule(state, now = new Date()) {
  const out = [];
  const settings = state.notifications || {};
  const today = new Date(now);
  today.setHours(0, 0, 0, 0);

  const parseTime = (s) => {
    if (!s) return null;
    const m = s.match(/^(\d{1,2}):(\d{2})$/);
    if (!m) return null;
    const d = new Date(today);
    d.setHours(+m[1], +m[2], 0, 0);
    return d;
  };

  // Medicatie
  const medRem = state.reminders?.find(r => /medic/i.test(r.label));
  const medTime = parseTime(settings.medicationTime);
  if (medRem && !medRem.doneToday && medTime && medTime > now) {
    out.push({
      id: 'med-' + today.toISOString().slice(0, 10),
      at: medTime,
      title: '💊 Tijd voor je medicatie',
      body: `Vink 'm af in de app · streak ${medRem.streak} dagen`,
      tag: 'maud-medication',
    });
  }

  // Top 3 morning
  const top3Time = parseTime(settings.top3Time);
  const openTop3 = state.top3?.filter(t => !t.done) || [];
  if (openTop3.length > 0 && top3Time && top3Time > now) {
    out.push({
      id: 'top3-' + today.toISOString().slice(0, 10),
      at: top3Time,
      title: '✦ Goedemorgen, wat zijn je top 3?',
      body: openTop3.length === 3 ? 'Drie kleine dingen voor vandaag' : `${openTop3.length} nog op je lijstje`,
      tag: 'maud-top3',
    });
  }

  // Bills lead-time (fire at 09:00 N days before)
  const lead = settings.billsLeadDays ?? 2;
  const dayOfMonth = now.getDate();
  (state.bills || []).filter(b => !b.paid).forEach(b => {
    const diff = b.day - dayOfMonth;
    if (diff === lead) {
      const t = new Date(today); t.setHours(9, 0, 0, 0);
      if (t > now) {
        out.push({
          id: 'bill-' + b.id + '-' + today.toISOString().slice(0, 10),
          at: t,
          title: `🪙 ${b.name} over ${lead} dag${lead === 1 ? '' : 'en'}`,
          body: `${b.amount.toFixed(2).replace('.', ',')} € · vink af zodra betaald`,
          tag: 'maud-bill-' + b.id,
        });
      }
    }
  });

  return out;
}

// ─── Hook: keep notification schedule synced with state ────────
function useNotifications() {
  const [state, set] = useDashboard();
  const [permission, setPermission] = React.useState(() =>
    typeof Notification !== 'undefined' ? Notification.permission : 'unavailable'
  );
  const [swReady, setSwReady] = React.useState(false);
  const timeoutsRef = React.useRef([]);

  // Register SW on first mount
  React.useEffect(() => {
    let cancelled = false;
    registerServiceWorker().then((reg) => { if (!cancelled && reg) setSwReady(true); });
    return () => { cancelled = true; };
  }, []);

  // Schedule timeouts whenever state or permission changes
  React.useEffect(() => {
    // Clear any old timeouts
    timeoutsRef.current.forEach(t => clearTimeout(t));
    timeoutsRef.current = [];

    const enabled = state.notifications?.enabled && permission === 'granted';
    if (!enabled) return;

    const now = new Date();
    const schedule = buildTodaysSchedule(state, now);
    schedule.forEach(n => {
      const delay = Math.max(0, n.at.getTime() - now.getTime());
      // Don't schedule more than 24h ahead — re-check periodically instead
      if (delay > 24 * 3600 * 1000) return;
      const id = setTimeout(() => {
        showNotification(n.title, n.body, n.tag);
      }, delay);
      timeoutsRef.current.push(id);
    });

    // Re-check every hour in case something changes
    const recheck = setTimeout(() => set(s => ({ ...s })), 60 * 60 * 1000);
    timeoutsRef.current.push(recheck);

    return () => {
      timeoutsRef.current.forEach(t => clearTimeout(t));
      timeoutsRef.current = [];
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [
    state.notifications?.enabled,
    state.notifications?.medicationTime,
    state.notifications?.top3Time,
    state.notifications?.billsLeadDays,
    JSON.stringify(state.bills),
    JSON.stringify(state.top3),
    JSON.stringify(state.reminders?.map(r => [r.id, r.doneToday])),
    permission,
  ]);

  const enable = React.useCallback(async () => {
    const r = await requestNotificationPermission();
    setPermission(typeof Notification !== 'undefined' ? Notification.permission : 'unavailable');
    if (r.granted) {
      set(s => ({ ...s, notifications: { ...(s.notifications || {}), enabled: true } }));
      // Demo notification
      setTimeout(() => showNotification('💚 Notificaties aan', 'Je krijgt herinneringen voor medicatie, top-3 en rekeningen.', 'maud-welcome'), 400);
    }
    return r;
  }, [set]);

  const disable = React.useCallback(() => {
    set(s => ({ ...s, notifications: { ...(s.notifications || {}), enabled: false } }));
  }, [set]);

  const testNotify = React.useCallback(() => {
    showNotification('Test 💚', 'Notificaties werken — je krijgt ze om de gekozen tijden.', 'maud-test');
  }, []);

  const pending = state.notifications?.enabled && permission === 'granted'
    ? buildTodaysSchedule(state)
    : [];

  return {
    permission, enable, disable, testNotify,
    pending, swReady, isStandalone: isStandalone(), isIOS: isIOS(),
  };
}

Object.assign(window, {
  registerServiceWorker, requestNotificationPermission, showNotification,
  buildTodaysSchedule, useNotifications, isStandalone, isIOS,
});
