import React, { type JSX, ComponentType } from 'react';
import DomPurify from 'dompurify';
import parse, {
  domToReact,
  HTMLReactParserOptions,
  Element,
  DOMNode,
  attributesToProps,
} from 'html-react-parser';
import { List, ListItem } from '@digigov/ui/content/List';
import { Link } from '@digigov/ui/navigation';
import { Heading } from '@digigov/ui/typography/Heading';
import { NormalText } from '@digigov/ui/typography/NormalText';
import { Paragraph } from '@digigov/ui/typography/Paragraph';

interface RegistryComponentProps {
  children?: React.ReactNode;
  [key: string]: any;
}

type ComponentsRegistry = Record<string, ComponentType<RegistryComponentProps>>;

export const componentsRegistry: ComponentsRegistry = {
  h1: (props) => <Heading size="xl">{props.children}</Heading>,
  h2: (props) => <Heading size="lg">{props.children}</Heading>,
  h3: (props) => <Heading size="md">{props.children}</Heading>,
  h4: (props) => <Heading size="sm">{props.children}</Heading>,
  h5: (props) => <Heading size="xs">{props.children}</Heading>,
  a: (props) => <Link href={props.href}>{props.children}</Link>,
  p: (props) => <Paragraph>{props.children}</Paragraph>,
  span: (props) => <NormalText mb={0}>{props.children}</NormalText>,
  ul: (props) => <List listStyle="bullet">{props.children}</List>,
  ol: (props) => <List listStyle="number">{props.children}</List>,
  li: (props) => <ListItem>{props.children}</ListItem>,
  br: () => <br />,
  b: (props) => <b>{props.children}</b>,
  strong: (props) => <strong>{props.children}</strong>,
  i: (props) => <i>{props.children}</i>,
  sup: (props) => <sup>{props.children}</sup>,
  sub: (props) => <sub>{props.children}</sub>,
  img: (props) => <img {...props} />,
};

export interface SafeHTMLProps {
  content: string;
  Tag?: keyof JSX.IntrinsicElements;
}

export const SafeHTML = ({
  content,
  Tag = 'span',
  ...props
}: SafeHTMLProps) => {
  const purifiedHtmlString = DomPurify.sanitize(content, {
    ALLOWED_TAGS: [...Object.keys(componentsRegistry)],
  });

  const options: HTMLReactParserOptions = {
    replace(domNode) {
      if (!(domNode instanceof Element && domNode.attribs)) return;

      const Component = componentsRegistry[domNode.name];
      if (!Component) return;

      const reactProps = attributesToProps(domNode.attribs);

      if (domNode.children && domNode.children.length > 0) {
        return (
          <Component {...reactProps}>
            {domToReact(domNode.children as DOMNode[], options)}
          </Component>
        );
      }

      return <Component {...reactProps} />;
    },
  };

  return <Tag {...props}>{parse(purifiedHtmlString, options)}</Tag>;
};

export default SafeHTML;
