import React from 'react';
import type { AppProps } from 'next/app';
import type { ReactElement, ReactNode } from 'react';
import type { NextPage } from 'next';
import Head from 'next/head';
import { store } from '../stores/store';
import { Provider } from 'react-redux';

// Import Instrument Sans font (self-hosted via Fontsource)
import '@fontsource-variable/instrument-sans';
import '@fontsource-variable/instrument-sans/wdth.css'; // Condensed width axis
import '../css/main.css';
import axios from 'axios';
import { baseURLApi } from '../config';
import { useRouter } from 'next/router';
import ErrorBoundary from '../components/ErrorBoundary';
import 'intro.js/introjs.css';
import { appWithTranslation } from 'next-i18next';
import '../i18n';
import IntroGuide from '../components/IntroGuide';
import {
  appSteps,
  loginSteps,
  usersSteps,
  rolesSteps,
} from '../stores/introSteps';
import { DownloadProvider } from '../context/DownloadContext';
import { logger } from '../lib/logger';
import { disablePresignedUrls } from '../lib/assetUrl';

/**
 * Check if a URL is a presigned S3 URL
 */
const isPresignedS3Url = (url: string): boolean => {
  return url.includes('X-Amz-Signature=') || url.includes('x-amz-signature=');
};

// Initialize axios
axios.defaults.baseURL = process.env.NEXT_PUBLIC_BACK_API
  ? process.env.NEXT_PUBLIC_BACK_API
  : baseURLApi;

axios.defaults.headers.common['Content-Type'] = 'application/json';

// Set up axios request interceptor synchronously to ensure token is always attached
axios.interceptors.request.use(
  (config) => {
    if (typeof window !== 'undefined') {
      const token =
        sessionStorage.getItem('token') || localStorage.getItem('token');
      if (token) {
        config.headers.Authorization = `Bearer ${token}`;
      } else {
        delete config.headers.Authorization;
      }
    }
    return config;
  },
  (error) => Promise.reject(error),
);

// Set up axios response interceptor to handle 401 errors and presigned URL failures
axios.interceptors.response.use(
  (response) => response,
  (error) => {
    if (typeof window !== 'undefined') {
      const status = error?.response?.status;
      const requestUrl = `${error?.config?.url || ''}`;
      const isLoginRequest =
        requestUrl.includes('/auth/signin/local') ||
        requestUrl.includes('auth/signin/local');

      // Detect presigned S3 URL failures (CORS not configured)
      // Network errors (status 0) or CORS errors typically indicate S3 CORS issues
      if (
        isPresignedS3Url(requestUrl) &&
        (!status || status === 0 || error.message?.includes('Network Error'))
      ) {
        logger.info('[axios] Presigned URL failed, disabling presigned URLs', {
          url: requestUrl.slice(0, 80),
        });
        disablePresignedUrls();
      }

      if (status === 401 && !isLoginRequest) {
        // Clear stored tokens
        sessionStorage.removeItem('token');
        sessionStorage.removeItem('user');
        localStorage.removeItem('token');
        localStorage.removeItem('user');
        delete axios.defaults.headers.common['Authorization'];

        // Redirect to login if not already there
        if (!window.location.pathname.includes('/login')) {
          window.location.href = '/login';
        }
      }
    }
    return Promise.reject(error);
  },
);

export type NextPageWithLayout<P = Record<string, unknown>, IP = P> = NextPage<
  P,
  IP
> & {
  getLayout?: (page: ReactElement) => ReactNode;
};

type AppPropsWithLayout = AppProps & {
  Component: NextPageWithLayout;
};

function MyApp({ Component, pageProps }: AppPropsWithLayout) {
  // Use the layout defined at the page level, if available
  const getLayout = Component.getLayout || ((page) => page);
  const router = useRouter();
  const [stepsEnabled, setStepsEnabled] = React.useState(false);
  const [stepName, setStepName] = React.useState('');
  const [steps, setSteps] = React.useState([]);

  // Register service worker for PWA offline support
  React.useEffect(() => {
    if (
      typeof window !== 'undefined' &&
      'serviceWorker' in navigator &&
      process.env.NODE_ENV === 'production'
    ) {
      navigator.serviceWorker
        .register('/sw.js')
        .then((registration) => {
          logger.info('[PWA] Service worker registered:', {
            scope: registration.scope,
          });

          // Check for updates periodically
          setInterval(
            () => {
              registration.update();
            },
            60 * 60 * 1000,
          ); // Check every hour
        })
        .catch((error) => {
          logger.error(
            '[PWA] Service worker registration failed:',
            error instanceof Error ? error : { error },
          );
        });
    }
  }, []);

  // TODO: Remove this code in future releases
  React.useEffect(() => {
    const trustedOrigins = new Set<string>([window.location.origin]);
    if (document.referrer) {
      try {
        trustedOrigins.add(new URL(document.referrer).origin);
      } catch (error) {
        logger.warn(
          '[postMessage] Failed to parse parent origin from referrer',
          error instanceof Error ? error : { error },
        );
      }
    }

    const isTrustedOrigin = (origin: string) => trustedOrigins.has(origin);

    const handleMessage = async (event: MessageEvent) => {
      if (!isTrustedOrigin(event.origin)) {
        logger.warn('[postMessage] Blocked message from untrusted origin', {
          origin: event.origin,
        });
        return;
      }

      if (event.data === 'getLocation') {
        (event.source as WindowProxy)?.postMessage(
          { iframeLocation: window.location.pathname },
          { targetOrigin: event.origin },
        );
        return;
      }

      if (event.data === 'getAuthToken') {
        const token =
          sessionStorage.getItem('token') || localStorage.getItem('token');
        const user =
          sessionStorage.getItem('user') || localStorage.getItem('user');
        (event.source as WindowProxy)?.postMessage(
          { iframeAuthToken: token, iframeAuthUser: user },
          { targetOrigin: event.origin },
        );
        return;
      }

      if (event.data === 'getScreenshot') {
        try {
          const html2canvas = (await import('html2canvas')).default;
          const canvas = await html2canvas(document.body, { useCORS: true });
          const url = canvas.toDataURL('image/jpeg', 0.8);
          (event.source as WindowProxy)?.postMessage(
            { iframeScreenshot: url },
            { targetOrigin: event.origin },
          );
        } catch (e) {
          logger.error(
            'html2canvas failed',
            e instanceof Error ? e : { error: e },
          );
          (event.source as WindowProxy)?.postMessage(
            { iframeScreenshot: null },
            { targetOrigin: event.origin },
          );
        }
      }
    };

    window.addEventListener('message', handleMessage);
    return () => window.removeEventListener('message', handleMessage);
  }, []);

  React.useEffect(() => {
    // Tour is disabled by default in generated projects.
    return;
    const isCompleted = (stepKey: string) => {
      return localStorage.getItem(`completed_${stepKey}`) === 'true';
    };
    if (router.pathname === '/login' && !isCompleted('loginSteps')) {
      setSteps(loginSteps);
      setStepName('loginSteps');
      setStepsEnabled(true);
    } else if (router.pathname === '/dashboard' && !isCompleted('appSteps')) {
      setTimeout(() => {
        setSteps(appSteps);
        setStepName('appSteps');
        setStepsEnabled(true);
      }, 1000);
    } else if (
      router.pathname === '/users/users-list' &&
      !isCompleted('usersSteps')
    ) {
      setTimeout(() => {
        setSteps(usersSteps);
        setStepName('usersSteps');
        setStepsEnabled(true);
      }, 1000);
    } else if (
      router.pathname === '/roles/roles-list' &&
      !isCompleted('rolesSteps')
    ) {
      setTimeout(() => {
        setSteps(rolesSteps);
        setStepName('rolesSteps');
        setStepsEnabled(true);
      }, 1000);
    } else {
      setSteps([]);
      setStepsEnabled(false);
    }
  }, [router.pathname]);

  const handleExit = () => {
    setStepsEnabled(false);
  };

  const title = 'Shimahara Visual';
  const description =
    'Platform to build, preview (stage), and publish offline-ready interactive tours on project subdomains.';
  const url = 'https://flatlogic.com/';
  const image =
    'https://project-screens.s3.amazonaws.com/screenshots/39215/app-hero-20260316-121031.png';
  const imageWidth = '1920';
  const imageHeight = '960';

  return (
    <Provider store={store}>
      <DownloadProvider>
        {getLayout(
          <>
            <Head>
              <meta name='description' content={description} />
              <meta property='og:url' content={url} />
              <meta property='og:site_name' content='https://flatlogic.com/' />
              <meta key='og:title' property='og:title' content={title} />
              <meta key='og:description' property='og:description' content={description} />
              <meta key='og:image' property='og:image' content={image} />
              <meta property='og:image:type' content='image/png' />
              <meta property='og:image:width' content={imageWidth} />
              <meta property='og:image:height' content={imageHeight} />
              <meta property='twitter:card' content='summary_large_image' />
              <meta key='twitter:title' property='twitter:title' content={title} />
              <meta key='twitter:description' property='twitter:description' content={description} />
              <meta key='twitter:image:src' property='twitter:image:src' content={image} />
              <meta property='twitter:image:width' content={imageWidth} />
              <meta property='twitter:image:height' content={imageHeight} />
              <link key='favicon' rel='icon' href='/favicon.svg' />
              <link rel='manifest' href='/manifest.json' />
              <meta name='theme-color' content='#3B82F6' />
              <meta name='mobile-web-app-capable' content='yes' />
              <meta
                name='apple-mobile-web-app-status-bar-style'
                content='default'
              />
              <meta name='apple-mobile-web-app-title' content='Tour Builder' />
            </Head>

            <ErrorBoundary>
              <Component {...pageProps} />
            </ErrorBoundary>
            <IntroGuide
              steps={steps}
              stepsName={stepName}
              stepsEnabled={stepsEnabled}
              onExit={handleExit}
            />
          </>,
        )}
      </DownloadProvider>
    </Provider>
  );
}

export default appWithTranslation(MyApp);
