import { ChatElementDisplayLocation } from 'src/application/models/chatElementDisplayLocation';
import { ColorMapping, ColorNames, colorVar } from 'src/application/models/colorsConfig';
import { FeatureGates } from 'src/application/models/featureGates';
import { CustomerServiceIntegrationMode, CustomerServiceType } from 'src/types/customerService';
import { GridInsertionType } from 'src/merchants/gridInsertion';
import { DOMInsertionType } from 'src/merchants/domInsertion';

import type {
  PageVisitCategory,
  SupportedEventProductCategory,
} from '@spiffy-ai/commerce-api-client';
import { ChatState } from 'src/types/custservice-types';
import { SuggestionBarLocationForMetrics } from 'src/types/suggestionBarV2-types';
import { TestProps } from 'src/types/test-types';
import { OrgConfigFeatureGate } from 'src/application/models/api/orgConfigResults';
import { WidgetConfigV3, WidgetTypeV3 } from './typesV3';
import type { HardcopyResponse } from './hardcopyContext/hardcopyContext';

type ShowFloatingButtonOptions =
  | 'always'
  | 'after-interaction-on-mobile-always-desktop'
  | 'after-interaction-anywhere'
  | 'never';

type FloatingEntryPointConfig = {
  position: 'bottom-left' | 'middle-left' | 'middle-right' | 'bottom-right';
  expansionText?: {
    pdp: string;
    plp: string;
  };
  minimizedColor: string;
  expandedColor: string;
  textColor?: string;
  showOption: ShowFloatingButtonOptions;
  iconSVGSrc?: string;
  iconSize?: number;
  iconStrokeColor?: string;
  iconFillColor?: string;
  height?: number;
  fontSize?: number;
};

type WelcomeSectionVariant = 'standard' | 'outlined';

type WelcomeSectionColorVariant = 'standard' | 'accent' | 'brand' | 'light';

type WelcomeSectionConfig = {
  variant: WelcomeSectionVariant;
  colorVariant?: WelcomeSectionColorVariant;
  title?: string;
  subtitle?: string;
  // icon?: React.FunctionComponent<React.SVGProps<SVGSVGElement>>;
  /* Serializable icon name that maps to a React component. Preferred over icon for database storage. */
  iconName?: string;
  imageSrc?: string;
};

type ChatPreviewConfig = {
  variant: 'flat' | 'filled' | 'outlined';
  largeProductComparison?: boolean;
  filledBackgroundColor: string;
  iconFillColor: string;
  buttonTextColor?: string;
  buttonTextSecondaryColor?: string;
  buttonTextHoverColor?: string;
  buttonBackgroundColor: string;
  buttonBackgroundHoverColor: string;
  buttonBorderColor?: string;
  buttonBorderHoverColor?: string;
  copies: { pdp: string[]; plp: string[] };
  staticSuggestionCopies?: { pdp: string[]; plp: string[] };
  staticPLPImages?: string[];
  footerConfig?: ChatPreviewFooterConfig;
  headerConfig?: ChatPreviewHeaderConfig;
  topMargin?: number;
};

type ChatPreviewHeaderConfig = {
  title?: string;
  imageSrc?: string;
  imageHeight?: number;
  sparklesColor?: string; // used by: spanx, uniqueVintage, dreamlandBaby
  fontSize?: string;
  iconWidth?: string;
  iconHeight?: string;
};

interface ChatPreviewFooterConfig {
  hasFade?: boolean; // used by: spanx, uniqueVintage
  suggestionButtonVariant?: 'dark' | 'light' | 'outlined';
  suggestionsBackground?: string; // used by: carbahn
  replyButtonIcon?: 'send' | 'magnifyingGlass' | 'thinMagnifyingGlass' | 'searchIcon';
  replyButtonText?: string;
  replyInputHasShadow?: boolean; // used by: spanx
  replyInputHasBorder?: boolean; // used by: spanx
  backgroundColor?: string; // used by spanx, tushbaby, will need custom CSS when switching over
}

type ProductReviewStyleVariant = 'standard' | 'bordered';

type ProductReviewColorVariant = 'neutral' | 'brand' | 'premium';

interface ProductReviewConfig {
  styleVariant: ProductReviewStyleVariant;
  colorVariant: ProductReviewColorVariant;
  verifiedBuyerTitle: string;
  incentivizedReviewFlag?: boolean;
}

type PageCardVariant = 'filled' | 'outlined' | 'minimal';

type PageCardHoverVariant = 'none' | 'shadow' | 'lift';

type PageCardIconVariant = 'primary' | 'accent' | 'background' | 'none';

type PageCardConfig = {
  variant: PageCardVariant;
  hoverVariant: PageCardHoverVariant;
  iconVariant: PageCardIconVariant;
};

type ProductCardVariant = 'filled' | 'bordered' | 'minimal' | 'transparentBordered';

type ProductCardHoverVariant = 'backgroundDark' | 'none';

type ProductCardLayoutVariant = 'normal' | 'tall' | 'square';

interface ProductCardConfig {
  variant: ProductCardVariant;
  hoverVariant: ProductCardHoverVariant;
  layoutVariant: ProductCardLayoutVariant;
  pricePrefix?: string;
}

type CSSwitchConfig = {
  variant: 'attached' | 'detached';
  backgroundColor: string;
  borderColor: string;
  selectedTextColor: string;
  selectedBackgroundColor?: string;
  unselectedTextColor: string;
  unselectedBackgroundColor?: string;
  supportTitle?: string;
  spiffyTitle?: string;
  spiffyTitleHasLogo?: boolean;
};

type ChatHeaderConfig = {
  collapsedColor: string;
  expandedColor: string;
  chevronColor: string;
  imageSrc?: string;
  icon?: React.FunctionComponent<React.SVGProps<SVGSVGElement>>;
  closeIcon?: React.FunctionComponent<React.SVGProps<SVGSVGElement>>;
  borderBottom?: string;
  headerBarHeightPartialView: number;
  headerBarHeightFullView: number;
  customerSupportSwitchConfig?: CSSwitchConfig;
};

type SimpleCustomerServiceIntegration = {
  integrationMode: CustomerServiceIntegrationMode;
  provider: CustomerServiceType;
  useUnifiedButton?: boolean;
  maxfileUploadSize?: number;
};

type FullCustomerServiceIntegration = {
  integrationMode: CustomerServiceIntegrationMode;
  provider: CustomerServiceType;
  useUnifiedButton?: boolean;
  chatEnabledDuringBusinessHours?: boolean;
  showNameInput?: boolean;
  formAiName?: string;
  welcomeTitle: string;
  welcomeDescription: string;
  showWelcomeOnForm?: boolean;
  contactSubjectOptions?: string[];
  getCustomWaitingMessage?: (name?: string) => string;
  withinBusinessHoursMessage?: string;
  withinBusinessHoursWaitingMessage?: string;
  outsideBusinessHoursMessage?: string;
  outsideBusinessHoursWaitingMessage?: string;
  withinBusinessHoursFormMessage?: string;
  outsideBusinessHoursFormMessage?: string;
  suggestedAIQuestions?: string[];
  businessHoursPolling?: number;
  maxfileUploadSize?: number;

  /**
   * @deprecated This is handled by the BE.
   */
  businessHoursStartUTC?: string;
  /**
   * @deprecated This is handled by the BE.
   */
  businessHoursEndUTC?: string;
  /**
   * @deprecated This is handled by the BE.
   */
  businessHoursTimezone?: string;

  showAISuggestionsWithinBusinessHours?: boolean;
  waitingMessagePosition?: 'BEFORE_MESSAGES' | 'AFTER_MESSAGES';
  legalMessage?: string;
  withinBusinessHoursInitialState?: ChatState;
  outsideBusinessHoursInitialState?: ChatState;
  withinBusinessHoursButtontext?: string;
  outsideBusinessHoursButtontext?: string;
  reopenChatMessage: string;
};

type CustomerServiceIntegration = SimpleCustomerServiceIntegration | FullCustomerServiceIntegration;

type ConversationalSeach = {
  enabled?: boolean;
  replyInput?: ReplyInputConfig;
  suggestions?: string[];
  entrypointBgColor?: string;
  entrypointTextColor?: string;
  entrypointBtnColor?: string;
  entrypointBtnTextColor?: string;
  entrypointBtnBorderColor?: string;
  entrypointContainer?: string;
  entrypointTrigger?: string;
  productGridContainer?: string;
  generalSearchBtn?: string;
  pageContent?: string;
  searchContent?: string;
  sortingTitle?: string;
  selectionTitle?: string;
  sortingFont?: string;
  optionsFont?: string;
  sortingButtonText?: string;
};

type ChatMessageVariant = 'standard' | 'premium' | 'accent';

interface ChatMessageConfig {
  assistantChatTitle: string;
  variant: ChatMessageVariant;
  productLink: {
    variant: ProductLinkVariant;
    hoverVariant: ProductLinkHoverVariant;
    iconVariant: ProductLinkIconVariant;
  };
}

interface ReplyInputConfig {
  // TODO consider making this a number
  size?: 'md' | 'lg';
  sendIcon: 'arrowUp' | 'send' | 'search';
  placeholder?: string;
}

interface PartialViewConfig {
  // maximum height of the partial view as a percentage of the screen height
  maxHeight: number;
  borderRadius?: string;
}

type ProductLinkIconVariant =
  | 'accentPrimary'
  | 'backgroundPrimary'
  | 'backgroundPrimaryDark'
  | 'borderLight'
  | 'backgroundSaturated';

type ProductLinkVariant = 'textLink';

type ProductLinkHoverVariant = 'backgroundDark';

type SearchCardVariant =
  | 'backgroundPrimary'
  | 'backgroundSecondary'
  | 'backgroundSecondaryDark'
  | 'backgroundLight'
  | 'backgroundSaturated';

type SuggestionButtonVariant =
  | 'outlined'
  | 'outlinedLight'
  | 'primary'
  | 'secondary'
  | 'tertiary'
  | 'dark'
  | 'darkAccent'
  | 'darkPrimary'
  | 'secondaryDark'
  | 'secondaryAccent'
  | 'transparent'
  | 'transparentDark'
  | 'lightDark';

interface SuggestionButtonConfig {
  variant?: SuggestionButtonVariant;
  hoverVariant?: SuggestionButtonVariant;
  answerVariant?: SuggestionButtonVariant;
  borderRadius?: 'sm' | 'md' | 'lg';
}

type NumRows = 'default' | 'alwaysOneRow' | 'alwaysTwoRows' | 'twoRowsOnMobile';

interface AlphabeticFilterSorting {
  type: 'alphabetic';
}
interface ProductCountFilterSorting {
  type: 'productCount';
}
interface CustomFilterSorting {
  type: 'custom';
  map: Record<string, number>;
}

type FilterSorting = AlphabeticFilterSorting | ProductCountFilterSorting | CustomFilterSorting;

interface BaseFilterConfig {
  filterId: string;
  displayName: string;
}
interface DynamicFilterConfig extends BaseFilterConfig {
  type: 'dynamic';
  attribute: string;
  sorting: FilterSorting;
}

interface PriceFilterConfig extends BaseFilterConfig {
  type: 'price';
  bucketSize: number;
}

export type FilterAttribute = DynamicFilterConfig | PriceFilterConfig;

export type SearchZeroStateVariant = 'backgroundTertiary' | 'backgroundDark' | 'backgroundPrimary';
export type SearchZeroStateLayout = 'input' | 'icon';

export type SearchInputVariant = 'standard';

export type SearchIconVariant = 'thin' | 'bold';

export type SearchFilterSidebarVariant = 'darkButton' | 'lightButton';

export type ProductGridVariant = 'standard' | 'square';

type UserQueryButtonIcon =
  | 'magnifyingGlass'
  | 'send'
  | 'magnifyingGlassThin'
  | 'sendArrow'
  | 'searchIcon';

interface UserQueryButtonConfig {
  variant?: 'box' | 'underlineLight' | 'underlineDark';
  placeholderText?: string;
  icon: UserQueryButtonIcon;
}

// TODO: this should be included in the top-level widget config
interface TermsAndConditionsConfig {
  copy: string;
  link: string;
  linkText: string;
}

interface MerchantVariantSettings {
  dynamicVariants: {
    enabled: boolean; // This feature will enable dynamic variants for the merchant. Useful for SPA's
    refreshInterval?: number; // The interval in milliseconds to check for changes in the URL
  };
}

interface FloatingChatConfig {
  enableWatermark: boolean;
  userQueryInputEnabled: boolean;
  ignoreFirstModelResponse?: boolean;
  neverShowSingleProductCards?: boolean;
  termsAndConditionsConfig?: TermsAndConditionsConfig;

  // Footer config
  suggestionButtonConfig?: SuggestionButtonConfig;
  replyInputConfig: ReplyInputConfig;
}

interface SearchConfig {
  enableGlobalSearch: boolean;
  searchFilterConfig: FilterAttribute[];
  searchOverlayHeading?: string;
  redirectSearchResultsUrl?: string;
  additiveDynamicFilters?: boolean;
  recommendedProducts?: string[];
  recommendedProductsHeading?: string;
}

type ConfigVersion = 'v3' | 'deprecated' | undefined;

type OrgUIConfig = {
  version?: ConfigVersion;
  shortName: string;
  id?: string;
  floatingEntrypointConfig?: FloatingEntryPointConfig;
  // Deprecated - remove with ChatPreview rewrite
  chatPreviewConfig?: ChatPreviewConfig;

  customerServiceIntegration: CustomerServiceIntegration;
  // Deprecated - remove when Global Search is fully launched
  conversationalSearch?: ConversationalSeach;

  merchantOverrideCss?: string;

  // Deprecated TODO: Remove this deprecated value when Groove CX has proper unified button support
  // selectors for elements that should be hidden when the chat is open
  // e.g. CS widgets with max z-index ("div[id*='cs-container']")
  hiddenElementSelectors?: string[];

  merchantVariantSettings?: MerchantVariantSettings;
  // TODO: Migrate all floating chat config into this top-level key
  //
  floatingChatConfig: FloatingChatConfig;

  // Contain all search config here
  searchConfig: SearchConfig;
  // TODO: Move these into FloatingChatConfig
  // Chat Header related values
  chatHeader: ChatHeaderConfig;
  stickyAgentSwitchSuggestion?: boolean;
  partialViewConfig: PartialViewConfig;
  welcomeSectionConfig?: WelcomeSectionConfig;
  // Different response values
  productCardConfig?: ProductCardConfig;
  productReviewConfig?: ProductReviewConfig;
  pageCardConfig?: PageCardConfig;
  chatMessageConfig: ChatMessageConfig;
};

type InsertionPoint = {
  selector: string;
  // this is the index of the target element, 0 if missing
  selectionIndex?: number;
  insertionType: DOMInsertionType;
};

type URLTest = 'shopify' | 'null';

type IdExtractor =
  | 'shopify-product-id'
  | 'shopify-collection-id'
  | 'shopify-product-variant-id'
  | 'url-resolver-product-id'
  | 'url-resolver-plp-id'
  | 'null';

// This contains a map between PageVisitCategory and a list of URL's that are classified as the value
enum CategoryExtractorType {
  VisitCategoryMap = 'VisitCategoryMap',
  VisitCategoryDefault = 'VisitCategoryDefault',
}

interface BaseCategoryExtractor<T extends CategoryExtractorType> {
  type: T;
}

// This map betweens a category and a list of url patterns
interface VisitCategoryMap extends BaseCategoryExtractor<CategoryExtractorType.VisitCategoryMap> {
  map: {
    [key in PageVisitCategory]?: string[];
  };
}

// This will return a hard-coded default PageVisitCategory. It is intended to be used by fallback page types
interface VisitCategoryDefault extends BaseCategoryExtractor<CategoryExtractorType.VisitCategoryDefault> {
  value: PageVisitCategory;
}

type CategoryExtractor = VisitCategoryMap | VisitCategoryDefault;

type WrappingElement = {
  className: string;
  element: string;
  insertionType: DOMInsertionType;
};

enum PageVariantTestType {
  PageCategory = 'PageCategory',
  CatalogCategory = 'CatalogCategory',
  TopCatalogCategory = 'TopCatalogCategory',
  HasReviews = 'HasReviews',
  InCollection = 'InCollection',
  HasMerchantTag = 'HasMerchantTag',
  FeatureGate = 'FeatureGate',
  PlpId = 'PlpId',
  QueryParam = 'QueryParam',
  ProductId = 'ProductId',
  UserHasInteracted = 'UserHasInteracted',
  UserHasNotInteracted = 'UserHasNotInteracted',
  isLoading = 'isLoading',
  isProductComparison = 'isProductComparison',
  Fallback = 'Fallback',
  UrlResolver = 'UrlResolver',
  isScreenWidthSmaller = 'isScreenWidthSmaller',
  Null = 'null',
}

interface BasePageVariantTest<T extends PageVariantTestType> {
  testType: T;
}

interface TopCatalogCategory extends BasePageVariantTest<PageVariantTestType.TopCatalogCategory> {
  topCategory: string[];
}

interface CatalogCategoryTest extends BasePageVariantTest<PageVariantTestType.CatalogCategory> {
  category: SupportedEventProductCategory;
}

interface HasReviewsTest extends BasePageVariantTest<PageVariantTestType.HasReviews> {
  reviewMinimum?: number;
}

// This will return true if the product is in any of the listed collections
interface InCollectionTest extends BasePageVariantTest<PageVariantTestType.InCollection> {
  collections: string[];
}

// This will return true if the product has any of the listed merchant tags
interface HasMerchantTagTest extends BasePageVariantTest<PageVariantTestType.HasMerchantTag> {
  merchantTags: string[];
}

interface PageCategoryTest extends BasePageVariantTest<PageVariantTestType.PageCategory> {
  extractor: CategoryExtractor;
}

interface FeatureGateTest extends BasePageVariantTest<PageVariantTestType.FeatureGate> {
  featureGate: FeatureGates;
}

interface ProductIdTest extends BasePageVariantTest<PageVariantTestType.ProductId> {
  productIdExtractor: IdExtractor;
  productIds: string[];
}

interface PlpIdTest extends BasePageVariantTest<PageVariantTestType.PlpId> {
  plpIdExtractor: IdExtractor;
  plpIds: string[];
}

interface QueryParamTest extends BasePageVariantTest<PageVariantTestType.QueryParam> {
  queryParam: string;
}

interface UserHasInteractedTest extends BasePageVariantTest<PageVariantTestType.UserHasInteracted> {}

interface UserHasNotInteractedTest extends BasePageVariantTest<PageVariantTestType.UserHasNotInteracted> {}

interface IsLoadingTest extends BasePageVariantTest<PageVariantTestType.isLoading> {}

interface IsProductComparison extends BasePageVariantTest<PageVariantTestType.isProductComparison> {}

interface PageFallbackTest extends BasePageVariantTest<PageVariantTestType.Fallback> {}

interface UrlResolverTest extends BasePageVariantTest<PageVariantTestType.UrlResolver> {}

interface IsScreenWidthSmallerTest extends BasePageVariantTest<PageVariantTestType.isScreenWidthSmaller> {
  breakpoint: number;
}

export type PageVariantTest =
  | PageCategoryTest
  | CatalogCategoryTest
  | TopCatalogCategory
  | HasReviewsTest
  | InCollectionTest
  | HasMerchantTagTest
  | FeatureGateTest
  | ProductIdTest
  | PlpIdTest
  | QueryParamTest
  | UserHasInteractedTest
  | UserHasNotInteractedTest
  | IsLoadingTest
  | IsProductComparison
  | PageFallbackTest
  | UrlResolverTest
  | IsScreenWidthSmallerTest;

/**
 * Configuration for the social proof embedded widget
 *
 * @param headerTitle - The title text to display in the widget header
 * @param staticSuggestions - A list of strings to display as suggestions in the widget
 * @param suggestionButtonVariantDefault - The variant of the suggestion button to display in the widget footer
 * @param suggestionButtonVariantAccent - The variant of the suggestion button to display in the widget body
 * @param staticImageIndex - Index of the imageUrl to use from the product response
 */
interface SocialProofConfig {
  customerQuery: string;
  headerTitle: string;
  staticPLPImagesLayout?: 'grid' | 'horizontal';
  headerFontFamily?: string;
  staticPLPImageNames?: string[];
  staticImageIndex?: number;
  suggestionButtonStrings: string[];
  suggestionButtonVariantDefault: SuggestionButtonVariant;
  suggestionButtonVariantAccent?: SuggestionButtonVariant;
  suggestionButtonDataAttributes?: Record<string, string>;
  userQueryButtonConfig?: UserQueryButtonConfig;
  logoName?: string;
}

/**
 * Configuration for creating the mount point for a widget
 *
 * @param className - Optional class name to apply to the mount point. Tailwind classes are supported
 * and encouraged. Use this parameter to style the mounting container for the widget.
 */
export type WidgetMountingConfig = {
  mountingConfigId: string;
  containerId: string;
  testId: string;
  parentInsertionPoint?: InsertionPoint;
  insertionPoint: InsertionPoint;
  gridInsertionType?: GridInsertionType;
  wrappingElement?: WrappingElement;
  divCheckSelector?: string;
  suppressionSelector?: string;
  style?: Partial<CSSStyleDeclaration>;
  className?: string;
  dataAttributes?: Record<string, string>;
};

type StaticWidgetMounting = {
  mountingConfigId: string;
  widgetConfigId: string;
};
type DynamicWidgetMounting = {
  mountingConfigId: string;
  mountingPointWidgets: WidgetDisplayTests[];
};

type WidgetDisplayTests = {
  tests: PageVariantTest[];
  widgetConfigId: string;
};

type WidgetMounting = StaticWidgetMounting | DynamicWidgetMounting;

enum WidgetType {
  ChatPreview = 'ChatPreview',
  SocialProofV2 = 'SocialProofV2',
  ChatPreviewV2 = 'ChatPreviewV2',
  ChatPreviewIsLoading = 'ChatPreviewIsLoading',
  ChatPreviewPostInteraction = 'ChatPreviewPostInteraction',
  ChatPreviewProductComparison = 'ChatPreviewProductComparison',
  SuggestionBar = 'SuggestionBar',
  SuggestionBarV2 = 'SuggestionBarV2',
  ImagePromptCard = 'ImagePromptCard',
  ImageBanner = 'ImageBanner',
  SingleImagePrompt = 'SingleImagePrompt',
  SearchPrompt = 'SearchPrompt',
  SearchZeroStateEntryPoint = 'SearchZeroStateEntryPoint',
  SearchResultsEntryPoint = 'SearchResultsEntryPoint',
  SearchOverlayHost = 'SearchOverlayHost',
  NoOp = 'NoOp',
}

type WidgetConfig =
  | ChatPreviewWidgetConfig
  | SocialProofV2WidgetConfig
  | ChatPreviewV2WidgetConfig
  | ChatPreviewPostInteractionWidgetConfig
  | ChatPreviewIsLoadingWidgetConfig
  | ChatPreviewProductComparisonWidgetConfig
  | SuggestionBarWidgetV2Config
  | ImagePromptWidgetConfig
  | ImageBannerWidgetConfig
  | SingleImagePromptWidgetConfig
  | SearchPromptWidgetConfig
  | SearchEntryPointWidgetConfig
  | SearchResultsEntryPointWidgetConfig
  | SearchOverlayHostWidgetConfig
  | NoOpWidgetConfig;

interface BaseWidgetConfig<T extends WidgetType> {
  widgetConfigId: string;
  type: T;
  contentId?: string;
}

interface ImageBannerWidgetConfig extends BaseWidgetConfig<WidgetType.ImageBanner> {
  imageSrc: string;
  title: string;
  subtitle: string;
  assistantMessage: string;
}

interface ChatPreviewWidgetConfig extends BaseWidgetConfig<WidgetType.ChatPreview> {
  variant: 'filled' | 'flat' | 'outlined';
  addSeparators?: boolean;
  socialProofConfig?: SocialProofConfig;
  footerConfig?: ChatPreviewFooterConfig;
}

interface ChatPreviewHeaderV2Config {
  title?: string; // Default: 'Shopping Assistant'
  imageSrc?: string;
  imageHeight?: number;
}

type SingleImageConfig = {
  layout: 'single';
  imageIndex: number;
};
type MultiImageConfig = {
  layout: 'grid' | 'horizontal';
  imageNames: string[];
};
type SocialProofImageConfig = SingleImageConfig | MultiImageConfig;

type ChatPreviewSuggestionButtonConfig = {
  buttonStrings: string[];
  accentButtonVariants?: {
    button: SuggestionButtonVariant;
    hover: SuggestionButtonVariant;
  };
  buttonVariants: {
    button: SuggestionButtonVariant;
    hover: SuggestionButtonVariant;
  };
  numRows?: NumRows;
};

type ChatPreviewAnimatedTextConfig = {
  leadingText: string;
  animatedStrings: string[];
};

type ChatPreviewVariant =
  | { variant: 'flat' }
  | { variant: 'filled'; backgroundFillColor: string }
  | { variant: 'outlined' };

// Base interface for common chat preview properties
interface BaseChatPreviewConfig {
  headerConfig: ChatPreviewHeaderV2Config;
  suggestionButtonsConfig: ChatPreviewSuggestionButtonConfig;
  userQueryButtonConfig: UserQueryButtonConfig;
  chatPreviewVariant: ChatPreviewVariant;
  addSeparators?: boolean;
}

// Specific chat preview widget configurations
interface ChatPreviewPostInteractionWidgetConfig
  extends BaseWidgetConfig<WidgetType.ChatPreviewPostInteraction>, BaseChatPreviewConfig {
  chatPreviewVariant: ChatPreviewVariant;
  addSeparators?: boolean;
}

interface ChatPreviewIsLoadingWidgetConfig
  extends BaseWidgetConfig<WidgetType.ChatPreviewIsLoading>, BaseChatPreviewConfig {}

interface ChatPreviewProductComparisonWidgetConfig
  extends BaseWidgetConfig<WidgetType.ChatPreviewProductComparison>, BaseChatPreviewConfig {
  useLargeProductComparison?: boolean;
}

interface ChatPreviewV2WidgetConfig
  extends BaseWidgetConfig<WidgetType.ChatPreviewV2>, BaseChatPreviewConfig {
  animatedTextConfig: ChatPreviewAnimatedTextConfig;
}

interface SocialProofV2WidgetConfig
  extends BaseWidgetConfig<WidgetType.SocialProofV2>, BaseChatPreviewConfig {
  customerQuery?: string; // Default: 'asked which products are the best'
  imageConfig: SocialProofImageConfig;
}

interface SuggestionBarWidgetV2Config extends BaseWidgetConfig<WidgetType.SuggestionBarV2> {
  metricDisplayLocation: ChatElementDisplayLocation;
  location: SuggestionBarLocationForMetrics;
  variant: SuggestionButtonVariant;
  hoverVariant: SuggestionButtonVariant;
  buttonTexts: {
    default: string[];
    productSpecific?: { [productId: string]: string[] };
  };
  boldFirstButton?: boolean;
  twoRowsOnMobile?: boolean;
  animationSpeed?: 'standard' | 'slow' | 'none';
  buttonBorderRadius?: 'sm' | 'md' | 'lg';
}

interface ImagePromptWidgetConfig extends BaseWidgetConfig<WidgetType.ImagePromptCard> {
  url: string;
  lightText?: boolean;
  title: string;
  subtitle: string[];
  staticSuggestionCopies: string[];
  userQueryButtonConfig: UserQueryButtonConfig;
  fallbackBackgroundColor?: string;
}

interface SingleImagePromptWidgetConfig extends BaseWidgetConfig<WidgetType.SingleImagePrompt> {
  title: string;
  staticSuggestionCopies: string[];
  userQueryButtonConfig: UserQueryButtonConfig;
}

interface SearchEntryPointWidgetConfig extends BaseWidgetConfig<WidgetType.SearchZeroStateEntryPoint> {
  searchZeroStateVariant: SearchZeroStateVariant;
  searchInputVariant: SearchInputVariant;
  searchIconVariant?: SearchIconVariant;
  searchIconSize?: number;
  suggestionButtonConfig: SuggestionButtonConfig;
  layout: SearchZeroStateLayout;
  searchBoxPlaceholder: string;
  animationSpeed?: 'standard' | 'slow' | 'none';
  compactLabel?: string;
  initialSuggestions?: string[];
  usingPortal?: boolean;
  includeSubtitle?: boolean;
}

interface NoOpWidgetConfig extends BaseWidgetConfig<WidgetType.NoOp> {}
interface SearchOverlayHostWidgetConfig extends BaseWidgetConfig<WidgetType.SearchOverlayHost> {}

interface SearchResultsEntryPointWidgetConfig extends BaseWidgetConfig<WidgetType.SearchResultsEntryPoint> {
  searchInputVariant: SearchInputVariant;
  searchFilterSidebarVariant: SearchFilterSidebarVariant;
  productGridVariant: ProductGridVariant;
  searchBoxPlaceholder: string;
  noResultsFoundText?: string;
}

export interface WidgetHeaderProps extends TestProps {
  title?: string;
  logo?: string;
  logoHeight?: number;
  orgShortName: string;
  variant?: SearchPromptVariant;
}

export interface UserQueryOptions {
  footerVariant?: 'standard';
  replyButtonText?: string;
  replyButtonIcon?: 'magnifyingGlass' | 'send' | 'thinMagnifyingGlass' | 'ai-search';
}

type SearchPromptVariant = 'primary';
interface SearchPromptWidgetConfig extends BaseWidgetConfig<WidgetType.SearchPrompt> {
  variant: SearchPromptVariant;
  title: string;
  headerConfig: WidgetHeaderProps;
  suggestionButtons: {
    variant: SuggestionButtonVariant;
    hoverVariant: SuggestionButtonVariant;
    buttonTexts: string[];
  };
  footerConfig?: UserQueryOptions;
}

type PageVariantBase = {
  // Unique identifier for each entry within the pageVariants.
  // Useful to differentiate which variant is loaded when there are multiples of a single type.
  variantId: string;
  widgetMounting: WidgetMounting[];
  variantTests: PageVariantTest[];
  floatingButtonOverride?: ShowFloatingButtonOptions;
};

type PLPPageVariant = PageVariantBase & {
  variantType: 'plp';
  plpIdExtractor: IdExtractor;
};

type PDPPageVariant = PageVariantBase & {
  variantType: 'pdp';
  parentProductIdExtractor?: IdExtractor;
  productIdExtractor: IdExtractor;
};

type VisitPageVariant = PageVariantBase & {
  variantType: 'page_visit';
};

type OtherPageVariant = PageVariantBase & {
  variantType: 'other';
};

type HomePageVariant = PageVariantBase & {
  variantType: 'homepage';
};

type SearchPageVariant = PageVariantBase & {
  variantType: 'search';
};

type FullPageSalesAgentVariant = PageVariantBase & {
  variantType: 'full_page';
};

export type PageVariantConfig =
  | PLPPageVariant
  | PDPPageVariant
  | VisitPageVariant
  | OtherPageVariant
  | HomePageVariant
  | SearchPageVariant
  | FullPageSalesAgentVariant;

export type OrgPageConfig = {
  // pageVariants is a list of page variants that we support.
  pageVariants: PageVariantConfig[];
  // widgetConfigs is a named set of widget configs
  widgetConfigs: Record<string, WidgetConfigV3>;
  mountingConfigs: Record<string, WidgetMountingConfig>;
};

export type OrgConfig = OrgUIConfig;

export { CategoryExtractorType, ColorNames, colorVar, PageVariantTestType, WidgetType };

export interface EnviveConfig {
  amplitudeApiKey?: string;
  dataResidency?: string;
  env?: string;
  baseUrl?: string;
  reactAppName?: string;
  cdnUrl?: string;
  contextSource?: string;
  orgLevelApiKey?: string;
  orgShortName?: string;
  orgId?: string;
  identifyingPrefix?: string;
  featureOverrides?: Record<string, boolean>;
  variantUrlOverride?: string;
  variantInfoOverride?: any;
  show?: boolean;
  enviveOn?: boolean;
  publicKey?: string;
  featureGates?: OrgConfigFeatureGate[];
  hardcopyOverride?: Partial<Record<WidgetTypeV3, HardcopyResponse>>;
}

export type {
  CategoryExtractor,
  ChatMessageVariant,
  ChatMessageConfig,
  ChatPreviewConfig,
  ChatPreviewIsLoadingWidgetConfig,
  ChatPreviewPostInteractionWidgetConfig,
  ChatPreviewProductComparisonWidgetConfig,
  ChatPreviewSuggestionButtonConfig,
  SocialProofV2WidgetConfig,
  ChatPreviewHeaderV2Config,
  ChatPreviewV2WidgetConfig,
  ChatPreviewFooterConfig,
  ChatPreviewHeaderConfig,
  ChatPreviewWidgetConfig,
  ChatPreviewVariant,
  ColorMapping,
  CustomerServiceIntegration,
  FloatingEntryPointConfig,
  FullCustomerServiceIntegration,
  IdExtractor,
  ImageBannerWidgetConfig,
  ImagePromptWidgetConfig,
  InsertionPoint,
  MultiImageConfig,
  MerchantVariantSettings,
  SearchConfig,
  OrgUIConfig,
  PageCardConfig,
  PageCardVariant,
  PageCardHoverVariant,
  PageCardIconVariant,
  ProductCardConfig,
  ProductCardVariant,
  ProductCardLayoutVariant,
  ProductCardHoverVariant,
  ProductLinkHoverVariant,
  ProductLinkIconVariant,
  ProductLinkVariant,
  ProductReviewConfig,
  ProductReviewStyleVariant,
  ProductReviewColorVariant,
  SearchPromptVariant,
  SearchPromptWidgetConfig,
  SearchResultsEntryPointWidgetConfig,
  ShowFloatingButtonOptions,
  SingleImagePromptWidgetConfig,
  SearchEntryPointWidgetConfig,
  SearchOverlayHostWidgetConfig,
  SocialProofConfig,
  SuggestionBarWidgetV2Config,
  SuggestionButtonConfig,
  SuggestionButtonVariant,
  URLTest,
  UserQueryButtonConfig,
  UserQueryButtonIcon,
  WelcomeSectionConfig,
  WelcomeSectionVariant,
  WelcomeSectionColorVariant,
  WidgetConfig,
  WrappingElement,
  SearchCardVariant,
  WidgetDisplayTests,
  NoOpWidgetConfig,
  WidgetMounting,
  StaticWidgetMounting,
  DynamicWidgetMounting,
  PDPPageVariant,
  PLPPageVariant,
  VisitPageVariant,
  OtherPageVariant,
  HomePageVariant,
  SearchPageVariant,
  NumRows,
};
