/* eslint-disable import/first */
import React from 'react';
import { createRoot } from 'react-dom/client';
import { enableMapSet } from 'immer';
import '@fontsource-variable/inter/index.css';
import 'folds/dist/style.css';
import { configClass, varsClass } from 'folds';

enableMapSet();

import './index.css';

import { trimTrailingSlash } from './app/utils/common';
import App from './app/pages/App';

// import i18n (needs to be bundled ;))
import './app/i18n';
import { pushSessionToSW } from './sw-session';
import { getFallbackSession } from './app/state/sessions';

document.body.classList.add(configClass, varsClass);

// Register Service Worker
if ('serviceWorker' in navigator) {
  const swUrl =
    import.meta.env.MODE === 'production'
      ? `${trimTrailingSlash(import.meta.env.BASE_URL)}/sw.js`
      : `/dev-sw.js?dev-sw`;

  const sendSessionToSW = () => {
    const session = getFallbackSession();
    pushSessionToSW(session?.baseUrl, session?.accessToken);
  };

  navigator.serviceWorker.register(swUrl).then(sendSessionToSW);
  navigator.serviceWorker.ready.then(sendSessionToSW);

  navigator.serviceWorker.addEventListener('message', (ev) => {
    const { type } = ev.data ?? {};

    if (type === 'requestSession') {
      sendSessionToSW();
    }
  });
}

// Request persistent storage so the browser can't evict the IndexedDB
// rust-crypto store under storage pressure. Eviction (while the localStorage
// session/device-id survives) resurrects the device with a blank crypto store,
// which then re-uploads OTKs the server already holds → the "one time key
// already exists" upload storm and E2EE breakage. Only ask for sessions worth
// protecting (skip anonymous/landing visitors to avoid a needless Firefox
// prompt); check persisted() first so we don't re-prompt. Best-effort.
if (navigator.storage?.persist && getFallbackSession()) {
  navigator.storage
    .persisted()
    .then((already) => (already ? undefined : navigator.storage.persist()))
    .catch(() => undefined);
}

// Reload once if a lazy-loaded chunk is missing (stale deployment)
window.addEventListener('vite:preloadError', () => {
  if (!sessionStorage.getItem('chunk-reload-attempted')) {
    sessionStorage.setItem('chunk-reload-attempted', '1');
    window.location.reload();
  }
});
// Clear the reload flag after a successful load so future deploys can still trigger a reload
window.addEventListener('load', () => sessionStorage.removeItem('chunk-reload-attempted'));

// Filter out known-benign, high-volume matrix-js-sdk console warnings that we
// can't fix client-side and that would otherwise flood the console:
//   - "Adding default global …": the SDK patches MSC3786/MSC3914 push rules on
//     every login (one warn each) until Synapse ships them as server defaults.
//   - "EventTimelineSet…": the SDK loudly warns whenever a decrypted event
//     references a thread/room the current timeline set doesn't hold, then
//     discards it harmlessly. This fires constantly in E2EE rooms with threads.
//   - "Decrypted event … is not in room …": same family — a late decryption for
//     an event the room's timeline no longer tracks; ignored by the SDK.
// These are informational SDK bookkeeping, not errors; real warnings still log.
{
  const suppressedPrefixes = ['Adding default global ', 'EventTimelineSet'];
  const _warn = console.warn.bind(console);
  console.warn = (...args: unknown[]) => {
    const first = args[0];
    if (typeof first === 'string') {
      if (suppressedPrefixes.some((p) => first.startsWith(p))) return;
      if (first.startsWith('Decrypted event ') && first.includes('is not in room')) return;
    }
    _warn(...args);
  };
}

const mountApp = () => {
  const rootContainer = document.getElementById('root');

  if (rootContainer === null) {
    console.error('Root container element not found!');
    return;
  }

  const root = createRoot(rootContainer);
  root.render(<App />);
};

mountApp();
