/* eslint jsx-a11y/no-static-element-interactions: warn */

/* eslint jsx-a11y/no-noninteractive-tabindex: warn */
import { useOutsideClick } from '@chakra-ui/react';
import { useStatsigClient } from '@statsig/react-bindings';
import clsx from 'clsx';
import { observer } from 'mobx-react-lite';
import React, {
  KeyboardEvent,
  MouseEvent,
  useEffect,
  useRef,
  useState,
} from 'react';
import ReactDOM from 'react-dom';
import { twMerge } from 'tailwind-merge';

import { useStores } from '@/app/(root)/AppProviders';
import { ModalTypes } from '@/components/modal/constants/ModalTypes';
import Tag, { TagVariant } from '@/components/tag/Tag';
import useDisclosure from '@/hooks/useDisclosure';
import { CaretDownIcon, CheckIcon } from '@/icons';
import { components } from '@/lib/gen';
import logWebUserEvent from '@/logging/logWebUserEvent';
import { resolveModelName } from '@/state/clipStore';
import { GenerateFormStore } from '@/state/createStore';
import { FeatureKey } from '@/state/sessionStore';
import { ModelType } from '@/state/sessionStore';
import { DEFAULT_CROW_MODEL_NAME, DEFAULT_V3_MODEL_NAME } from '@/utils/utils';

// Extract the BadgeType from the generated types
type BadgeType = components['schemas']['BadgeType'];

interface ModelSelectProps {
  state: GenerateFormStore;
  forceModelKey?: string;
  allowedModelNames?: string[];
  openPosition?: 'top' | 'bottom';
  logContext?: {
    createVersion?: string;
    source?: string;
  };
  className?: string;
  wrapperClassName?: string;
  enableUpsell?: boolean;
}

const ModelSelect: React.FC<ModelSelectProps> = observer(
  ({
    state,
    forceModelKey,
    allowedModelNames,
    openPosition = 'bottom',
    logContext = {},
    className = '',
    wrapperClassName = '',
  }) => {
    const { session, clips, menus, genForm } = useStores();
    const { isOpen, onOpen, onClose } = useDisclosure();
    const dropdownRef = useRef<HTMLDivElement>(null);
    const buttonRef = useRef<HTMLDivElement>(null);
    const statsigClient = useStatsigClient();
    const viewableModels = session.getViewableModels();

    const allowedModels = allowedModelNames
      ? viewableModels.filter((model: ModelType) =>
          allowedModelNames?.includes(model.external_key || '')
        )
      : viewableModels;

    useOutsideClick({
      ref: dropdownRef as React.RefObject<HTMLDivElement>,
      handler: (e) => {
        if (!buttonRef.current?.contains(e.target as any)) {
          onClose();
        }
      },
    });

    const [localSelectedModel, setLocalSelectedModel] = useState(
      forceModelKey || resolveModelName(state, clips, false)
    );

    useEffect(() => {
      if (!viewableModels) {
        return;
      }

      const localModel = resolveModelName(state, clips, false);
      if (
        localModel !== localSelectedModel &&
        !forceModelKey &&
        !allowedModelNames
      ) {
        setLocalSelectedModel(localModel);
      } else if (allowedModelNames && allowedModelNames?.includes(state.mv)) {
        setLocalSelectedModel(state.mv);
      }
    }, [
      state.mv,
      state.continueClipId,
      state.personaClipId,
      localSelectedModel,
      viewableModels,
      session.experiments,
      forceModelKey,
      allowedModelNames,
    ]);

    useEffect(() => {
      if (forceModelKey) {
        setLocalSelectedModel(forceModelKey);
      } else if (
        allowedModels.length > 0 &&
        !allowedModels
          .map((m: ModelType) => m.external_key)
          .includes(localSelectedModel)
      ) {
        setLocalSelectedModel(
          allowedModels[0].external_key || DEFAULT_V3_MODEL_NAME
        );
      } else if (allowedModels.length === 0) {
        setLocalSelectedModel(DEFAULT_V3_MODEL_NAME);
      }
    }, [forceModelKey, allowedModels]);

    // Track when user sees crow model for the first time
    useEffect(() => {
      if (
        localSelectedModel === DEFAULT_CROW_MODEL_NAME &&
        !state.hasSeenCrow
      ) {
        state.hasSeenCrow = true;
      }
    }, [localSelectedModel, state.hasSeenCrow]);

    const handleModelSelect = (
      modelKey: any,
      event: MouseEvent | KeyboardEvent
    ) => {
      const previousModelKey = state.mvUserPreference;
      event.preventDefault();
      event.stopPropagation();
      if (session.flags?.['session-all-models']) {
        const canUseCrow = viewableModels.find((m) =>
          m.external_key.includes('crow')
        )?.can_use;
        const canUseBluejay = viewableModels.find((m) =>
          m.external_key.includes('bluejay')
        )?.can_use;
        const canUseAuk = viewableModels.find((m) =>
          m.external_key.includes('auk')
        )?.can_use;
        const canUseV4 = viewableModels.find((m) =>
          m.external_key.includes('v4')
        )?.can_use;
        if (!canUseCrow && modelKey.includes('crow')) {
          genForm.shouldOpenMobileCreate = false;
          menus.setCurrentUpsellFeature(FeatureKey.UPGRADE_LATEST_MODEL);
          menus.openModal(ModalTypes.UPSELL_MODAL);
        } else if (!canUseBluejay && modelKey.includes('bluejay')) {
          genForm.shouldOpenMobileCreate = false;
          menus.setCurrentUpsellFeature(FeatureKey.UPGRADE_LATEST_MODEL);
          menus.openModal(ModalTypes.UPSELL_MODAL);
        } else if (
          !canUseAuk &&
          modelKey.includes('auk') &&
          !modelKey.includes('turbo')
        ) {
          genForm.shouldOpenMobileCreate = false;
          menus.setCurrentUpsellFeature(FeatureKey.UPGRADE_LATEST_MODEL);
          menus.openModal(ModalTypes.UPSELL_MODAL);
        } else if (!canUseV4 && modelKey.includes('v4')) {
          menus.setCurrentUpsellFeature(FeatureKey.UPGRADE_LATEST_MODEL);
          menus.openModal(ModalTypes.UPSELL_MODAL);
        } else {
          setLocalSelectedModel(modelKey);
          state.setMvUserPreference(modelKey);
        }
      } else {
        setLocalSelectedModel(modelKey);
        state.setMvUserPreference(modelKey);
      }

      onClose();
      logWebUserEvent({
        actionName: 'ChangeAudioModel',
        context: {
          ...logContext,
          modelBefore: previousModelKey,
          modelAfter: modelKey,
        },
      });
    };

    const handleToggle = () => {
      if (isOpen && !forceModelKey) {
        onClose();
      } else {
        onOpen();
      }
    };

    const rect = buttonRef.current?.getBoundingClientRect();
    let leftPosition = rect
      ? rect.left + (typeof window !== 'undefined' ? window?.scrollX : 0)
      : 0;
    const dropdownWidth = 192;
    const screenWidth = typeof window !== 'undefined' ? window?.innerWidth : 0;
    if (leftPosition + dropdownWidth > screenWidth) {
      leftPosition = screenWidth - dropdownWidth;
    }
    const position = {
      top: rect ? rect.bottom + window.scrollY : 0,
      left: leftPosition,
    };

    return (
      <div
        className={twMerge(
          'relative flex flex-row-reverse text-left font-sans',
          wrapperClassName
        )}
      >
        <div
          aria-label='Model Select Dropdown'
          tabIndex={0}
          className={twMerge(
            'inline-flex items-center gap-2 rounded-full px-3 py-2',
            'bg-background-secondary text-foreground-primary hover:bg-background-tertiary',
            'text-sm font-medium',
            'cursor-pointer select-none',
            `z-[100000]`,
            (
              viewableModels.find((m) => m.external_key === localSelectedModel)
                ?.external_key || ''
            ).indexOf('bluejay') !== -1
              ? 'text-accent-pink-on-primary'
              : '',
            className
          )}
          ref={buttonRef}
          onClick={(e: MouseEvent) => {
            e.preventDefault();
            e.stopPropagation();
            handleToggle();
          }}
          onKeyDown={(e: KeyboardEvent) => {
            if (e.key === 'Enter') {
              e.preventDefault();
              e.stopPropagation();
              handleToggle();
            } else if (e.key === 'Tab' && isOpen) {
              e.preventDefault();
              e.stopPropagation();
              const firstFocusElement = dropdownRef.current?.querySelectorAll(
                '[tabindex]:not([tabindex="-1"]'
              );
              if (firstFocusElement && firstFocusElement[0]) {
                (firstFocusElement[0] as HTMLDivElement).focus();
              }
            } else if (e.key === 'Escape' && isOpen) {
              e.preventDefault();
              e.stopPropagation();
              handleToggle();
            }
          }}
        >
          <span className='line-clamp-1 break-all'>
            {viewableModels.find((m) => m.external_key === localSelectedModel)
              ?.name || 'v3.5'}
          </span>
          {!forceModelKey ? <CaretDownIcon className='h-4 w-4' /> : null}
        </div>
        {isOpen &&
          !forceModelKey &&
          ReactDOM.createPortal(
            <div
              className='prevent-modal-close absolute z-10000 mt-2 h-60 w-48 overflow-y-auto rounded-md border border-background-primary bg-background-tertiary shadow-lg'
              style={
                openPosition === 'bottom'
                  ? { top: position.top, left: position.left }
                  : { top: position.top - 280, left: position.left }
              }
              ref={dropdownRef}
            >
              <div className='py-1'>
                {allowedModels.map((model) => {
                  const isBluejay = model.external_key.includes('bluejay');
                  return !!model.model_subtype ? null : (
                    <div
                      tabIndex={0}
                      aria-label={`Model Selection: ${model.name}`}
                      key={model.external_key}
                      className='flex cursor-pointer items-center justify-between px-3 py-1 text-sm text-foreground-secondary hover:bg-background-glass-thin'
                      onClick={(e) => handleModelSelect(model.external_key, e)}
                      onKeyDown={(e: KeyboardEvent) => {
                        if (e.key === 'Enter') {
                          handleModelSelect(model.external_key, e);
                        }
                      }}
                    >
                      <div>
                        <div
                          className={clsx('text-md font-sans font-medium', {
                            'text-foreground-primary': !isBluejay,
                            'text-accent-pink-on-primary': isBluejay,
                          })}
                        >
                          <div className='mb-1 flex flex-row items-center'>
                            <div>{model.name}</div>
                            {statsigClient?.checkGate('auk-go-live') && (
                              <div className='ml-1.5 flex flex-row items-center gap-1'>
                                {model.badges?.includes(
                                  'beta' as BadgeType
                                ) && <Tag variant={TagVariant.Beta}>Beta</Tag>}
                                {model.badges?.includes('pro' as BadgeType) && (
                                  <Tag variant={TagVariant.Pro}>Pro</Tag>
                                )}
                              </div>
                            )}
                          </div>
                        </div>
                        <div className='pr-2 font-sans text-sm text-foreground-tertiary'>
                          {model.description}
                        </div>
                      </div>
                      {model.external_key === localSelectedModel && (
                        <div>
                          <CheckIcon className='h-5 w-5 text-foreground-secondary' />
                        </div>
                      )}
                    </div>
                  );
                })}
              </div>
            </div>,
            document.body
          )}
      </div>
    );
  }
);

export default ModelSelect;
