import React, { useContext } from 'react';
import { Text as RNText, TextProps as RNTextProps, View } from 'react-native';
import styles from './styles';
import { Typography, TypographyWeight } from './types';
import {
  ApplicationContext,
  MiniAppContext,
  SkeletonContext,
} from '../Context';
import { scaleSize, useScaleSize } from './utils';
import { Skeleton } from '../Skeleton';

const SFProText: TypographyWeight = {
  100: 'Thin',
  200: 'Ultralight',
  300: 'Light',
  400: 'Regular',
  500: 'Medium',
  600: 'Semibold',
  700: 'Bold',
  800: 'Heavy',
  900: 'Black',
  normal: 'Regular',
  bold: 'Bold',
};

const AlegreyaSans: TypographyWeight = {
  100: 'Thin',
  200: 'Thin',
  300: 'Thin',
  400: 'Regular',
  500: 'Medium',
  600: 'Medium',
  700: 'Bold',
  800: 'Black',
  900: 'Black',
  normal: 'Regular',
  bold: 'Bold',
};

const BarlowCondensed: TypographyWeight = {
  100: 'Thin',
  200: 'ExtraLight',
  300: 'Light',
  400: 'Regular',
  500: 'Medium',
  600: 'SemiBold',
  700: 'Bold',
  800: 'ExtraBold',
  900: 'Black',
  normal: 'Regular',
  bold: 'Bold',
};

const FontStyle: { [key: string]: string } = {
  italic: 'Italic',
  normal: '',
};

export interface TextProps extends RNTextProps {
  /**
   * Represents the typography style applied to the Text component.
   * It defines the appearance of the text in terms of font size, weight, line height etc.
   */
  typography: Typography;

  /**
   * Optional. Represents the color of the text in the Text component.
   * It can be any valid color string (e.g., hex, rgb, rgba, etc.).
   */
  color?: string;

  /**
   * Optional. Represents the font-family of the text in the Text component.
   * Ex: MomoSignature, MomoTrustDisplay
   */
  fontFamily?: string;

  /**
   * Optional. Modified max scale rate of scaleSize function in Text component, default is 1.5.
   * Ex: 1.5, 2
   */
  maxScaleRate?: number;
}

const deprecatedValues: Typography[] = [
  'headline_default',
  'headline_l',
  'headline_xl',
  'title_default',
  'title_xs',
  'title_s',
  'header_default',
  'paragraph_default',
  'paragraph_bold',
  'paragraph_italic',
  'label_xxs',
  'action_s',
];

const TypoStyles = (
  typo: Typography,
  newFontFamily?: string,
  maxScaleRate?: number,
) => {
  const { theme } = useContext(ApplicationContext);
  const styleSheet: {
    [key: string]: any;
  } = styles;
  const typoStyle = styleSheet[typo] ?? styleSheet.paragraph_default;
  const { fontWeight, fontSize, fontStyle, lineHeight } = typoStyle;
  const style = FontStyle[fontStyle ?? 'normal'];
  const font = newFontFamily ?? theme.font;
  let fontFamily: string;

  switch (font) {
    case 'SFProText': {
      fontFamily = `${font}-${SFProText[fontWeight]}${style}`;
      break;
    }
    case 'AlegreyaSans': {
      fontFamily = `${font}-${AlegreyaSans[fontWeight]}${style}`;
      break;
    }
    case 'BarlowCondensed': {
      fontFamily = `${font}-${BarlowCondensed[fontWeight]}${style}`;
      break;
    }
    case 'Montserrat-Bold':
    case 'iCielPanton-Black':
    case 'iCielBCCubano-Normal':
    case 'MoMoTrustDisplay':
    case 'MoMoSignature': {
      fontFamily = font;
      break;
    }
    default: {
      fontFamily = `SFProText-${SFProText[fontWeight]}${style}`;
    }
  }

  return {
    ...typoStyle,
    fontFamily,
    fontSize: useScaleSize(fontSize, maxScaleRate),
    lineHeight: useScaleSize(lineHeight, maxScaleRate),
    fontStyle,
    fontWeight,
  };
};

const Text: React.FC<TextProps> = ({
  typography = 'body_default_regular',
  color,
  children,
  style,
  fontFamily,
  maxScaleRate,
  ...rest
}) => {
  const { theme } = useContext(ApplicationContext);
  const context = useContext<any>(MiniAppContext);
  const skeleton = useContext(SkeletonContext);
  const textStyle = TypoStyles(typography, fontFamily, maxScaleRate);

  if (deprecatedValues.includes(typography)) {
    console.warn(
      `Warning: The typography value "${typography}" is deprecated.`,
    );
  }

  const showBaseLineDebug = context?.features?.showBaseLineDebug ?? false;

  if (skeleton.loading) {
    return (
      <View style={style}>
        <RNText
          {...rest}
          allowFontScaling={false}
          style={[
            textStyle,
            {
              color: color ?? theme.colors.text.default,
            },
          ]}
        >
          {children ?? ''}
        </RNText>
        <Skeleton style={{ position: 'absolute' }} />
      </View>
    );
  }

  return (
    <RNText
      {...rest}
      allowFontScaling={false}
      style={[
        style,
        textStyle,
        showBaseLineDebug && styles.debugBaseLine,
        {
          color: color ?? theme.colors.text.default,
        },
      ]}
    >
      {children ?? ''}
    </RNText>
  );
};

const exportFontFamily = (
  fontWeight: string,
  typography?: Typography,
  fontFamily?: string,
): string => {
  let newFontFamily;

  switch (fontWeight) {
    case 'bold':
    case 'Bold':
      typography = 'action_xs_bold';
      break;

    case 'regular':
    case 'Regular':
      typography = 'body_default_regular';
      break;

    default: {
      typography = 'body_default_regular';
      break;
    }
  }

  newFontFamily = TypoStyles(typography, fontFamily).fontFamily;

  return newFontFamily;
};

export { Text, scaleSize, useScaleSize, exportFontFamily };
