import { ReactNode, createContext, useCallback, useContext, useMemo, useState } from 'react';
import Logger from 'src/application/logging/logger';
import { v4 as uuid } from 'uuid';
import CommerceApiClient from 'src/application/commerce-api';
import { WidgetString, WidgetText } from 'src/application/models/api/widgetText';
import { WidgetTextRequest } from 'src/application/models/api/widgetTextRequest';

import { useAtomValue } from 'jotai';
import { appDetailsAtom } from 'src/atoms/app';
import { EnviveMetricsEventName } from 'src/services/amplitudeService/amplitudeService';
import { toCamelCase } from 'src/application/models/utils/snakeToCamelTransformer';
import { UserEvent } from 'src/application/models';
import { getQueryParam } from 'src/application/utils';
import { WidgetTypeV3 } from '../typesV3';
import { useFeatureFlagService } from '../featureFlagServiceContext/featureFlagServiceContext';
import { useAmplitude } from '../amplitudeContext';

const logger = new Logger('hardcopyContext');

interface HardcopyRequest {
  widgetType: WidgetTypeV3;
  userEvent: UserEvent;
}

export type HardcopyResponse = {
  responseId: string;
  language: string;
  rawValues?: Record<string, WidgetString | WidgetString[]>;
  values: Record<string, string | string[]>;
};

interface HardcopyContextType {
  getHardcopy: (HardcopyRequest: HardcopyRequest) => Promise<HardcopyResponse>;
  isLoading: boolean;
}

const convertToHardcopyResponse = (response: WidgetText): HardcopyResponse => {
  return {
    responseId: response.responseId,
    language: response.language,
    rawValues: response.values,
    values: Object.fromEntries(
      Object.entries(response.values).map(([key, value]) => [
        // Transform the key from snake_case to camelCase
        toCamelCase(key),
        value.length === 1 ? value[0].value : value.map(v => v.value),
      ]),
    ),
  };
};

// These are just sample responses for the sake of testing.
// As we start to build the actual widgets we should determine what the actual
// values and their names should be.
const MOCK_HARDCOPY_RESPONSE: Partial<Record<WidgetTypeV3, HardcopyResponse>> = {
  [WidgetTypeV3.PromptCarouselV3]: {
    responseId: uuid(),
    language: 'en',
    values: {
      promptButtonTexts: [
        'What are your best sellers?',
        'Show me summer dresses',
        'Do you have free shipping?',
        'What sizes are available?',
        'Can I return items?',
      ],
    },
  },
  [WidgetTypeV3.TitledPromptCarouselV3]: {
    responseId: 'mock-response-id',
    language: 'en',
    values: {
      titleLabel: 'Need some help?',
      promptButtonTexts: [
        'What are your best sellers?',
        'Show me summer dresses',
        'Do you have free shipping?',
        'What sizes are available?',
        'Can I return items?',
      ],
    },
  },
  [WidgetTypeV3.SocialProofV3]: {
    responseId: 'mock-response-id',
    language: 'en',
    values: {
      titleLabel: 'Shopping Assistant',
      numberOfCustomersText: '123 customers',
      customerQueryText: 'found what they were looking for...',
      primaryButtonText: 'Start shopping',
      secondaryButtonTitleText: 'Popular searches',
      secondaryButtonTexts: [
        'Why should I buy from you?',
        'How do I return an item?',
        'New arrivals',
        'Sale items',
        'Popular items',
      ],
      textFieldPlaceholderText: 'Ask me anything...',
    },
  },
  [WidgetTypeV3.TypingAnimationV3]: {
    responseId: 'mock-response-id',
    language: 'en',
    values: {
      titleLabel: 'Shopping Assistant',
      headlineText: 'Need help finding',
      animatedTextSequence: [
        'the perfect gift for your loved ones?',
        'something special for the holidays?',
        'the ideal present for someone special?',
      ],
      hintText: 'Ask me anything',
      promptButtonTexts: [
        'What are your best sellers?',
        'Show me summer dresses',
        'Do you have free shipping?',
        'What sizes are available?',
      ],
      textFieldAriaLabel: 'Ask me anything',
    },
  },
  [WidgetTypeV3.ChatPreviewComparisonV3]: {
    responseId: 'mock-response-id',
    language: 'en',
    values: {
      titleLabel: 'Shopping Assistant',
      headlineText: 'Need help comparing?',
      textFieldPlaceholderText: 'Ask me anything...',
    },
  },
  [WidgetTypeV3.ChatPreviewLoadingV3]: {
    responseId: 'mock-response-id',
    language: 'en',
    values: {
      titleLabel: 'Shopping Assistant',
      textFieldPlaceholderText: 'Ask me anything...',
    },
  },
  [WidgetTypeV3.ChatPreviewV3]: {
    responseId: 'mock-response-id',
    language: 'en',
    values: {
      titleLabel: 'Shopping Assistant',
      textFieldPlaceholderText: 'Ask me anything...',
    },
  },
  [WidgetTypeV3.PromptButtonCarouselWithImageV3]: {
    responseId: 'mock-response-id',
    language: 'en',
    values: {
      titleLabel: 'Need some help?',
      promptButtonsTexts: ['Help me find a product', "What's on your mind?", 'Talk to a human'],
      textFieldPlaceholderText: 'Ask me anything...',
    },
  },
  [WidgetTypeV3.ProductCardV3]: {
    responseId: 'mock-response-id',
    language: 'en',
    values: {
      headline: 'Discover Your Perfect Style',
      animatedText: [
        'the perfect outfit for any occasion',
        'trending fashion that fits your lifestyle',
        'quality pieces that last',
      ],
      prompts: [
        'What are your best sellers?',
        'Show me summer dresses',
        'Do you have free shipping?',
        'What sizes are available?',
        'Can I return items?',
      ],
      placeholder: 'Ask me anything...',
    },
  },
  [WidgetTypeV3.FloatingChatV3]: {
    responseId: 'mock-response-id',
    language: 'en',
    values: {
      welcomeMessageTitle: 'Welcome to Envive AI',
      welcomeMessageText:
        'Your personal shopper trained on the collective knowledge of thousands of real experts!',
      chatFooterTextFieldPlaceholderText: 'Ask me anything...',
      disclaimerText: 'This is a disclaimer...',
      leftToggleLabel: 'Shop with AI',
      rightToggleLabel: 'Live support',
    },
  },
  [WidgetTypeV3.FullPageSalesAgentV3]: {
    responseId: 'mock-response-id',
    language: 'en',
    values: {
      welcomeMessageTitle: 'Welcome to Envive AI',
      welcomeMessageText:
        'Your personal shopper trained on the collective knowledge of thousands of real experts!',
      chatFooterTextFieldPlaceholderText: 'Ask me anything...',
      disclaimerText: 'This is a disclaimer...',
    },
  },
};

const HardcopyContext = createContext<HardcopyContextType | undefined>(undefined);

interface HardcopyProviderProps {
  children: ReactNode;
  hardcopyOverride?: Partial<Record<WidgetTypeV3, HardcopyResponse>>;
}

export const HardcopyProvider: React.FC<HardcopyProviderProps> = ({
  children,
  hardcopyOverride,
}) => {
  const languages = useMemo(() => navigator.languages, []);
  const [isLoading, setIsLoading] = useState(false);
  const context = useAtomValue(appDetailsAtom);
  const { trackEvent } = useAmplitude();

  const { featureFlagService } = useFeatureFlagService();
  const getHardcopyFromBackend = useCallback(
    async (request: HardcopyRequest): Promise<HardcopyResponse> => {
      const fallbackWidgetType =
        request.widgetType === WidgetTypeV3.ProductCardV3
          ? WidgetTypeV3.ImagePromptCardV3
          : request.widgetType;

      const overrideEntry =
        hardcopyOverride?.[request.widgetType] ?? hardcopyOverride?.[fallbackWidgetType];
      if (overrideEntry) {
        logger.logDebug('using hardcopy override', request.widgetType);
        return overrideEntry;
      }

      const overrideConfigVersion =
        getQueryParam('spiffy_config_version') ||
        getQueryParam('envive_config_version') ||
        undefined;
      const widgetTextRequest: WidgetTextRequest = {
        requestId: uuid(),
        widgetType: request.widgetType,
        context,
        featureFlags: featureFlagService?.getFeatureFlags() || {},
        language: languages[0] || 'en',
        overrideConfigVersion,
        url: window.location.href,
      };
      trackEvent({
        eventName: EnviveMetricsEventName.WidgetTextRequest,
        eventProps: {
          widget_type: request.widgetType,
          request_id: widgetTextRequest.requestId,
        },
      });
      try {
        const response = await CommerceApiClient.getHardcopy(widgetTextRequest);
        if (response) {
          const convertedResponse = convertToHardcopyResponse(response);
          logger.logDebug('converted response', convertedResponse);
          trackEvent({
            eventName: EnviveMetricsEventName.WidgetTextResponse,
            eventProps: {
              widget_type: request.widgetType,
              response_id: response.responseId,
              widget_text: response.values,
              request_id: widgetTextRequest.requestId,
            },
          });
          return convertedResponse;
        }
      } catch (error) {
        logger.logError('error getting hardcopy from backend', error);
      }
      const mockResponse = MOCK_HARDCOPY_RESPONSE[request.widgetType];
      if (mockResponse) {
        logger.logDebug('no real response, using mock', mockResponse);
        return mockResponse;
      }
      throw new Error(`No hardcopy response found for widget type: ${request.widgetType}`);
    },
    [context, featureFlagService, hardcopyOverride, languages, trackEvent],
  );

  const getHardcopy = useCallback(
    async (request: HardcopyRequest): Promise<HardcopyResponse> => {
      setIsLoading(true);
      logger.logDebug('retrieving hardcopy', languages);

      logger.logDebug('request', request);
      const response = await getHardcopyFromBackend(request);
      logger.logDebug('returning hardcopy response', response);
      if (!response) {
        setIsLoading(false);
        throw new Error(`No hardcopy response found for widget type: ${request.widgetType}`);
      }
      setIsLoading(false);
      return response;
    },
    [getHardcopyFromBackend, languages],
  );

  const value = useMemo(() => ({ getHardcopy, isLoading }), [getHardcopy, isLoading]);

  return <HardcopyContext.Provider value={value}>{children}</HardcopyContext.Provider>;
};

export const useHardcopy = () => {
  const context = useContext(HardcopyContext);
  if (!context) {
    throw new Error('useHardcopy must be used within a HardcopyProvider');
  }
  return context;
};
