'use client';

import { useAuth } from '@clerk/nextjs';
import clsx from 'clsx';
import React from 'react';

import Button, {
  ButtonShape,
  ButtonSize,
  ButtonVariant,
} from '@/components/button/Button';
import AnimatedLogo from '@/components/image/AnimatedLogo';
import AnimatedStripeBackground from '@/components/studioWaitlist/components/Background';
import { useClickToFocus } from '@/components/studioWaitlist/hooks/useClickToFocus';
import { toast } from '@/components/toast/Toast';
import logWebUserEvent from '@/logging/logWebUserEvent';

import InfoPage from './InfoPage';
import { ButtonRow, SegmentsBar } from './components/';
import Footer from './components/Footer';
import GradientHoleOverlay from './components/GradientHoleOverlay';
import HeaderBar from './components/HeaderBar';
import LoggedInBadge from './components/LoggedInBadge';
import { SlideFlowProvider, useSlideFlowContext } from './components/slideFlow';
import { HEADER_PADDING, PAGE_PAD_X } from './constants';
import { useInviteCode } from './hooks/useInviteCode';
import {
  IntroSlide,
  JoinWaitlistButton,
  createDoneSlide,
  createInviteCodeSlide,
  createSurveyQuestionSlide,
} from './slides';
import type { LightProps, StudioWaitlistState } from './types';
import { SlideFlowStatus } from './types';

// Header Component
function Header({ light = false }: LightProps) {
  return (
    <HeaderBar
      color={light ? '#FAF7F5' : '#101012'} // same color transition behavior
      paddingClass={HEADER_PADDING}
      maxWidthClass=''
      left={
        <a
          href={'/studio-waitlist'}
          aria-label='Home'
          className='cursor-pointer'
          onClick={(e) => {
            e.preventDefault();
            window.location.reload();
          }}
        >
          <div className='flex w-full items-center gap-2'>
            <AnimatedLogo className='pointer-events-auto h-[18px] w-auto flex-shrink-0' />
            <span
              className='text-[24px] leading-none font-bold transition-colors delay-200 duration-[1000ms] ease-out'
              style={{ color: light ? '#FAF7F5' : '#101012' }}
            >
              Studio
            </span>
          </div>
        </a>
      }
      right={
        <>
          {/* shows only when the user is logged-in */}
          <LoggedInBadge light={light} />

          <Button
            variant={ButtonVariant.DarkPrimary}
            size={ButtonSize.Medium}
            shape={ButtonShape.Pill}
            aria-label='Info'
            className='h-[56px]'
            onClick={() => {
              document
                .getElementById('info')
                ?.scrollIntoView({ behavior: 'smooth' });
            }}
          >
            Info
          </Button>
        </>
      }
    />
  );
}

// FooterBar Component
function FooterBar({ light = false }: LightProps) {
  return (
    <Footer
      className={clsx(PAGE_PAD_X, 'mt-auto')}
      textColor={light ? '#FAF7F5' : 'rgba(16, 16, 18, 0.5)'}
      animateColorTransition
    />
  );
}

// New simplified SlideWizard that uses context
function SlideWizard({
  onExpandMask,
  getEmail,
  setEmail,
}: {
  onExpandMask: () => void;
  getEmail: () => string;
  setEmail: (email: string) => void;
}) {
  const flow = useSlideFlowContext();

  // Use the flow methods and state
  const active = flow.currentIndex;
  const { isLoaded } = useAuth();

  // Public focus target (hidden input) that slides can register
  const publicInputRef = React.useRef<
    HTMLInputElement | HTMLTextAreaElement | null
  >(null);

  // Handle auth button click - now just calls the hook method
  const handleAuthButtonClick = React.useCallback(() => {
    logWebUserEvent({
      actionName: 'SignInButtonClicked',
    });
    flow.openAuthModal();
  }, [flow]);

  const registerFocusTarget = React.useCallback(
    (
      ref: React.RefObject<HTMLInputElement | HTMLTextAreaElement | null> | null
    ) => {
      publicInputRef.current = ref?.current ?? null;
    },
    []
  );

  // Only enable outer click-to-focus on email/invite slides
  const wantsOuterClickFocus =
    flow.slides.length > 0 &&
    active < flow.slides.length &&
    (flow.slides[active]?.id === 'email' ||
      flow.slides[active]?.id === 'invite-code');
  const outerClickToFocus = useClickToFocus(publicInputRef, {
    excludeSelectors: ['button', '[role="tab"]', 'a[href]'],
    enabled: wantsOuterClickFocus,
  });

  // Waitlist submission is now handled automatically by useSlideFlow

  // Guard: slides may be empty while survey questions load
  if (flow.slides.length === 0) {
    return null;
  }

  const currentSlide = flow.slides[active];
  if (!currentSlide) return null;

  // Create context that includes navigation and mask expansion
  const ctx: StudioWaitlistState = {
    goNext: flow.goNext,
    goPrev: flow.goPrev,
    goTo: flow.goTo,
    totalSlides: flow.slides.length,
    currentIndex: active,
    expandMask: onExpandMask,
    getEmail,
    setEmail,
    isAuthSlideNext: () => {
      const nextIndex = active + 1;
      return (
        nextIndex < flow.slides.length && flow.slides[nextIndex].id === 'done'
      );
    },
    registerFocusTarget,
    setField: flow.setField,
    getField: flow.getField,
    status: flow.status,
    updateStatus: flow.updateStatus,
    waitlistRank: flow.waitlistRank,
    waitlistSize: flow.waitlistSize,
    waitlistResponseLoaded: flow.waitlistResponseLoaded,
    getCachedInviteCode: flow.getCachedInviteCode,
    setCachedInviteCode: flow.setCachedInviteCode,
    openAuthModal: flow.openAuthModal,
    skipToLastSlide: flow.skipToLastSlide,
    getAuthButtonText: flow.getAuthButtonText,
    hasStudioAccess: flow.hasStudioAccess,
    isRedeemingCode: flow.isRedeemingCode,
  };

  // Use slide's shouldShowSegments function
  const shouldShowSegments = currentSlide.shouldShowSegments?.(ctx) ?? false;

  // Calculate segments from slides that should show segments
  const segmentSlides = flow.slides.filter(
    (slide: any) => slide.shouldShowSegments?.(ctx) ?? false
  );
  const segmentCount = segmentSlides.length;
  const activeSegment = segmentSlides.findIndex(
    (slide: any) => slide.id === currentSlide.id
  );

  return (
    <section
      className={clsx('flex min-h-0 w-full flex-1 flex-col', PAGE_PAD_X)}
    >
      <div
        className={clsx(
          // gradient & sizing
          'relative z-20 h-full w-full flex-1 cursor-text rounded-[120px]',
          'px-[16px] py-8 md:aspect-auto lg:px-[116px] lg:py-12',
          'flex min-h-0 flex-col'
        )}
        data-hole-target
        onPointerDownCapture={
          wantsOuterClickFocus ? outerClickToFocus : undefined
        }
        tabIndex={-1}
      >
        {/* Segments bar - always render for layout, transparent when not needed */}
        {segmentCount > 0 && activeSegment >= 0 ? (
          <SegmentsBar
            total={segmentCount}
            active={activeSegment}
            onSelect={(i) => {
              const targetSlide = segmentSlides[i];
              if (targetSlide) {
                const targetIndex = flow.slides.findIndex(
                  (slide: any) => slide.id === targetSlide.id
                );
                if (targetIndex >= 0) {
                  flow.goTo(targetIndex);
                }
              }
            }}
            className={clsx(
              'flex h-[20px] flex-shrink-0 items-center self-center lg:h-[56px]',
              !shouldShowSegments && 'pointer-events-none opacity-0'
            )}
          />
        ) : (
          // Placeholder div to maintain layout when no segments
          <div className='h-[56px] flex-shrink-0' />
        )}

        {/* Content area */}
        <div className='flex min-h-0 flex-1 flex-col justify-center overflow-hidden'>
          {currentSlide.renderContent(ctx)}
        </div>

        {/* Footer – sticks to bottom within padding */}
        <div className='mt-auto flex-shrink-0'>
          {ctx.isAuthSlideNext() ? (
            <ButtonRow>
              <JoinWaitlistButton
                className='h-14 w-[140px] justify-center bg-white/90 whitespace-nowrap disabled:opacity-40 disabled:brightness-100'
                onClick={handleAuthButtonClick}
                disabled={!isLoaded || flow.isRedeemingCode}
              >
                {flow.getAuthButtonText()}
              </JoinWaitlistButton>
            </ButtonRow>
          ) : (
            currentSlide.renderButtons(ctx)
          )}
        </div>
      </div>
    </section>
  );
}

const WaitlistPageContent = () => {
  const { isSignedIn } = useAuth();

  const [email, setEmail] = React.useState('');
  const { code: inviteCode } = useInviteCode();
  const hasInviteCode = !!inviteCode;

  const inviteCodeSlide = React.useMemo(() => createInviteCodeSlide(), []);
  const doneSlide = React.useMemo(() => createDoneSlide(), []);

  const onSubmitError = React.useCallback((_error: any) => {
    toast({
      title: 'Failed to join waitlist',
      description: 'Please try again.',
      status: 'error',
      duration: 4000,
      isClosable: true,
    });
  }, []);

  const slideFlowConfig = {
    hasInviteCode,
    surveyGroupId: 'studio_waitlist',
    surveySlideFactory: createSurveyQuestionSlide,
    introSlide: IntroSlide,
    inviteCodeSlide,
    doneSlide,

    // Waitlist submission
    submitEndpoint: '/api/studio/join-waitlist',
    onSubmitError,

    // Invite code caching
    inviteCodeStorageKey: 'studio-waitlist-invite-code',
  };

  return (
    <SlideFlowProvider config={slideFlowConfig}>
      <WaitlistPageUI
        email={email}
        setEmail={setEmail}
        isSignedIn={isSignedIn ?? false}
      />
    </SlideFlowProvider>
  );
};

// Internal component that uses the context
const WaitlistPageUI = ({
  email,
  setEmail,
  isSignedIn: _isSignedIn,
}: {
  email: string;
  setEmail: (email: string) => void;
  isSignedIn: boolean;
}) => {
  const flow = useSlideFlowContext();

  /* ──────────────────────────────────────────────────────────────── *
   *  Deep-link guard — if the initial URL has "#info" we delay the
   *  first visible paint until:
   *     1) slide-flow is ready  → we have the DOM
   *     2) we've scrolled to #info → nothing above flashes
   *  Everything is rendered but hidden (visibility:hidden) so the
   *  anchor exists for `scrollIntoView`.
   * ──────────────────────────────────────────────────────────────── */
  const infoDeepLink =
    typeof window !== 'undefined' && window.location.hash === '#info';
  const [showPage, setShowPage] = React.useState(!infoDeepLink);

  React.useEffect(() => {
    if (!infoDeepLink || !flow.ready || showPage) return;

    // Wait one frame so the DOM is committed, then jump to #info
    requestAnimationFrame(() => {
      document.getElementById('info')?.scrollIntoView({ behavior: 'auto' });
      // …and on the next frame we allow the page to be shown.
      requestAnimationFrame(() => setShowPage(true));
    });
  }, [infoDeepLink, flow.ready, showPage]);

  /* ── status-derived flags ─────────────── */
  const maskShown = flow.status >= SlideFlowStatus.MASK_SHOWN;

  const [fadeLight, setFadeLight] = React.useState(maskShown);
  const [maskExpanded, setMaskExpanded] = React.useState(maskShown);
  const [shouldExpandMask, setShouldExpandMask] = React.useState(maskShown);
  const [_shouldAnimateColor, setShouldAnimateColor] = React.useState(
    flow.status < SlideFlowStatus.TRANSITION_DONE
  );

  const handleExpandMask = React.useCallback(() => {
    if (!shouldExpandMask && !maskExpanded) {
      setFadeLight(true);
      setShouldExpandMask(true);
      flow.updateStatus(SlideFlowStatus.MASK_SHOWN);
    }
  }, [shouldExpandMask, maskExpanded, flow]);

  const handleAnimationComplete = React.useCallback(() => {
    setMaskExpanded(true);
    flow.updateStatus(SlideFlowStatus.TRANSITION_DONE);
    setShouldAnimateColor(false);
  }, [flow]);

  // No URL-coupled slide index; start from in-app state only.

  React.useEffect(() => {
    if (flow.slides.length === 0) return;
    const rafId = requestAnimationFrame(() => {
      window.dispatchEvent(new Event('resize'));
    });
    return () => cancelAnimationFrame(rafId);
  }, [flow.slides.length]);

  /* ------------------------------------------------------------------ *
   *  Guard 1 – Background and layout should always be mounted to prevent
   *            disappearing. Only hide the slide content until ready.
   * ------------------------------------------------------------------ */

  /* 2.  Keep the page hidden until we've scrolled to #info */
  const pageVisibility = showPage ? 'visible' : 'hidden';

  return (
    <main className='w-full' style={{ visibility: pageVisibility }}>
      {/* Global caret blink keyframes for custom caret */}
      <style>{`
        @media (prefers-reduced-motion: no-preference) {
          @keyframes cci-blink {
            0%, 55%, 100% { opacity: 1; }
            30%           { opacity: 0; }
          }
        }
        :root { --app-pad-x: 2rem; }
        @media (min-width: 640px) { :root { --app-pad-x: 2.5rem; } }
        @media (min-width: 768px) { :root { --app-pad-x: 116px; } }

        @media (prefers-reduced-motion: reduce) {
          .cci-caret { animation: none !important; }
        }

        /* Make logo darker */
        .cl-logoImage {
          filter: brightness(0.2) !important;
        }

        /* Dark social buttons */
        .cl-socialButtonsIconButton {
          background-color: #1f2937 !important;
          border: 1px solid #374151 !important;
          color: #ffffff !important;
        }

        .cl-socialButtonsIconButton:hover {
          background-color: #374151 !important;
          border-color: #4b5563 !important;
        }
      `}</style>
      <section
        id='waitlist'
        className='relative flex h-screen flex-col overflow-hidden'
      >
        <AnimatedStripeBackground className='pointer-events-none absolute inset-0 z-0' />
        {/* ---------------------------------------------------------------- *
         *  Keep overlay mounted to prevent white flash on re-mount.
         *  Once expanded, it's transparent and costs nothing to keep.
         * ---------------------------------------------------------------- */}
        <div
          className='pointer-events-none absolute inset-0'
          style={{
            /* Extend slightly beyond the visible viewport so the mask covers the
               iOS bottom address bar / home-indicator area. The negative bottom
               offset is ignored by non-iOS browsers. */
            bottom: 'calc(-1 * env(safe-area-inset-bottom))',
            /* fade the canvas out once it has fully expanded */
            opacity: maskExpanded ? 0 : 1,
            transition: 'opacity .35s linear',
          }}
        >
          <GradientHoleOverlay
            expanded={shouldExpandMask}
            onAnimationComplete={handleAnimationComplete}
          />
        </div>
        <Header light={fadeLight} />
        <div className='flex min-h-0 flex-1 flex-col'>
          {flow.ready && flow.slides.length > 0 && (
            <SlideWizard
              onExpandMask={handleExpandMask}
              getEmail={() => email}
              setEmail={setEmail}
            />
          )}
        </div>
        <FooterBar light={fadeLight} />
      </section>
      <section id='info' className='relative z-10 min-h-screen w-full'>
        <InfoPage
          hideWaitlistButton={flow.slides[flow.currentIndex]?.id === 'done'}
        />
      </section>
    </main>
  );
};

export default function JoinWaitlistPage() {
  const { isLoaded: authLoaded } = useAuth();

  if (!authLoaded) {
    return (
      <main className='w-full'>
        <section
          id='waitlist'
          className='relative flex h-screen flex-col items-center justify-center overflow-hidden'
          style={{ backgroundColor: '#FAF7F5' }}
        >
          <AnimatedLogo className='h-8 w-auto' />
        </section>
      </main>
    );
  }

  return <WaitlistPageContent />;
}
