import '../styles/globals.css';
import type {AppProps} from 'next/app';
import {useRouter} from 'next/router';
import React, {useEffect} from 'react';
import {Toaster} from 'sonner';
import {SWRConfig} from 'swr';
import {DefaultSeo} from 'next-seo';
import {NuqsAdapter} from 'nuqs/adapters/next/pages';
import {Loader} from '@plunk/ui';
import {ActiveProjectProvider} from '../lib/contexts/ActiveProjectProvider';
import {useProjects} from '../lib/hooks/useProject';
import {useUser} from '../lib/hooks/useUser';
import {network} from '../lib/network';
import dayjs from 'dayjs';
import relativeTime from 'dayjs/plugin/relativeTime';
import advancedFormat from 'dayjs/plugin/advancedFormat';
import Script from 'next/script';

// Configure dayjs plugins globally
dayjs.extend(relativeTime);
dayjs.extend(advancedFormat);

// Routes that don't require authentication
const PUBLIC_ROUTES = [
  '/auth/login',
  '/auth/signup',
  '/auth/reset-password',
  '/auth/verify-email',
  '/unsubscribe',
  '/subscribe',
  '/manage',
];

// Routes that don't require a project
const NO_PROJECT_ROUTES = ['/projects/create'];

function App({Component, pageProps}: AppProps) {
  return (
    <>
      <Component {...pageProps} />
    </>
  );
}

function AuthGuard({children}: {children: React.ReactNode}) {
  const {data: user, isLoading} = useUser();
  const router = useRouter();
  const isPublicRoute = PUBLIC_ROUTES.some(
    route => router.pathname === route || router.pathname.startsWith(`${route}/`),
  );

  useEffect(() => {
    // If not loading, no user, and trying to access a protected route, redirect to login
    if (!isLoading && !user && !isPublicRoute) {
      void router.push('/auth/login');
    }

    // If user is logged in and trying to access login/signup, redirect to home
    if (!isLoading && user && (router.pathname === '/auth/login' || router.pathname === '/auth/signup')) {
      void router.push('/');
    }
  }, [user, isLoading, router, isPublicRoute]);

  // Show loading state while checking authentication (only for protected routes)
  if (isLoading && !isPublicRoute) {
    return <Loader message="Authenticating..." />;
  }

  // Don't render protected content if redirecting
  if (!user && !isPublicRoute) {
    return null;
  }

  return <>{children}</>;
}

function ProjectGuard({children}: {children: React.ReactNode}) {
  const {data: projects, isLoading} = useProjects();
  const router = useRouter();
  const isNoProjectRoute = NO_PROJECT_ROUTES.includes(router.pathname);

  useEffect(() => {
    // If not loading, user has no projects, and not already on project creation page
    if (!isLoading && projects && projects.length === 0 && !isNoProjectRoute) {
      void router.push('/projects/create');
    }
  }, [projects, isLoading, router, isNoProjectRoute]);

  // Show loading state while checking projects (only for routes that need a project)
  if (isLoading && !isNoProjectRoute) {
    return <Loader message="Loading project..." />;
  }

  // Don't render protected content if redirecting
  if (!isLoading && projects && projects.length === 0 && !isNoProjectRoute) {
    return null;
  }

  return <>{children}</>;
}

/**
 * Main app root component that houses all components
 * @param props Default nextjs props
 */
export default function WithProviders(props: AppProps) {
  return (
    <NuqsAdapter>
      <SWRConfig
        value={{
          fetcher: (url: string) => network.fetch('GET', url),
          shouldRetryOnError: false,
        }}
      >
        <DefaultSeo titleTemplate="%s | Plunk" defaultTitle="Plunk | Email Platform Dashboard" />

        <Script
          defer
          src="https://analytics.driaug.com/script.js"
          data-website-id="5880df93-9025-41ae-8e33-7c3da865f764"
          data-domains="next-app.useplunk.com"
        />

        <ActiveProjectProvider>
          <Root {...props} />
        </ActiveProjectProvider>
      </SWRConfig>
    </NuqsAdapter>
  );
}

function Root(props: AppProps) {
  const router = useRouter();
  const isPublicRoute = PUBLIC_ROUTES.some(
    route => router.pathname === route || router.pathname.startsWith(`${route}/`),
  );

  return (
    <>
      <Toaster position={'top-right'} />

      <div>
        <AuthGuard>
          {isPublicRoute ? (
            <App {...props} />
          ) : (
            <ProjectGuard>
              <App {...props} />
            </ProjectGuard>
          )}
        </AuthGuard>
      </div>
    </>
  );
}
