import clsx from 'clsx';
import { usePathname } from 'next/navigation';
import { Dispatch, SetStateAction } from 'react';

import { useStores } from '@/app/(root)/AppProviders';
import Button, { ButtonShape, ButtonVariant } from '@/components/button/Button';
import {
  ContextMenuItem,
  ContextMenuTrigger,
} from '@/components/contextMenu/ContextMenu';
import ImageWithFallback from '@/components/image/ImageWithFallback';
import { toast } from '@/components/toast/Toast';
import { Tooltip } from '@/components/tooltip/Tooltip';
import { useContextSelector } from '@/hooks/useContextSelector';
import {
  CheckIcon,
  LinkIcon,
  PlusIcon,
  SidebarRightIcon,
  TriangleDownIcon,
  WorkspacesIcon,
} from '@/icons';
import logWebUserEvent from '@/logging/logWebUserEvent';

import AnimatedTabs, {
  Option,
} from '../create/createV2/componentsQ3/AnimatedTabs';
import { ModelMenuContents } from '../create/createV2/componentsQ3/CreateHeader';
import CreditsCounter from '../create/createV2/componentsQ3/CreditsCounter';
import { useModelUpsell } from '../create/createV2/componentsQ3/useModelUpsell';
import CreateFormContext from '../create/v2/CreateFormContext';
import { CreateModes } from '../create/v2/types';
import { ActiveUser } from './ChatClient';
import { orpheusVariants } from './constants';
import { useOrpheusExperimentGroup } from './hooks/useOrpheusExperimentGroup';
import { useChatMessagesStore } from './stores';
import { ChatSession, OrpheusExperimentGroup, Variant } from './types';
import { useChatContext } from './useChat';

type ChatTopBarProps<ModeType extends string> = {
  activeUsers?: ActiveUser[];
  readOnly?: boolean;
  modeOptions?: Option<ModeType>[];
  mode?: ModeType;
  setMode?: Dispatch<SetStateAction<ModeType>>;
  creditsRemaining?: number | null;
  onClickCredits?: () => void;
  creditsHref?: string;
  onOutOfCreditsClick?: () => void;
  sessionMetadata?: ChatSession;
};

export const NewSessionButton = () => {
  const { createChatSession } = useChatContext();

  return (
    <Button
      icon={PlusIcon}
      variant={ButtonVariant.Secondary}
      className='bg-background-transparent h-[40px] min-w-[40px] text-xs backdrop-blur-xs'
      shape={ButtonShape.Pill}
      onClick={async () => {
        await createChatSession();
      }}
    >
      New Chat
    </Button>
  );
};

export const ChatTopBar = <ModeType extends string>({
  activeUsers,
  modeOptions,
  mode,
  setMode,
  creditsRemaining,
  onClickCredits,
  creditsHref,
  onOutOfCreditsClick,
  sessionMetadata,
}: ChatTopBarProps<ModeType>) => {
  const { session } = useStores();
  const pathname = usePathname();
  const isChatPage = pathname?.startsWith('/chat');
  const modelUpsell = useModelUpsell();
  const { msgIds, loadedMessages } = useChatMessagesStore();
  const hasMessages = msgIds.length > 0 || (loadedMessages?.length ?? 0) > 0;
  const { experimentGroup } = useOrpheusExperimentGroup();

  const { isChatHistoryOpen, setIsChatHistoryOpen, currentSession } =
    useChatContext();

  const [modelType, setModelType] = useContextSelector(
    CreateFormContext,
    (context) => context.selectState<string>(['global', 'model'])
  );
  const modelTypeOptions = useContextSelector(
    CreateFormContext,
    (context) => context.modelTypeOptions
  );
  const model =
    modelTypeOptions.find((m) => m.external_key === modelType) ||
    modelTypeOptions[0];

  return (
    <div
      className={clsx(
        'absolute top-0 left-1/2 z-[0] flex h-16 w-full min-w-[700px] -translate-x-1/2 flex-row items-center justify-center border-b-[0.5px] border-white/10 bg-transparent backdrop-blur-xs'
      )}
    >
      <div className='absolute left-2 flex items-center gap-1 py-1'>
        {mode === CreateModes.CHAT &&
        experimentGroup === OrpheusExperimentGroup.B &&
        !isChatPage ? (
          <Button
            icon={WorkspacesIcon}
            className={clsx('h-[40px] w-[40px]', {
              'bg-background-transparent': !isChatHistoryOpen,
            })}
            shape={ButtonShape.Pill}
            variant={
              isChatHistoryOpen
                ? ButtonVariant.Primary
                : ButtonVariant.Secondary
            }
            onClick={() => {
              setIsChatHistoryOpen(!isChatHistoryOpen);
            }}
            aria-label='Toggle chat history'
            iconClassName='h-4 w-4'
          />
        ) : null}
        {creditsRemaining !== null && (
          <CreditsCounter
            creditsRemaining={creditsRemaining ?? 0}
            onClick={onClickCredits}
            href={creditsHref}
            onOutOfCreditsClick={onOutOfCreditsClick}
          />
        )}
      </div>
      {!!modeOptions?.length ? (
        <AnimatedTabs
          options={modeOptions}
          value={mode}
          onChange={(option) => {
            logWebUserEvent({
              actionName: 'OrpheusChatToggleClicked',
              context: {
                stateBefore: modeOptions[0]?.value === mode ? 'on' : 'off',
                stateAfter:
                  modeOptions[0]?.value === option.value ? 'on' : 'off',
              },
            });
            setMode?.(option.value);
          }}
        />
      ) : (
        <div className='flex flex-col items-center'>
          <span className='text-base font-medium'>
            {sessionMetadata?.name ?? currentSession?.name ?? 'New Chat'}
          </span>
          <span className='font-mono text-xs text-white/40'>
            {session.credits} Credits
          </span>
        </div>
      )}
      <div className='absolute right-2 flex items-center gap-1'>
        {(activeUsers ?? []).map((user: any, _: number) => (
          <div key={user.clientId} className='group relative backdrop-blur-xs'>
            <Tooltip
              label={
                user.data?.userHandle ? user.data.userHandle : 'Anonymous user'
              }
            >
              <div className='relative top-2 cursor-pointer transition-transform hover:scale-105'>
                {user.data?.userAvatar ? (
                  <ImageWithFallback
                    src={user.data.userAvatar}
                    alt={
                      user.data?.userHandle
                        ? user.data.userHandle
                        : 'User avatar'
                    }
                    className='h-6 w-6 rounded-full border border-border-primary'
                    fallbackSrc='https://cdn-o.suno.com/auras/Aura-01.png'
                  />
                ) : (
                  <div className='flex h-6 w-6 items-center justify-center rounded-full border border-border-primary bg-secondary'>
                    <span className='text-xs font-medium text-foreground-primary'>
                      {(user.data?.userHandle
                        ? user.data.userHandle
                        : 'A')[0].toUpperCase()}
                    </span>
                  </div>
                )}
                {/* Online indicator */}
                <div className='absolute -right-0.5 -bottom-0.5 h-2.5 w-2.5 rounded-full border border-background-primary bg-accent-green'></div>
              </div>
            </Tooltip>
          </div>
        ))}
        {(mode === CreateModes.CHAT || isChatPage) &&
        hasMessages &&
        !!currentSession?.session_id ? (
          <Button
            icon={LinkIcon}
            className='bg-background-transparent h-[40px] w-[40px]'
            shape={ButtonShape.Pill}
            variant={ButtonVariant.Secondary}
            aria-label={'Copy link to chat'}
            onClick={() => {
              const chatLink = `${window.location.origin}/chat/${currentSession?.session_id}`;
              navigator.clipboard.writeText(chatLink);
              toast({
                title: 'Link copied to clipboard',
                status: 'success',
              });
              logWebUserEvent(
                {
                  actionName: 'OrpheusChatLinkCopied',
                  context: {
                    sessionId: currentSession?.session_id,
                    chatLink,
                  },
                },
                session
              );
            }}
            iconClassName='h-4 w-4'
          />
        ) : null}
        {mode === CreateModes.CHAT &&
        experimentGroup === OrpheusExperimentGroup.A &&
        !isChatPage ? (
          <Button
            className={clsx('h-[40px] text-xs', {
              'bg-background-transparent': !isChatHistoryOpen,
            })}
            shape={ButtonShape.Pill}
            variant={
              isChatHistoryOpen
                ? ButtonVariant.Primary
                : ButtonVariant.Secondary
            }
            onClick={() => {
              setIsChatHistoryOpen(!isChatHistoryOpen);
            }}
            iconEnd={SidebarRightIcon}
          >
            Chats
          </Button>
        ) : null}
        {isChatPage ? null : (
          <ContextMenuTrigger
            placement='bottom-left'
            ButtonComponent={(props) => (
              <Button
                variant={ButtonVariant.Secondary}
                shape={ButtonShape.Pill}
                className='h-[40px] text-[12px]'
                {...props}
              >
                {model?.name}
                <TriangleDownIcon className='-ml-1 h-4 w-4' />
              </Button>
            )}
            ContentsComponent={() => (
              <ModelMenuContents
                options={modelTypeOptions}
                activeId={modelType}
                onSelect={(model) => {
                  const isUpsellTriggered = modelUpsell.checkForUpsell(
                    model.external_key
                  );
                  if (!isUpsellTriggered) {
                    setModelType(model.external_key);
                  }
                }}
              />
            )}
          />
        )}
      </div>
    </div>
  );
};

export const OrpheusVariantsMenu = () => {
  const { variant, setVariant } = useChatContext();
  return (
    <>
      {orpheusVariants.map((variantOpt: Variant) => (
        <ContextMenuItem
          key={variantOpt.id}
          onClick={() => {
            setVariant(variantOpt.id);
          }}
          icon={variant === variantOpt.id ? CheckIcon : undefined}
        >
          {variantOpt.name}
        </ContextMenuItem>
      ))}
    </>
  );
};
