import React from 'react'
import ReactDOM from 'react-dom/client'
import { BrowserRouter } from 'react-router-dom'
import { HelmetProvider } from 'react-helmet-async'
import App from './App.tsx'
import './index.css'
import { CurrencyProvider } from './contexts/CurrencyContext.tsx'
import { ThemeProvider } from './contexts/ThemeContext.tsx'

// ── Global fetch interceptor ─────────────────────────────────────────────
// Attaches Bearer token to all API requests and auto-redirects to login on 401.
;((() => {
  const API_HOSTS = ['ravikumar289-002-site1.anytempurl.com', 'localhost:7076', 'localhost:7077'];
  const _fetch = (window.fetch as typeof fetch).bind(window);

  // Endpoints that handle 401 gracefully themselves — do NOT trigger a hard
  // redirect for these.  Redirecting on their 401 causes infinite reload loops
  // because the component error-handles the failure and re-renders, which
  // re-triggers the same API call on the new page load.
  const SILENT_401_PATHS = [
    // Auth / profile (mock-user fallback)
    '/api/PageVisibility/',
    '/api/register/by-email/',
    '/api/users',
    '/api/UserCredits/',
    // Feed & social content — these are [AllowAnonymous] on the backend;
    // 401 here means an expired token, handled by showing empty state
    // Feed & all social/content endpoints — components handle their own errors
    '/api/feed',
    '/api/Feed',
    '/api/notifications/',
    '/api/Notifications/',
    '/api/followers',
    '/api/Followers',
    '/api/stories',
    '/api/Stories',
    '/api/reels',
    '/api/Reels',
    '/api/ads',
    '/api/Ads',
    '/api/pages',
    '/api/Pages',
    '/api/marketplace',
    '/api/Marketplace',
    '/api/DirectChat',
    '/api/directchat',
    '/api/GroupChat',
    '/api/groupchat',
    '/api/messages',
    '/api/Messages',
    '/api/search',
    '/api/Search',
    '/api/activity',
    '/api/Activity',
    // Chat notifications — polled frequently, fail silently when server is down
    '/api/private-chat/notifications',
    '/api/PrivateChat/notifications',
    '/api/chat/notifications',
  ];

  // Endpoints that should NEVER trigger a hard redirect even on 500.
  // These are polled frequently — a transient server error should just be ignored.
  const SILENT_500_PATHS = [
    '/api/private-chat/notifications',
    '/api/UserCredits/',
    '/api/notifications/',
    '/api/feed',
    '/api/pages',
    '/api/stories',
    '/api/ads',
  ];

  // Guard: prevent concurrent 401 responses from firing multiple simultaneous
  // redirects. Only the first one takes effect; rest are no-ops until reload.
  let _redirecting = false;

  function isApiUrl(url: string): boolean {
    return API_HOSTS.some(h => url.includes(h));
  }

  function isSilent401(url: string): boolean {
    return SILENT_401_PATHS.some(p => url.includes(p));
  }

  function isSilent500(url: string): boolean {
    return SILENT_500_PATHS.some(p => url.includes(p));
  }

  function buildHeaders(existing: HeadersInit | undefined, token: string): Headers {
    const h = new Headers();
    if (existing) {
      if (existing instanceof Headers) {
        existing.forEach((v, k) => h.set(k, v));
      } else if (Array.isArray(existing)) {
        (existing as [string, string][]).forEach(([k, v]) => h.set(k, v));
      } else {
        Object.entries(existing as Record<string, string>).forEach(([k, v]) => h.set(k, v));
      }
    }
    if (!h.has('Authorization')) h.set('Authorization', `Bearer ${token}`);
    return h;
  }

  window.fetch = function interceptedFetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response> {
    try {
      const url = input instanceof Request ? input.url
                : input instanceof URL    ? input.href
                : String(input);

      if (isApiUrl(url)) {
        const token = localStorage.getItem('auth_token');
        if (token) {
          init = { ...(init ?? {}), headers: buildHeaders(init?.headers, token) };
        }

        return _fetch(input as RequestInfo, init).then(res => {
          // Write operations (POST/PUT/PATCH/DELETE) always redirect on 401 —
          // a write failure means the session expired and the user must re-login.
          // Only GET/HEAD reads are silenced (they show empty state instead).
          const method = ((init?.method) ?? 'GET').toUpperCase();
          const isWriteRequest = method !== 'GET' && method !== 'HEAD';

          // 500 on non-critical polling endpoints (e.g. chat notifications, credits)
          // should be swallowed — typically caused by transient DB/server issues.
          // The component's catch block will handle it gracefully.
          if (res.status >= 500 && isSilent500(url)) {
            return res; // return as-is, component handles silently
          }

          if (
            res.status === 401
            && !window.location.pathname.includes('/login')
            && !_redirecting
            && (!isSilent401(url) || isWriteRequest)
          ) {
            _redirecting = true;
            localStorage.removeItem('auth_token');
            localStorage.removeItem('auth_user');
            window.location.href = '/login';
          }
          return res;
        });
      }
    } catch { /* never break fetch */ }
    return _fetch(input as RequestInfo, init);
  };
})());

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <ThemeProvider>
      <HelmetProvider>
        <BrowserRouter>
          <CurrencyProvider>
            <App />
          </CurrencyProvider>
        </BrowserRouter>
      </HelmetProvider>
    </ThemeProvider>
  </React.StrictMode>,
)
