'use client';

import { ThemeProvider } from '@emotion/react';
import styled from '@emotion/styled';
import { useStatsigClient } from '@statsig/react-bindings';
import { observer } from 'mobx-react-lite';
import { redirect, useSearchParams } from 'next/navigation';
import { useCallback, useEffect, useRef, useState } from 'react';
import storageAvailable from 'storage-available';

import { useStores } from '@/app/(root)/AppProviders';
import WorkspaceClipBrowser from '@/components/clipBrowser/WorkspaceClipBrowser';
import { getWorkspaceDefaultClipBrowserFilters } from '@/components/clipBrowser/defaultClipBrowserFilters';
import { ClipBrowserFilters } from '@/components/clipBrowser/types';
import { ClipBrowserContextProvider } from '@/components/clipBrowser/useClipBrowser';
import FocusedObjectPanel from '@/components/focusedObjectPanel/FocusedObjectPanel';
import WelcomeModal from '@/components/modal/WelcomeModal';
import { ModalTypes } from '@/components/modal/constants/ModalTypes';
import {
  Divider,
  HorizontalPanelGroup,
  Panel,
} from '@/components/panelSystem/PanelSystem';
import { ModelDownsampleWarning } from '@/components/section/ModelDownsampleWarning';
import { NarrowGapVerticalDivider } from '@/components/studio/StudioPanelUtilities';
import makePanelSize from '@/components/studio/makePanelSize';
import SpinnerSVG from '@/components/svg/SpinnerSVG';
import useBreakpoint, { useBreakpointMd } from '@/hooks/useBreakpoint';
import { useContextSelector } from '@/hooks/useContextSelector';
import usePageViewLog from '@/hooks/usePageViewLog';
import { useQueueFocusSync } from '@/hooks/useQueueFocusSync';
import { FeatureKey, FeatureUpsellConfig } from '@/state/sessionStore';
import { DEFAULT_PROJECT_ID } from '@/utils/constants';
import { UNDERLYING_PLAN_KEY } from '@/utils/session';

import { ActiveUser, ChatClient } from '../../chat/ChatClient';
import { ChatTopBar } from '../../chat/ChatTopBar';
import { OrpheusAblyProvider } from '../../chat/OrpheusAblyProvider';
import { ReferenceType } from '../../chat/components/input/ReferenceTypes';
import { useOrpheusExperimentGroup } from '../../chat/hooks/useOrpheusExperimentGroup';
import { ChatSession, OrpheusExperimentGroup } from '../../chat/types';
import { OrpheusChatProvider, useChat } from '../../chat/useChat';
import { Option } from '../createV2/componentsQ3/AnimatedTabs';
import CreateFileDropReceiver from '../createV2/componentsQ3/CreateFileDropReceiver';
import CreateForm from '../createV2/componentsQ3/CreateForm';
import { standardTheme } from '../createV2/componentsQ3/themes';
import CreateFormContext from './CreateFormContext';
import { CreateModes } from './types';
import { useCurrentWorkspace } from './useCurrentWorkspace';
import { FocusedObjectContext, useFocusedObject } from './useFocusedObject';
import { useMatrixParams } from './useMatrixParams';
import { usePostSubscriptionModelOverride } from './usePostSubscriptionModelOverride';
import { usePrompts } from './usePrompts';
import { useSuggestedTags } from './useSuggestedTags';

const Wrapper = styled.div`
  width: 100%;
  max-height: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
`;

const InnerContent = styled.div`
  flex-grow: 1;
  flex-shrink: 1;
  flex-basis: 0%;
  position: relative;
`;

const CreateWrapper = styled.div<{
  active: boolean;
  isTopBarEnabled: boolean;
}>`
  position: absolute;
  top: ${({ isTopBarEnabled }) => (isTopBarEnabled ? '64px' : '0')};
  bottom: 0;
  width: 100%;
  transition-property: opacity;
  transition-duration: 300ms;
  transition-timing-function: ease-in-out;
  opacity: ${({ active }) => (active ? 1 : 0)};
  visibility: ${({ active }) => (active ? 'visible' : 'hidden')};
`;

const createModeOptions: Option<CreateModes>[] = [
  { label: 'Chat', value: CreateModes.CHAT },
  { label: 'Custom', value: CreateModes.CUSTOM },
];

const WORKSPACE_REFETCH_THRESHOLD_MS = 1000;

const CreateV2ClientInner = observer(() => {
  const { session, menus, project } = useStores();
  const statsigClient = useStatsigClient();
  const isMobile = !useBreakpointMd();
  const rightPanelRef = useRef<any>(undefined);
  const wrapperRef = useRef<any>(undefined);
  const [activeUsers, setActiveUsers] = useState<ActiveUser[]>([]);
  const [showWelcomeModal, setShowWelcomeModal] = useState<boolean>(false);
  const lastSeenWorkspaceIdRef = useRef<string | null>(null);

  // Add state to force re-render when wrapper width changes
  const [, forceUpdate] = useState({});

  // Update global welcome modal state when local state changes
  useEffect(() => {
    session.setWelcomeModalOpen(showWelcomeModal);
  }, [showWelcomeModal, session]);

  const model = useContextSelector(
    CreateFormContext,
    (context) => context.state.global.model
  );

  const [mode, setMode] = useContextSelector(CreateFormContext, (context) =>
    context.selectState<CreateModes>(['global', 'mode'])
  );

  const creditsRemaining = useContextSelector(
    CreateFormContext,
    (context) => context.creditsRemaining
  );

  usePrompts();
  useSuggestedTags();
  useMatrixParams();
  usePageViewLog({ actionName: 'PageViewed', componentContext: 'create' });
  // Check if user just subscribed. If so, set the model to latest model.
  const searchParams = useSearchParams();
  usePostSubscriptionModelOverride(searchParams);

  useEffect(() => {
    if (rightPanelRef.current && storageAvailable('localStorage')) {
      const rightPanelWidth = localStorage.getItem('right-panel-width');
      rightPanelRef.current.style.width = `${rightPanelWidth}px`;
    }
  }, [rightPanelRef.current, session.flags]);

  useEffect(() => {
    if (statsigClient?.client?.loadingStatus === 'Ready') {
      if (
        session.sessionIsLoaded &&
        session.isSubLoaded &&
        !menus.featureUpsellConfig
      ) {
        const config = statsigClient.getDynamicConfig('feature_upsell_configs');
        const configContent = config.value as unknown as FeatureUpsellConfig;
        const filteredConfigContent = Object.fromEntries(
          Object.entries(configContent).filter(([_, feature]) => {
            return !feature.required_plans.includes(
              UNDERLYING_PLAN_KEY[
                session.sub.plan?.plan_key as keyof typeof UNDERLYING_PLAN_KEY
              ]
            );
          })
        );
        menus.setFeatureUpsellConfig(filteredConfigContent);
      }
    }
  }, [
    statsigClient,
    statsigClient?.client?.loadingStatus,
    session.sessionIsLoaded,
    session.isSubLoaded,
    session.sub.plan?.plan_key,
  ]);

  useEffect(() => {
    if (
      statsigClient.checkGate('new-user-welcome-onboarding') &&
      !session.shownCreateOnboarding &&
      session.roles?.['is_day_zero_user']
    ) {
      setShowWelcomeModal(true);
    }
  }, [session, session.shownCreateOnboarding, statsigClient]);

  const focusedObjectContext = useFocusedObject();
  const isWideEnoughForPanel = useBreakpoint(1400);

  // Sync playbar queue state with focused object
  useQueueFocusSync(focusedObjectContext);

  // Add ResizeObserver to watch wrapperRef width changes
  useEffect(() => {
    if (!wrapperRef.current) return;

    const resizeObserver = new ResizeObserver(() => {
      // Force a re-render when the wrapper width changes
      forceUpdate({});
    });

    resizeObserver.observe(wrapperRef.current);

    return () => {
      resizeObserver.disconnect();
    };
  }, []);

  const userId = session.user?.id;
  const workspaceId = useCurrentWorkspace();

  const {
    isControlGroup: isChatExpControlGroup,
    isLoading: isChatExpLoading,
    experimentGroup,
  } = useOrpheusExperimentGroup();
  const isChatExpEnabled = !isChatExpControlGroup;
  const orpheusChatState = useChat(!!isChatExpEnabled && !isMobile);

  const getDefaultFilters = useCallback(
    () =>
      userId && workspaceId
        ? getWorkspaceDefaultClipBrowserFilters(userId, workspaceId)
        : null,
    [userId, workspaceId]
  );

  useEffect(() => {
    const syncWithSearchParams = async () => {
      if (searchParams.get('mode') === 'chat' && isChatExpEnabled) {
        setMode(CreateModes.CHAT);
        const url = new URL(window.location.href);
        if (
          searchParams.get('ref_id') &&
          searchParams.get('ref_type') === 'clip'
        ) {
          await orpheusChatState.createChatSession();
          orpheusChatState.addReference({
            clipId: searchParams.get('ref_id')!,
            type: ReferenceType.CLIP,
          });
          url.searchParams.delete('ref_id');
          url.searchParams.delete('ref_type');
        }
        url.searchParams.delete('mode');
        window.history.replaceState(
          {},
          '',
          `${window.location.pathname}?${url.searchParams.toString()}`
        );
      }
    };
    syncWithSearchParams();
  }, [searchParams, isChatExpEnabled, orpheusChatState]);

  useEffect(() => {
    if (searchParams.get('upgrade_for_studio') && session?.isSubLoaded) {
      menus.setCurrentUpsellFeature(FeatureKey.STUDIO);
      menus.openModal(ModalTypes.UPSELL_MODAL);
      const url = new URL(window.location.href);
      url.searchParams.delete('upgrade_for_studio');

      window.history.replaceState(
        {},
        '',
        `${window.location.pathname}?${url.searchParams.toString()}`
      );
    }
  }, [searchParams, session?.isSubLoaded, session.flags?.['studio']]);

  useEffect(() => {
    if (!!session.flags && !isChatExpEnabled && mode === CreateModes.CHAT) {
      setMode(CreateModes.SIMPLE);
    } else if (isChatExpEnabled && mode === CreateModes.SIMPLE) {
      setMode(CreateModes.CHAT);
    }
  }, [isMobile, session.flags, mode, setMode]);

  if (!userId || !workspaceId) {
    return null;
  }

  useEffect(() => {
    if (
      mode !== CreateModes.CHAT ||
      !orpheusChatState.isSessionsDataLoaded ||
      !isChatExpEnabled ||
      (orpheusChatState.createdSessionWorkspaceIds.has(
        project.currentProjectId
      ) &&
        orpheusChatState.isCreatingNewSession &&
        orpheusChatState.workspaceRefetchedAt <
          Date.now() - WORKSPACE_REFETCH_THRESHOLD_MS)
    ) {
      if (
        orpheusChatState.isCreatingNewSession &&
        orpheusChatState.createdSessionWorkspaceIds.has(
          project.currentProjectId
        )
      ) {
        orpheusChatState.setIsCreatingNewSession(false);
      }
      return;
    }
    const previousWorkspaceId = lastSeenWorkspaceIdRef.current;
    lastSeenWorkspaceIdRef.current = project.currentProjectId;

    const TEN_MINUTES_MS = 600000;
    const prompt = localStorage.getItem('prompt') || '';
    const promptSavedAt = localStorage.getItem('prompt_saved_at');
    const promptSource = localStorage.getItem('prompt_source');

    if (
      prompt &&
      Date.now() - (parseInt(promptSavedAt || '') || 0) < TEN_MINUTES_MS &&
      promptSource === 'quickbox'
    ) {
      if (isChatExpEnabled && mode !== CreateModes.CHAT) {
        setMode(CreateModes.CHAT);
      }
      return;
    }

    if (previousWorkspaceId === null && storageAvailable('localStorage')) {
      const sessionLastTouched = localStorage.getItem(
        `orpheus_session_last_touched:${session?.userId}`
      );
      const lastWorkspaceStored = localStorage.getItem(
        `orpheus_last_workspace_id:${session?.userId}`
      );
      const lastTouchedMs = parseInt(sessionLastTouched ?? '');
      if (
        isNaN(lastTouchedMs) ||
        Date.now() - lastTouchedMs > TEN_MINUTES_MS ||
        project.currentProjectId !== lastWorkspaceStored
      ) {
        orpheusChatState.createChatSession();
        orpheusChatState.setIsChatHistoryOpen(true);
        return;
      }
    }

    const sessionsForWorkspaces = orpheusChatState.sessions
      .filter(
        (session: ChatSession) =>
          session.workspace_id === project.currentProjectId
      )
      .sort((a, b) => a.created_at - b.created_at);
    if (
      sessionsForWorkspaces.length > 0 &&
      project.currentProjectId !== DEFAULT_PROJECT_ID
    ) {
      const sessionForWorkspace = sessionsForWorkspaces[0];
      if (sessionForWorkspace?.session_id) {
        if (sessionForWorkspace?.session_id !== orpheusChatState.chatUUID) {
          orpheusChatState.setChatUUID(sessionForWorkspace.session_id);
          orpheusChatState.fetchChatHistory(
            sessionForWorkspace.session_id,
            project.currentProjectId
          );
        }
        return;
      }
    }
    if (project.currentProjectId !== DEFAULT_PROJECT_ID) {
      orpheusChatState.createChatSession(project.currentProjectId);
    } else {
      orpheusChatState.createChatSession();
    }
  }, [
    mode,
    project.currentProjectId,
    orpheusChatState.isSessionsDataLoaded,
    orpheusChatState.workspaceRefetchedAt,
  ]);

  if (isChatExpLoading) {
    return (
      <div className='flex h-full w-full items-center justify-center'>
        <SpinnerSVG />
      </div>
    );
  }

  return (
    <ThemeProvider theme={standardTheme}>
      <FocusedObjectContext.Provider value={focusedObjectContext}>
        <ClipBrowserContextProvider
          // should return correct type if userId and workspaceId are set.
          getDefaultFilters={getDefaultFilters as () => ClipBrowserFilters}
        >
          <OrpheusChatProvider value={orpheusChatState}>
            <Wrapper ref={wrapperRef}>
              <InnerContent>
                {isChatExpEnabled && !isMobile ? (
                  <ChatTopBar
                    activeUsers={activeUsers}
                    mode={mode}
                    setMode={setMode}
                    modeOptions={createModeOptions}
                    creditsRemaining={creditsRemaining}
                  />
                ) : null}
                <CreateFileDropReceiver>
                  <CreateWrapper
                    active
                    isTopBarEnabled={!isMobile && !!isChatExpEnabled}
                  >
                    <HorizontalPanelGroup>
                      {!isMobile ? (
                        <>
                          <Panel
                            size={
                              mode === CreateModes.CHAT &&
                              experimentGroup === OrpheusExperimentGroup.B &&
                              orpheusChatState.isChatHistoryOpen
                                ? makePanelSize(400, 'px')
                                : makePanelSize(0, 'px')
                            }
                            minSizePx={
                              isMobile
                                ? undefined
                                : mode === CreateModes.CHAT &&
                                    experimentGroup ===
                                      OrpheusExperimentGroup.B &&
                                    orpheusChatState.isChatHistoryOpen
                                  ? 400
                                  : 0
                            }
                          >
                            <div className='flex h-full flex-col overflow-y-hidden'>
                              <WorkspaceClipBrowser forceShowWorkspaceList />
                            </div>
                          </Panel>
                          <Divider
                            influence={
                              mode === CreateModes.CHAT &&
                              experimentGroup === OrpheusExperimentGroup.B &&
                              orpheusChatState.isChatHistoryOpen
                                ? 'both'
                                : 'neither'
                            }
                          >
                            <NarrowGapVerticalDivider
                              style={{
                                backgroundColor: 'var(--color-border-primary)',
                                width:
                                  mode === CreateModes.CHAT &&
                                  experimentGroup ===
                                    OrpheusExperimentGroup.B &&
                                  orpheusChatState.isChatHistoryOpen
                                    ? 1
                                    : 0,
                              }}
                            />
                          </Divider>
                          <Panel
                            size={
                              mode === CreateModes.CHAT
                                ? experimentGroup === OrpheusExperimentGroup.B
                                  ? makePanelSize(1, 'fr')
                                  : !orpheusChatState.isChatHistoryOpen
                                    ? makePanelSize(
                                        Math.max(
                                          (wrapperRef.current?.offsetWidth ??
                                            0) -
                                            (focusedObjectContext.focusedObject
                                              ? 320
                                              : 0),
                                          368
                                        ),
                                        'px'
                                      )
                                    : makePanelSize(
                                        Math.max(
                                          (wrapperRef.current?.offsetWidth ??
                                            0) -
                                            400 -
                                            (focusedObjectContext.focusedObject
                                              ? 320
                                              : 0),
                                          368
                                        ),
                                        'px'
                                      )
                                : makePanelSize(
                                    Math.min(window.innerWidth, 450),
                                    'px'
                                  )
                            }
                            minSizePx={368}
                          >
                            {mode === CreateModes.CHAT && isChatExpEnabled ? (
                              <OrpheusAblyProvider>
                                <ChatClient
                                  model={model}
                                  setActiveUsers={setActiveUsers}
                                />
                              </OrpheusAblyProvider>
                            ) : (
                              <CreateForm
                                showModeSwitcher={!isChatExpEnabled}
                              />
                            )}
                          </Panel>
                          <Divider
                            influence={
                              mode === CreateModes.CHAT &&
                              (!orpheusChatState.isChatHistoryOpen ||
                                experimentGroup === OrpheusExperimentGroup.B)
                                ? 'neither'
                                : 'both'
                            }
                          >
                            <NarrowGapVerticalDivider
                              style={{
                                backgroundColor: 'var(--color-border-primary)',
                                width:
                                  mode === CreateModes.CHAT &&
                                  (!orpheusChatState.isChatHistoryOpen ||
                                    experimentGroup ===
                                      OrpheusExperimentGroup.B)
                                    ? 0
                                    : 1,
                              }}
                            />
                          </Divider>
                        </>
                      ) : null}

                      <Panel
                        size={
                          mode === CreateModes.CHAT &&
                          (!orpheusChatState.isChatHistoryOpen ||
                            experimentGroup === OrpheusExperimentGroup.B) &&
                          !isMobile
                            ? makePanelSize(0, 'fr')
                            : makePanelSize(1, 'fr')
                        }
                        minSizePx={
                          isMobile
                            ? undefined
                            : mode === CreateModes.CHAT &&
                                (!orpheusChatState.isChatHistoryOpen ||
                                  experimentGroup === OrpheusExperimentGroup.B)
                              ? 0
                              : 400
                        }
                      >
                        <div className='flex h-full flex-col overflow-y-hidden'>
                          <WorkspaceClipBrowser />
                        </div>
                      </Panel>

                      {!isMobile ? (
                        <Panel
                          size={
                            focusedObjectContext.focusedObject &&
                            isWideEnoughForPanel
                              ? makePanelSize(316, 'px')
                              : makePanelSize(0, 'px')
                          }
                          minSizePx={316}
                        >
                          <div className='h-full pt-4 pr-4 pb-0'>
                            <FocusedObjectPanel />
                          </div>
                        </Panel>
                      ) : null}
                    </HorizontalPanelGroup>
                  </CreateWrapper>
                </CreateFileDropReceiver>
              </InnerContent>
            </Wrapper>
          </OrpheusChatProvider>
        </ClipBrowserContextProvider>
      </FocusedObjectContext.Provider>
      <ModelDownsampleWarning />
      {showWelcomeModal && (
        <WelcomeModal
          isOpen={showWelcomeModal}
          onClose={() => {
            setShowWelcomeModal(false);
            session.updateShownCreateOnboarding();
          }}
        />
      )}
    </ThemeProvider>
  );
});

const CreateV2Client = observer(() => {
  const { session } = useStores();

  const flagState = session.flags && Boolean(session.flags['create-v2-page']);

  if (flagState === false) {
    redirect('/create');
  } else if (flagState !== true) {
    return null;
  } else {
    return <CreateV2ClientInner />;
  }
});

export default CreateV2Client;
