import { StrictMode, lazy, Suspense } from 'react';
import { createRoot } from 'react-dom/client';
import { HashRouter, Routes, Route, useLocation } from 'react-router-dom';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { AuthProvider } from './contexts/AuthContext.tsx';
import { DateProvider } from './contexts/DateContext.tsx';
import { LoadingProvider } from '@/contexts/LoadingContext';
import { TimezoneProvider } from './contexts/TimezoneContext.tsx';
import { ThemeProvider } from './contexts/ThemeContext.tsx';
import { FutureSalesProvider } from './contexts/FutureSalesContext.tsx';
import { FuturePurchasesProvider } from './contexts/FuturePurchasesContext.tsx';
import { Toaster } from './components/ui/toaster.tsx';
import { Toaster as Sonner, toast as sonnerToast } from 'sonner';
import { TooltipProvider } from './components/ui/tooltip.tsx';
import { StoreProvider } from './contexts/StoreContext';
import { ErrorBoundary } from '@/components/ErrorBoundary';
import { VersionChecker } from '@/components/VersionChecker';

import { hardReload, isChunkLoadFailure } from '@/lib/hardReload';

// Importar logger de produção ANTES de qualquer código que use console
import './lib/productionLogger';

// Force cache bust - v2
import './index.css';

// Auto-update on app open: silently check for new version and force update if needed
// Uses sessionStorage to run only once per session (avoids infinite reload loops)
import { fetchServerFingerprint, getPageAssetHashes, getStoredValue, setStoredValue } from '@/lib/updateVersion';
import { SERVER_HASH_KEY, POST_RELOAD_GRACE, LOOP_GUARD_KEY, LOOP_GUARD_MS } from '@/lib/updateKeys';
import { forceManualUpdate } from '@/lib/forceUpdate';

const AUTO_UPDATE_SESSION_KEY = '__auto_update_done';

function isAutoUpdateLoop(): boolean {
  try {
    const last = localStorage.getItem(LOOP_GUARD_KEY);
    if (last && Date.now() - Number(last) < LOOP_GUARD_MS) return true;
  } catch {}
  return false;
}

if (!sessionStorage.getItem(AUTO_UPDATE_SESSION_KEY) && !isAutoUpdateLoop()) {
  sessionStorage.setItem(AUTO_UPDATE_SESSION_KEY, '1');

  // Run async check without blocking app render
  (async () => {
    try {
      const serverHash = await fetchServerFingerprint('_auto');
      if (!serverHash) return;

      const storedHash = getStoredValue(SERVER_HASH_KEY);
      const currentAssets = getPageAssetHashes();

      // If server hash matches what we have, no update needed
      if (serverHash === currentAssets) {
        // Ensure baseline is stored
        if (!storedHash) setStoredValue(SERVER_HASH_KEY, serverHash);
        return;
      }

      // If server hash differs from current DOM assets → new version available → force update
      if (serverHash !== currentAssets && currentAssets && currentAssets.split('|').length >= 2) {
        console.log('[AutoUpdate] Nova versão detectada, atualizando automaticamente...');
        await forceManualUpdate();
      }
    } catch {
      // Silently ignore errors — don't block app startup
    }
  })();
}

// Safari/iOS: force-unregister stale service workers that serve cached HTML
// This prevents the "can't access via WiFi" issue on iPhones
if ('serviceWorker' in navigator) {
  const isSafari = /Safari/i.test(navigator.userAgent) && !/Chrome|CriOS|Chromium/i.test(navigator.userAgent);
  const isIOS = /iPhone|iPad|iPod/i.test(navigator.userAgent);

  if (isSafari || isIOS) {
    navigator.serviceWorker.getRegistrations().then(regs => {
      regs.forEach(reg => {
        // Force SW update check on every page load for Safari/iOS
        reg.update().catch(() => {});
      });
    }).catch(() => {});
  }
}

// Recover from broken ESM chunk loads (Safari/PWA cache edge cases)
// This prevents a permanent blank screen by forcing a cache-busted reload.
window.addEventListener('error', (event) => {
  const message = (event as ErrorEvent)?.message ?? '';
  if (isChunkLoadFailure(message)) {
    void hardReload(message);
  }
});

window.addEventListener('unhandledrejection', (event) => {
  const reason = (event as PromiseRejectionEvent)?.reason;

  // Recuperação específica para chunks
  if (isChunkLoadFailure(reason)) {
    void hardReload(typeof reason === 'string' ? reason : 'unhandledrejection');
    return;
  }

  // Segurança: não deixar rejeição não tratada "travar" a UI (Android WebView/Chrome)
  console.error('Unhandled promise rejection:', reason);
  try {
    sonnerToast.error('Ocorreu um erro inesperado. Tente novamente.');
  } catch {
    // ignore
  }

  // Evita log/erro padrão em alguns browsers que pode interromper fluxo
  event.preventDefault();
});

// Bloquear zoom por gesto/double-tap no mobile sem afetar o scroll vertical
const preventGestureZoom = (event: Event) => {
  event.preventDefault();
};

let lastTouchEnd = 0;
const preventDoubleTapZoom = (event: TouchEvent) => {
  const now = Date.now();
  if (now - lastTouchEnd <= 300) {
    event.preventDefault();
  }
  lastTouchEnd = now;
};

const preventPinchZoom = (event: TouchEvent) => {
  if (event.touches.length > 1) {
    event.preventDefault();
  }
};

window.addEventListener('gesturestart', preventGestureZoom as EventListener, { passive: false });
window.addEventListener('gesturechange', preventGestureZoom as EventListener, { passive: false });
window.addEventListener('gestureend', preventGestureZoom as EventListener, { passive: false });
window.addEventListener('touchmove', preventPinchZoom, { passive: false });
window.addEventListener('touchend', preventDoubleTapZoom, { passive: false });

// iOS: prevent overscroll bounce on the body/document while allowing scroll inside scrollable containers
document.addEventListener('touchmove', (e) => {
  // Allow scroll inside elements that are scrollable
  let target = e.target as HTMLElement | null;
  while (target && target !== document.body) {
    const style = window.getComputedStyle(target);
    const overflowY = style.overflowY;
    const overflowX = style.overflowX;
    if (
      (overflowY === 'auto' || overflowY === 'scroll') && target.scrollHeight > target.clientHeight ||
      (overflowX === 'auto' || overflowX === 'scroll') && target.scrollWidth > target.clientWidth
    ) {
      return; // allow scroll inside this container
    }
    target = target.parentElement;
  }
  // No scrollable parent found — prevent bounce
  e.preventDefault();
}, { passive: false });

// Lazy load App for faster initial paint
const App = lazy(() => import('./App.tsx'));
const FormularioPedidoExterno = lazy(() => import('./pages/FormularioPedidoExterno'));
const CarregamentoPublico = lazy(() => import('./pages/CarregamentoPublico'));

// Query Client with optimized settings for performance
const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: 5 * 60 * 1000, // 5 minutes
      gcTime: 15 * 60 * 1000, // 15 minutes
      retry: 1, // Faster failure
      refetchOnWindowFocus: false,
      refetchOnReconnect: true,
      refetchInterval: false,
      refetchIntervalInBackground: false,
      networkMode: 'offlineFirst',
      structuralSharing: true, // Reutilizar partes do cache que não mudaram
    },
    mutations: {
      retry: 1,
      networkMode: 'offlineFirst',
    },
  }
});

// Detect public route
const detectPublicRoute = (): boolean => {
  const fullUrl = window.location.href;
  const hash = window.location.hash || '';
  const pathname = window.location.pathname || '';

  return (
    fullUrl.includes('#/pedido/') ||
    fullUrl.includes('/#/pedido/') ||
    hash.includes('/pedido/') ||
    hash.startsWith('#/pedido/') ||
    pathname.includes('/pedido/') ||
    fullUrl.includes('#/carregamento/') ||
    fullUrl.includes('/#/carregamento/') ||
    hash.includes('/carregamento/') ||
    hash.startsWith('#/carregamento/') ||
    pathname.includes('/carregamento/') ||
    fullUrl.includes('#/teste-nota-server') ||
    fullUrl.includes('/#/teste-nota-server') ||
    hash === '#/teste-nota-server' ||
    pathname === '/teste-nota-server' ||
    pathname === '/teste-nota-server/'
  );
};

// Handle redirect for non-hash URL format (public routes)
const pathname = window.location.pathname;

// Redirect /landing to /#/landing for clean marketing URLs
if (pathname === '/landing' || pathname === '/landing/') {
  window.location.replace(`${window.location.origin}/#/landing`);
}

// Redirect /teste-nota-server to /#/teste-nota-server
if (pathname === '/teste-nota-server' || pathname === '/teste-nota-server/') {
  window.location.replace(`${window.location.origin}/#/teste-nota-server`);
}

// Redirect /criar-conta?token=... to /#/criar-conta?token=...
if (pathname === '/criar-conta' || pathname === '/criar-conta/') {
  window.location.replace(`${window.location.origin}/#/criar-conta${window.location.search}`);
}

// Redirect /aceitar-convite?token=... to /#/criar-conta?token=... for legacy invite links
if (pathname === '/aceitar-convite' || pathname === '/aceitar-convite/') {
  window.location.replace(`${window.location.origin}/#/criar-conta${window.location.search}`);
}

// Redirect /pedido/:slug to /#/pedido/:slug
if (pathname.includes('/pedido/')) {
  const slug = pathname.split('/pedido/')[1]?.split('?')[0]?.split('/')[0];
  if (slug) {
    window.location.replace(`${window.location.origin}/#/pedido/${slug}`);
  }
}

// Redirect /carregamento/:token to /#/carregamento/:token
if (pathname.includes('/carregamento/')) {
  const token = pathname.split('/carregamento/')[1]?.split('?')[0]?.split('/')[0];
  if (token) {
    window.location.replace(`${window.location.origin}/#/carregamento/${token}`);
  }
}

const isPublicRoute = detectPublicRoute();

// Minimal loading fallback for faster FCP
const MinimalLoader = () => (
  <div style={{ 
    display: 'flex', 
    alignItems: 'center', 
    justifyContent: 'center', 
    height: '100vh',
    background: 'var(--background, #fff)'
  }}>
    <div style={{
      width: '32px',
      height: '32px',
      border: '3px solid #e5e7eb',
      borderTopColor: '#8b5cf6',
      borderRadius: '50%',
      animation: 'spin 0.8s linear infinite'
    }} />
  </div>
);

// Root component with route detection
function RootApp() {
  const location = useLocation();
  const isPublic = location.pathname.startsWith('/carregamento/') || location.pathname.startsWith('/pedido/');
  
  if (isPublic) {
    return (
      <Suspense fallback={<MinimalLoader />}>
        <Routes>
          <Route path="/pedido/:empresaSlug" element={<FormularioPedidoExterno />} />
          <Route path="/carregamento/:token" element={<CarregamentoPublico />} />
          <Route path="*" element={<FormularioPedidoExterno />} />
        </Routes>
      </Suspense>
    );
  }
  
  return (
    <ErrorBoundary
      onError={(error) => {
        if (isChunkLoadFailure(error)) {
          void hardReload(error.message);
        }
      }}
    >
      <ThemeProvider defaultTheme="dark">
        <AuthProvider>
          <StoreProvider>
            <FutureSalesProvider>
            <FuturePurchasesProvider>
              <DateProvider>
                <TimezoneProvider>
                  <LoadingProvider>
                    <TooltipProvider>
                      <Suspense fallback={<MinimalLoader />}>
                        <App />
                      </Suspense>
                      <Toaster />
                    </TooltipProvider>
                  </LoadingProvider>
                </TimezoneProvider>
              </DateProvider>
            </FuturePurchasesProvider>
            </FutureSalesProvider>
          </StoreProvider>
        </AuthProvider>
      </ThemeProvider>
    </ErrorBoundary>
  );
}

// Single render
createRoot(document.getElementById('root')!).render(
  <StrictMode>
    <QueryClientProvider client={queryClient}>
      <HashRouter>
        <RootApp />
        <VersionChecker />
        <Sonner position={isPublicRoute ? "top-center" : "top-right"} style={{ zIndex: 2147483647 }} toastOptions={{ style: { zIndex: 2147483647 } }} />
      </HashRouter>
    </QueryClientProvider>
  </StrictMode>,
);
