import React, {memo, useMemo} from 'react';
import {StyleSheet, useWindowDimensions} from 'react-native';
import RNRenderHtml, {MixedStyleDeclaration} from 'react-native-render-html';
import {WebView} from '@components/_core/WebView';
import {useTheme} from '@shared/theme';
import {getCommunityFeature} from '@stores/communityFeatures';

import {
  CUSTOM_HTML_ELEMENT_MODELS,
  DEFAULT_TEXT_PROPS,
  IGNORED_STYLES,
  RENDERERS,
  SYSTEM_FONTS,
} from './constants';
import {CustomImgRendererProps, HtmlRenderProps} from './interfaces';
import {
  buildBaseTagsStyles,
  getListMarkerTextStyle,
  mergeTagsStyles,
  splitTextStyleColor,
} from './utils';

export type {HtmlRenderProps};

function HtmlRenderContentRenderer({
  html,
  contentWidth,
  onLoaded,
  onLinkPress,
  textStyle,
  androidLayerType = 'hardware',
  tagsStyles,
  numberOfLines,
  hasCustomVideoControl = false,
  resizeAndAlignMultimedia = false,
  baseStyle,
}: HtmlRenderProps) {
  const {theme} = useTheme();
  const {width: defaultWidth} = useWindowDimensions();
  const preventCopy = getCommunityFeature('PREVENT_COPY_TO_CLIPBOARD');
  const width = useMemo(
    () => contentWidth ?? defaultWidth,
    [contentWidth, defaultWidth],
  );

  const {defaultBodyTextColor, textStyleForDefaultProps} = useMemo(
    () => splitTextStyleColor(textStyle, theme.text.neutral.default),
    [textStyle, theme.text.neutral.default],
  );

  const textProps = useMemo(
    () => ({
      ...DEFAULT_TEXT_PROPS,
      ...(preventCopy ? {selectable: false} : {}),
      ...(textStyleForDefaultProps != null
        ? {style: textStyleForDefaultProps}
        : {}),
      numberOfLines,
    }),
    [numberOfLines, preventCopy, textStyleForDefaultProps],
  );

  const baseTagsStyles = useMemo(
    () => buildBaseTagsStyles(theme, defaultBodyTextColor),
    [defaultBodyTextColor, theme],
  );

  const combinedTagsStyles = useMemo(
    () => mergeTagsStyles(baseTagsStyles, tagsStyles),
    [baseTagsStyles, tagsStyles],
  );

  const listMarkerTextStyle = useMemo(
    () => getListMarkerTextStyle(combinedTagsStyles, defaultBodyTextColor),
    [combinedTagsStyles, defaultBodyTextColor],
  );

  const renderersProps = useMemo(
    () => ({
      ul: {markerTextStyle: listMarkerTextStyle},
      ol: {markerTextStyle: listMarkerTextStyle},
      video: {
        hasCustomVideoControl,
        resizeAndAlignMultimedia,
      },
      iframe: {
        resizeAndAlignMultimedia,
      },
      img: {resizeAndAlignMultimedia} as CustomImgRendererProps,
      ...(onLinkPress
        ? {
            a: {
              onPress: onLinkPress,
            },
          }
        : {}),
    }),
    [
      hasCustomVideoControl,
      listMarkerTextStyle,
      onLinkPress,
      resizeAndAlignMultimedia,
    ],
  );

  const webViewProps = useMemo(
    () => ({
      androidLayerType,
      scrollEnabled: true,
      nestedScrollEnabled: true,
      overScrollMode: 'always',
      androidHardwareAccelerationDisabled: false,
    }),
    [androidLayerType],
  );

  const source = useMemo(() => ({html}), [html]);

  const flatBaseStyle = useMemo(
    () => StyleSheet.flatten(baseStyle) as MixedStyleDeclaration | undefined,
    [baseStyle],
  );

  return (
    <RNRenderHtml
      contentWidth={width}
      source={source}
      WebView={WebView}
      customHTMLElementModels={CUSTOM_HTML_ELEMENT_MODELS}
      renderers={RENDERERS}
      onHTMLLoaded={onLoaded}
      ignoredStyles={IGNORED_STYLES}
      systemFonts={SYSTEM_FONTS}
      renderersProps={renderersProps}
      defaultTextProps={textProps}
      defaultWebViewProps={webViewProps}
      tagsStyles={combinedTagsStyles}
      baseStyle={flatBaseStyle}
    />
  );
}

export const HtmlRenderContent = memo(HtmlRenderContentRenderer);
