import { Component, ErrorInfo, ReactNode, StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import App from './App.tsx';
import './index.css';
import { secureDecrypt, secureEncrypt } from './lib/security';
import { safeB64Decode, safeJsonParse, forceSyncTimestamp } from './lib/mysqlSync';
import { initPrismaSync } from './lib/prismaSync';

class ErrorBoundary extends Component<{ children: ReactNode }, { hasError: boolean; error: Error | null }> {
  constructor(props: { children: ReactNode }) {
    super(props);
    this.state = { hasError: false, error: null };
  }

  static getDerivedStateFromError(error: Error) {
    return { hasError: true, error };
  }

  componentDidCatch(error: Error, errorInfo: ErrorInfo) {
    console.error('[E-Class Client Error]:', error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
      return (
        <div style={{ padding: '2rem', fontFamily: 'sans-serif', maxWidth: '600px', margin: '40px auto', background: '#fef2f2', border: '1px solid #fca5a5', borderRadius: '12px', color: '#991b1b' }}>
          <h2 style={{ margin: '0 0 10px 0', fontSize: '1.25rem' }}>Terjadi Kesalahan pada Aplikasi (Client Error)</h2>
          <p style={{ fontSize: '0.9rem', color: '#7f1d1d' }}>{this.state.error?.message || 'Unknown error occurred'}</p>
          <button 
            onClick={() => window.location.reload()}
            style={{ marginTop: '12px', padding: '8px 16px', background: '#dc2626', color: '#fff', border: 'none', borderRadius: '6px', cursor: 'pointer' }}
          >
            Muat Ulang Halaman
          </button>
        </div>
      );
    }
    return this.props.children;
  }
}

// Initialize initializing flag and initial sync status to prevent initial empty-state writes from overriding cPanel MySQL database
if (typeof window !== 'undefined') {
  (window as any).__ECLASS_INITIALIZING__ = true;
  (window as any).__ECLASS_INITIAL_SYNC_DONE__ = false;
  // Trigger initial synchronization with cPanel MySQL database on app boot
  initPrismaSync().catch(() => {});
}

// --- Intercept localStorage changes with Quota Guard and debounced event dispatching ---
if (typeof window !== 'undefined' && typeof Storage !== 'undefined') {
  const nativeSetItem = Storage.prototype.setItem;
  const nativeRemoveItem = Storage.prototype.removeItem;

  (localStorage as any).__originalSetItem = nativeSetItem.bind(localStorage);
  (localStorage as any).__originalRemoveItem = nativeRemoveItem.bind(localStorage);

  let dispatchTimer: any = null;
  const changedKeyQueue = new Set<string>();

  const flushDispatchedEvents = () => {
    if (changedKeyQueue.size === 0) return;
    const keys = Array.from(changedKeyQueue);
    changedKeyQueue.clear();
    try {
      window.dispatchEvent(new CustomEvent('eclass-data-changed', { detail: { keys, source: 'local' } }));
    } catch (e) {
      // ignore
    }
  };

  const safePruneStorageOnQuotaError = () => {
    try {
      // Clean obsolete GTK keys and temporary cache from local storage
      const obsoleteKeys = [
        'eclass_gtk_attendance',
        'eclass_gtk_attendance_logs',
        'eclass_gtk_presensi_logs',
        'eclass_gtk_presensi_config',
        'eclass_gtk_leaves',
        'eclass_gtk_letterhead_config',
        'eclass_rekap_absensi_cache',
        'eclass_mysql_sync_cache'
      ];
      obsoleteKeys.forEach(k => {
        try { nativeRemoveItem.call(localStorage, k); } catch (e) {}
      });

      // Remove any oversized temp debug or sync log items
      for (let i = localStorage.length - 1; i >= 0; i--) {
        const k = localStorage.key(i);
        if (k && (k.startsWith('eclass_temp_') || k.startsWith('eclass_log_') || k.includes('cache'))) {
          try { nativeRemoveItem.call(localStorage, k); } catch (e) {}
        }
      }
    } catch (e) {
      // ignore
    }
  };

  Storage.prototype.setItem = function (key: string, value: string) {
    try {
      nativeSetItem.call(this, key, value);
    } catch (err: any) {
      if (err && (err.name === 'QuotaExceededError' || err.name === 'NS_ERROR_DOM_QUOTA_REACHED' || err.code === 22)) {
        console.warn('[Storage Quota Guard] Quota exceeded. Pruning obsolete cache...');
        safePruneStorageOnQuotaError();
        try {
          nativeSetItem.call(this, key, value);
        } catch (retryErr) {
          console.error('[Storage Quota Guard] Failed to write item after pruning:', key);
          return;
        }
      } else {
        console.error('[Storage SetItem Error]:', err);
        return;
      }
    }

    if (this === localStorage && 
        key && typeof key === 'string' &&
        key.startsWith('eclass_') && 
        key !== 'eclass_sync_timestamps' && 
        key !== 'eclass_mysql_sync_cache' && 
        key !== 'eclass_mysql_sync_config' &&
        key !== 'eclass_is_clearing_data_flag' &&
        key !== 'eclass_last_active_time') {
      try {
        if ((window as any).__ECLASS_INITIAL_SYNC_DONE__ || (window as any).__ECLASS_MANUAL_SAVE_IN_PROGRESS__) {
          forceSyncTimestamp(key);
        }
      } catch (e) {
        // ignore
      }

      changedKeyQueue.add(key);
      if (!dispatchTimer) {
        dispatchTimer = setTimeout(() => {
          dispatchTimer = null;
          flushDispatchedEvents();
        }, 80);
      }
    }
  };

  Storage.prototype.removeItem = function (key: string) {
    try {
      nativeRemoveItem.call(this, key);
    } catch (e) {
      // ignore
    }

    if (this === localStorage && 
        key && typeof key === 'string' &&
        key.startsWith('eclass_') && 
        key !== 'eclass_sync_timestamps' && 
        key !== 'eclass_mysql_sync_cache' && 
        key !== 'eclass_mysql_sync_config' &&
        key !== 'eclass_is_clearing_data_flag' &&
        key !== 'eclass_last_active_time') {
      try {
        if ((window as any).__ECLASS_INITIAL_SYNC_DONE__ || (window as any).__ECLASS_MANUAL_SAVE_IN_PROGRESS__) {
          forceSyncTimestamp(key);
        }
      } catch (e) {
        // ignore
      }

      changedKeyQueue.add(key);
      if (!dispatchTimer) {
        dispatchTimer = setTimeout(() => {
          dispatchTimer = null;
          flushDispatchedEvents();
        }, 80);
      }
    }
  };
}

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