'use client';

import { useAuth } from '@clerk/nextjs';
import { useGateValue, useStatsigClient } from '@statsig/react-bindings';
import clsx from 'clsx';
import { observer } from 'mobx-react-lite';
import dynamic from 'next/dynamic';
import { useParams, usePathname, useSearchParams } from 'next/navigation';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { useCookies } from 'react-cookie';
import { useIsClient } from 'usehooks-ts';

import AppModals from '@/app/(root)/AppModals';
import { useStores } from '@/app/(root)/AppProviders';
import SunoDevTools from '@/components/SunoDevTools';
import MobileWebRedirect from '@/components/appsflyer/MobileWebRedirect';
import { getOneLinkUrl } from '@/components/appsflyer/SmartScript';
import AntiAbuseTracker from '@/components/auth/AntiAbuseTracker';
import MaintenanceBar from '@/components/banner/MaintenanceBar';
import MobileBanner from '@/components/banner/MobileBanner';
import Ga4AnalyticsTracker from '@/components/ga4/Ga4AnalyticsTracker';
import { isVideoHooksPath } from '@/components/hooksPlayer/utils';
import { VerticalSplitGroup } from '@/components/layout/SplitPanel';
import MobileTopBar, { MobileNavNew } from '@/components/menu/MobileTopBar';
import CleffyModal from '@/components/modal/CleffyModal';
import { DialogModalContainer } from '@/components/modal/DialogModal';
import { ModalTypes } from '@/components/modal/constants/ModalTypes';
import Playbar from '@/components/playbar/Playbar';
import PlaybarAudioElements from '@/components/playbar/PlaybarAudioElements';
import RadioPlaybar from '@/components/playbar/RadioPlaybar';
import MobileCreate from '@/components/section/MobileCreate';
import SideNav from '@/components/section/SideNav';
import useSharedContentTracker from '@/components/share-tracking/useSharedContentTracker';
import StudioLoadingOverlay from '@/components/studio/StudioLoadingOverlay';
import { ToastContainer } from '@/components/toast/Toast';
import { useModalContext } from '@/context/ModalContext';
import { usePreviewContext } from '@/context/PreviewContext';
import useArtistProfileInitialize from '@/hooks/useArtistProfileInitialize';
import { useBreakpointLg, useBreakpointMd } from '@/hooks/useBreakpoint';
import useExperiment from '@/hooks/useExperiment';
import useFeedbackForm from '@/hooks/useFeedbackForm';
import useNavigationTracker from '@/hooks/useNavigationTracker';
import useNotifications from '@/hooks/useNotifications';
import usePinnedClipsInitialize from '@/hooks/usePinnedClipsInitialize';
import usePollRunningGens from '@/hooks/usePollRunningGens';
import useRemixPermissionModal from '@/hooks/useRemixPermissionModal';
import useShareTracking from '@/hooks/useShareTracking';
import useSubscriptionInfo from '@/hooks/useSubscriptionInfo';
import { useTranslationDetection } from '@/hooks/useTranslationDetection';
import useUpsells from '@/hooks/useUpsells';
import { upgradeAuth } from '@/lib/auth';
import logWebUserEvent from '@/logging/logWebUserEvent';
import { DOWNLOAD_UPGRADE_EXPERIMENT_NAME } from '@/utils/constants';
import { isIOS } from '@/utils/device';

import Captcha from './Captcha';
import LiveRadioAudioBus from './live-radio/LiveRadioAudioBus';
import { STATION_ID } from './live-radio/constants';
import { isLiveRadioPath } from './live-radio/util';

const RightSidebarContent = dynamic(
  () => import('@/components/section/SidebarContent'),
  { ssr: false }
);

const isCrossOriginIsolatedRoute = (path: string) => {
  return (
    path.startsWith('/edit') ||
    path.startsWith('/edit-v3') ||
    path.startsWith('/studio') ||
    path.startsWith('/edit-legacy')
  );
};

const CROSS_ORIGIN_DEISOLATION_REFRESH_PARAM = 'codr';

interface ClientLayoutProps {
  children: React.ReactNode;
  supportedBrowser: boolean | undefined;
  supportedCountriesForMobileBanner?: string[];
  hideSidebars?: boolean;
  hideMobileNav?: boolean;
}

/**
 * Main client layout and top-level app bootstrapping
 *
 * It would be good to further modularize this to separate the compeonnt layout
 * from the additional app bootstrapping
 */
const ClientLayout: React.FC<ClientLayoutProps> = observer((props) => {
  const {
    children,
    supportedBrowser,
    supportedCountriesForMobileBanner,
    hideSidebars: explicitHideSidebars,
    hideMobileNav: explicitHideMobileNav,
  } = props;

  const { isSignedIn, getToken, signOut } = useAuth();

  const [cookies, setCookie, removeCookie] = useCookies(['suno_auth']);
  const sunoAuthCookie = cookies.suno_auth;
  const statsigClient = useStatsigClient();
  const hasRunRef = useRef(false);

  // Handle Clerkless Auth upgrade/downgrade
  // See https://console.statsig.com/64RBMXCoSmsTc9oTU9ghAk/experiments/clerkless-auth
  useEffect(() => {
    // Avoid exposing the feature to users that are not signed in
    if (!isSignedIn) return;
    // Wait for Statsig to be ready with userID attached
    const context = statsigClient?.client?.getContext();
    const statsigUserId = context?.user?.userID;
    if (statsigClient?.client?.loadingStatus !== 'Ready' || !statsigUserId)
      return;

    const isClerklessAuthEnabled = statsigClient
      .getLayer('auth-layer')
      .get('is_clerkless_auth_enabled');

    // Avoid running this logic multiple times
    if (hasRunRef.current) return;
    hasRunRef.current = true;

    const doUpgradeAuth = async () => {
      const sessionToken = await getToken();
      if (!sessionToken) {
        throw new Error('No session token found for user ' + statsigUserId);
      }
      // This is a bit early but logging events is asynchronous
      // and we want to give it some time to post.
      logWebUserEvent({
        actionName: 'AuthUpgraded',
      });
      await upgradeAuth(sessionToken);
      setCookie('suno_auth', process.env.NEXT_PUBLIC_AUTH_PUBLISHABLE_KEY, {
        path: '/',
        maxAge: 365 * 24 * 60 * 60, // 365 days in seconds
        sameSite: 'lax',
      });
    };

    // User is in Clerkless Auth experiment and not already upgraded
    if (isClerklessAuthEnabled && !sunoAuthCookie) {
      doUpgradeAuth().then(
        () => {
          window.location.reload();
        },
        (error) => {
          logWebUserEvent({
            actionName: 'AuthUpgradeFailed',
            context: {
              errorName: error.name || 'Unknown Error',
              errorMessage: error.message || '',
            },
          });
        }
      );
      // User is upgraded and need to be rolled back
    } else if (!isClerklessAuthEnabled && sunoAuthCookie) {
      removeCookie('suno_auth', { path: '/' });
      logWebUserEvent({
        actionName: 'AuthDowngraded',
      });
      // Sign out of Clerkless
      signOut(() => {
        window.location.reload();
      });
    }
  }, [
    statsigClient,
    isSignedIn,
    getToken,
    signOut,
    sunoAuthCookie,
    setCookie,
    removeCookie,
  ]);

  const { session, playbar } = useStores();

  const [loadingLink, setLoadingLink] = useState(true);
  const pathname = usePathname();
  const params = useParams();
  const searchParams = useSearchParams();

  // SUNO hiring advert!
  useEffect(() => {
    const hiringAdvert = `
  ███████╗██╗   ██╗███╗   ██╗ ██████╗
  ██╔════╝██║   ██║████╗  ██║██╔═══██╗
  ███████╗██║   ██║██╔██╗ ██║██║   ██║
  ╚════██║██║   ██║██║╚██╗██║██║   ██║
  ███████║╚██████╔╝██║ ╚████║╚██████╔╝
  ╚══════╝ ╚═════╝ ╚═╝  ╚═══╝ ╚═════╝
  We are hiring! Come join our amazing team!
  https://suno.com/careers
      `;

    const fancyCSS =
      'color: #ff6b9d; font-weight: bold; text-shadow: 0 0 10px rgba(255, 107, 157, 0.5), 0 0 20px rgba(255, 107, 157, 0.3), 0 0 30px rgba(255, 107, 157, 0.2); font-family: "Courier New", monospace;';

    console.log('%c' + hiringAdvert, fancyCSS);
  }, []);

  useEffect(() => {
    if (
      window.crossOriginIsolated &&
      !isCrossOriginIsolatedRoute(pathname) &&
      !searchParams.get(CROSS_ORIGIN_DEISOLATION_REFRESH_PARAM)
    ) {
      sessionStorage.setItem('crossOriginRefreshTime', Date.now().toString());
      const newParams = new URLSearchParams(searchParams);
      newParams.set(CROSS_ORIGIN_DEISOLATION_REFRESH_PARAM, '1');
      window.location.href = `${window.location.href}?${newParams.toString()}`;
    }
  }, [pathname, searchParams]);

  /**
   * Bootstrap experiments that we want to resolve up-front rather than when
   * it is actually accessed in the feature
   */
  useExperiment({
    layerName: 'revenue-layer',
    parameterName: DOWNLOAD_UPGRADE_EXPERIMENT_NAME,
    gatingFlagName: 'download-upgrade',
  });

  const isClient = useIsClient();
  const isBreakpointLg = useBreakpointLg();
  const isMobile = !useBreakpointMd();

  const { previewClip, clipForSongRecs, allowFlushToTop } = usePreviewContext();

  /**
   * Bootstrap various background tasks
   */
  useNavigationTracker(); // for playback events metadata
  useSharedContentTracker();
  useShareTracking();
  useUpsells();
  useNotifications();
  useSubscriptionInfo();
  useFeedbackForm();
  usePollRunningGens();
  usePinnedClipsInitialize();
  useArtistProfileInitialize();
  useRemixPermissionModal();
  useTranslationDetection((fromLanguage, toLanguage) => {
    logWebUserEvent({
      actionName: 'PageTranslated',
      context: {
        fromLanguage,
        toLanguage,
      },
    });
  });

  const hooksEnabled =
    useGateValue('web-hooks-2025') && isVideoHooksPath(pathname);

  // Basic sidebar/mobile nav setup
  let showLeftSidebar = !explicitHideSidebars;
  let showRightSidebar =
    typeof explicitHideSidebars === 'boolean'
      ? isClient && !explicitHideSidebars
      : isBreakpointLg && !hooksEnabled;
  let showMobileNav = !explicitHideMobileNav && isClient && isMobile;

  // Toggle sidebars for special cases
  const isMarketingHomePath =
    pathname === '/home' || pathname.startsWith('/home/');
  const isLibraryV2Path = pathname.startsWith('/me/v2');
  const isCreatePath = pathname.startsWith('/create');
  const isOAuthConsentPath = pathname.startsWith('/link-account');
  const isLegacyEditFlow = pathname.startsWith('/edit-legacy/');
  const isChatPath = pathname.startsWith('/chat');
  const isStudioOrEditV3 =
    pathname === '/studio' ||
    pathname.startsWith('/studio/') ||
    pathname.startsWith('/edit-v3/') ||
    pathname.startsWith('/edit/');
  const isLiveRadio = isLiveRadioPath(pathname);
  const isLabelMakerPath = pathname.startsWith('/listen-and-rank');
  const isMarketplacePath = pathname.startsWith('/marketplace');
  const isSunoCollabsPath = pathname.startsWith('/collab');
  const isSunoContestPath = pathname.startsWith('/contest');
  const isHomePath = pathname.startsWith('/home');
  const isVideoGenPath = pathname.startsWith('/b-side/video-gen');
  const isAuthPath =
    pathname.startsWith('/auth') ||
    pathname.startsWith('/sign-in') ||
    pathname.startsWith('/sign-up');
  const isSongifyPath = pathname.startsWith('/songify');
  if (isOAuthConsentPath || isAuthPath) {
    showLeftSidebar = false;
    showRightSidebar = false;
    showMobileNav = false;
  } else if (
    isCreatePath ||
    isLibraryV2Path ||
    isChatPath ||
    isLiveRadio ||
    playbar.isLivingRadioMode ||
    isLabelMakerPath ||
    isLegacyEditFlow ||
    isMarketplacePath
  ) {
    showRightSidebar = false;
  } else if (isStudioOrEditV3) {
    showLeftSidebar = false;
    showRightSidebar = false;
    showMobileNav = false;
  } else if (isSunoCollabsPath) {
    showRightSidebar = false;
    showLeftSidebar = false;
    showMobileNav = false;
  } else if (isSunoContestPath) {
    showRightSidebar = false;
    showLeftSidebar = false;
    showMobileNav = false;
  } else if (isSongifyPath) {
    showRightSidebar = false;
  }
  const isStudioWaitlistPath = pathname.startsWith('/studio-waitlist');
  const isStudioLandingPagePath = pathname.startsWith('/studio-welcome');

  const { openModal, isModalOpen } = useModalContext();

  /**
   * Mobile create drawer
   */
  const [isDrawerOpen, setDrawerOpen] = useState(false);
  const handleOpenDrawer = useCallback(() => {
    setDrawerOpen(true);
  }, []);
  const handleCloseDrawer = useCallback(() => {
    setDrawerOpen(false);
  }, []);

  /**
   * AppsFlyer mobile web redirect state and logic
   */
  const isAFEnabled =
    isClient &&
    !!window.AF_SMART_SCRIPT &&
    !!window.AF_SMART_SCRIPT.generateOneLinkURL;

  const afOneLinkUrl = useMemo(() => {
    if (!isAFEnabled) return '';
    if (pathname.startsWith('/song/')) {
      return getOneLinkUrl({
        contentType: 'song',
        contentId: params.slug as string,
      });
    }
    return '';
  }, [isAFEnabled, pathname, params.slug]);

  useEffect(() => {
    if (!isAFEnabled && isIOS()) {
      // Wait for the smart script to load
      const timer = setTimeout(() => {
        setLoadingLink(false);
      }, 500);
      return () => clearTimeout(timer);
    } else {
      // Set loading to false immediately for other cases
      setLoadingLink(false);
    }
  }, [isAFEnabled, afOneLinkUrl]);

  // Show V2 mobile song page only for logged in users with feature flag enabled on mobile
  const shouldShowV2MobileSongPage =
    useGateValue('logged-in-song-page-v2') &&
    isMobile &&
    pathname.startsWith('/song/') &&
    isSignedIn;

  // Show logged-out mobile song page for logged out users on mobile
  const shouldShowLoggedOutMobileSongPage =
    isMobile && pathname.startsWith('/song/') && !isSignedIn;

  /**
   * Playbar
   */
  const isPlaybarHidden =
    (!playbar.clip && isMobile) ||
    isMarketingHomePath ||
    isStudioOrEditV3 ||
    isLegacyEditFlow ||
    isLiveRadio ||
    isOAuthConsentPath ||
    shouldShowV2MobileSongPage ||
    shouldShowLoggedOutMobileSongPage ||
    hooksEnabled ||
    isLabelMakerPath ||
    isMarketplacePath ||
    isStudioWaitlistPath ||
    isStudioLandingPagePath ||
    isSunoCollabsPath ||
    isSunoContestPath ||
    isVideoGenPath ||
    isAuthPath ||
    isSongifyPath ||
    isHomePath;

  const isRegularPlaybarHidden =
    isPlaybarHidden ||
    isLiveRadio ||
    playbar.isLivingRadioMode ||
    (isMobile && isModalOpen(ModalTypes.CANCEL_SUBSCRIPTION));

  const isLivingRadioPlaybarHidden =
    isPlaybarHidden || !playbar.isLivingRadioMode;

  const showMobileBanner = !isIOS() && !isOAuthConsentPath && !isAuthPath;

  return (
    <>
      {(pathname === '/studio' || pathname.startsWith('/studio/')) && (
        <StudioLoadingOverlay />
      )}
      <PlaybarAudioElements />
      {isMobile && (
        <>
          {!loadingLink &&
            (afOneLinkUrl && isIOS() && !shouldShowV2MobileSongPage ? (
              <MobileWebRedirect oneLinkUrl={afOneLinkUrl} />
            ) : (
              showMobileBanner && (
                <MobileBanner
                  supportedBrowser={supportedBrowser}
                  supportedCountries={supportedCountriesForMobileBanner}
                />
              )
            ))}
          {showMobileNav && (
            <MobileTopBar enableMobileSongPageV2={shouldShowV2MobileSongPage} />
          )}
        </>
      )}
      <div
        className={clsx(
          '@container flex w-full flex-col bg-background-primary md:h-full',
          { 'h-full': hooksEnabled }
        )}
      >
        <LiveRadioAudioBus />
        <div className='flex w-full flex-1 flex-col overflow-y-auto md:flex-row'>
          {!showLeftSidebar || isMobile ? null : <SideNav collapsible={true} />}
          <div className='relative flex flex-1 flex-col overflow-y-auto'>
            <div
              className={clsx(
                'relative flex w-full flex-1 overflow-x-hidden overflow-y-hidden',
                { '-mt-16': allowFlushToTop },
                'md:mt-0'
              )}
            >
              <VerticalSplitGroup
                visible={
                  !isMobile &&
                  showRightSidebar &&
                  (!!previewClip || !!clipForSongRecs)
                }
                className='z-10 w-full flex-1 overflow-hidden'
                barClassName='bg-background-secondary'
              >
                <div
                  className='flex min-h-svh w-full max-w-full flex-1 bg-background-primary md:min-h-full lg:min-w-[570px]'
                  style={{ position: 'relative' }}
                  id='main-container'
                >
                  {children}
                </div>
                {!showRightSidebar ? null : <RightSidebarContent />}
              </VerticalSplitGroup>
            </div>

            {!isMobile && (
              <>
                <Playbar
                  hidden={isRegularPlaybarHidden}
                  disableControls={isLiveRadio}
                />
                {!isLivingRadioPlaybarHidden && (
                  <RadioPlaybar stationId={STATION_ID} />
                )}
              </>
            )}
          </div>
        </div>
        {isMobile && isSignedIn ? (
          <MobileCreate
            isOpen={isDrawerOpen}
            onClose={handleCloseDrawer}
            onOpen={handleOpenDrawer}
          />
        ) : null}
        <div
          className={clsx({
            'sticky bottom-0 z-50 flex w-full flex-col': isMobile,
            'pointer-events-none opacity-0':
              isMobile && playbar.isMobileCommentsModalOpen,
          })}
        >
          {isMobile && (
            <>
              <Playbar
                hidden={isRegularPlaybarHidden}
                disableControls={isLiveRadio}
              />
              {!isLivingRadioPlaybarHidden && (
                <RadioPlaybar stationId={STATION_ID} />
              )}
            </>
          )}
          {showMobileNav && !shouldShowLoggedOutMobileSongPage && (
            <MobileNavNew
              onOpenCreate={handleOpenDrawer}
              onOpenFeedback={() => openModal(ModalTypes.FEEDBACK_FORM)}
              hideMobileTopBar={shouldShowV2MobileSongPage}
              enableMobileSongPageV2={shouldShowV2MobileSongPage}
            />
          )}
        </div>
        <MaintenanceBar />
        {/* Be very careful with any changes to where or how this component is loaded. See the comment at the top of Captcha.tsx. */}
        <Captcha wrapperClassName='pointer-events-none fixed -z-50 opacity-0' />
        <Ga4AnalyticsTracker session={session} />
        <AntiAbuseTracker />
        <AppModals />
        {session.flags?.['cleffy'] && <CleffyModal />}
      </div>
    </>
  );
});

const ClientLayoutAndFriends: React.FC<ClientLayoutProps> = (props) => (
  <>
    <SunoDevTools />
    <DialogModalContainer />
    <ToastContainer />
    <ClientLayout {...props} />
  </>
);

export default ClientLayoutAndFriends;
