import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import App from './App.tsx';
import './index.css';
import { initErrorLogger } from './lib/errorLogger';
import { ErrorBoundary } from './components/ErrorBoundary';

// Ensure window.fetch has both a getter and setter across its entire prototype chain
(function makeFetchWritable() {
  if (typeof window === 'undefined') return;
  try {
    const realFetch = window.fetch ? window.fetch.bind(window) : null;
    let assignedFetch: any = null;

    const patch = (obj: any) => {
      if (!obj) return false;
      try {
        const desc = Object.getOwnPropertyDescriptor(obj, 'fetch');
        if (desc) {
          const origGet = desc.get;
          const origVal = desc.value;
          Object.defineProperty(obj, 'fetch', {
            get() {
              return assignedFetch || (origGet ? origGet.call(this) : (origVal || realFetch));
            },
            set(fn) {
              assignedFetch = fn;
            },
            configurable: true,
            enumerable: true,
          });
          return true;
        }
      } catch {}
      return false;
    };

    let curr: any = window;
    while (curr) {
      patch(curr);
      curr = Object.getPrototypeOf(curr);
    }

    if (typeof Window !== 'undefined' && Window.prototype) {
      patch(Window.prototype);
    }

    try {
      Object.defineProperty(window, 'fetch', {
        get() {
          return assignedFetch || realFetch;
        },
        set(fn) {
          assignedFetch = fn;
        },
        configurable: true,
        enumerable: true,
      });
    } catch {}
  } catch {}
})();

// Global handler to suppress benign WebSocket / Vite HMR preview sandbox events
const isNoiseText = (text: string) => {
  const lower = text.toLowerCase();
  return (
    lower.includes('cannot set property fetch') ||
    lower.includes('which has only a getter') ||
    lower.includes('has only a getter') ||
    lower.includes('websocket') ||
    lower.includes('failed to connect') ||
    lower.includes('closed without opened') ||
    lower.includes('closeevent') ||
    lower.includes('vite') ||
    lower.includes('ws://') ||
    lower.includes('wss://')
  );
};

// Hook window.onerror directly so that returning true prevents unhandled error reporting
const existingOnError = window.onerror;
window.onerror = function (msg, url, line, col, err) {
  try {
    const combined = [msg, url, err?.message, err?.stack].join(' ');
    if (isNoiseText(combined)) {
      return true; // suppresses unhandled error reporting
    }
  } catch {}
  if (typeof existingOnError === 'function') {
    return existingOnError.apply(this, arguments as any);
  }
  return false;
};

const existingOnRejection = window.onunhandledrejection;
window.onunhandledrejection = function (e: any) {
  try {
    const reason = e?.reason || e;
    const combined = [reason?.message, reason?.stack, String(reason)].join(' ');
    if (isNoiseText(combined)) {
      if (e && typeof e.preventDefault === 'function') e.preventDefault();
      return true;
    }
  } catch {}
  if (typeof existingOnRejection === 'function') {
    return existingOnRejection.apply(this, arguments as any);
  }
};

const suppressNoise = (e: any) => {
  const reason = e?.reason || e?.error || e?.message || e;
  let text = '';
  try {
    text = (typeof reason === 'string' ? reason : (reason?.message || reason?.reason || reason?.type || reason?.stack || reason?.constructor?.name || String(reason || ''))).toLowerCase();
    if (e?.type) text += ' ' + String(e.type).toLowerCase();
    if (e?.target?.constructor?.name) text += ' ' + String(e.target.constructor.name).toLowerCase();
  } catch {}

  if (isNoiseText(text)) {
    if (typeof e?.preventDefault === 'function') e.preventDefault();
    if (typeof e?.stopImmediatePropagation === 'function') e.stopImmediatePropagation();
    if (typeof e?.stopPropagation === 'function') e.stopPropagation();
    return true;
  }
  return false;
};

window.addEventListener('unhandledrejection', suppressNoise, true);
window.addEventListener('error', suppressNoise, true);

// Purge stale static caches that might hold outdated React / Vite dev chunks
if (typeof window !== 'undefined' && 'caches' in window) {
  try {
    caches.keys().then((keys) => {
      keys.forEach((key) => {
        if (key.includes('jrshop-static-v1') || key.includes('jrshop-static-v2') || key.includes('jrshop-static-v3')) {
          caches.delete(key);
        }
      });
    }).catch(() => {});
  } catch {}
}

// Inisialisasi Error Logger global untuk menangkap runtime errors & unhandled rejections
initErrorLogger();

createRoot(document.getElementById('root')!).render(
  <StrictMode>
    <ErrorBoundary>
      <App />
    </ErrorBoundary>
  </StrictMode>,
);
