/* @flow */

import type { Key } from 'react';
import formatReactElementNode from './formatReactElementNode';
import type { Options } from './../options';
import type {
  ReactElementTreeNode,
  ReactFragmentTreeNode,
  TreeNode,
} from './../tree';

const REACT_FRAGMENT_TAG_NAME_SHORT_SYNTAX = '';
const REACT_FRAGMENT_TAG_NAME_EXPLICIT_SYNTAX = 'React.Fragment';

const toReactElementTreeNode = (
  displayName: string,
  key: ?Key,
  childrens: TreeNode[]
): ReactElementTreeNode => {
  let props = {};
  if (key) {
    props = { key };
  }

  return {
    type: 'ReactElement',
    displayName,
    props,
    defaultProps: {},
    childrens,
  };
};

const isKeyedFragment = ({ key }: ReactFragmentTreeNode) => Boolean(key);
const hasNoChildren = ({ childrens }: ReactFragmentTreeNode) =>
  childrens.length === 0;

export default (
  node: ReactFragmentTreeNode,
  inline: boolean,
  lvl: number,
  options: Options
): string => {
  const { type, key, childrens } = node;

  if (type !== 'ReactFragment') {
    throw new Error(
      `The "formatReactFragmentNode" function could only format node of type "ReactFragment". Given: ${type}`
    );
  }

  const { useFragmentShortSyntax } = options;

  let displayName;
  if (useFragmentShortSyntax) {
    if (hasNoChildren(node) || isKeyedFragment(node)) {
      displayName = REACT_FRAGMENT_TAG_NAME_EXPLICIT_SYNTAX;
    } else {
      displayName = REACT_FRAGMENT_TAG_NAME_SHORT_SYNTAX;
    }
  } else {
    displayName = REACT_FRAGMENT_TAG_NAME_EXPLICIT_SYNTAX;
  }

  return formatReactElementNode(
    toReactElementTreeNode(displayName, key, childrens),
    inline,
    lvl,
    options
  );
};
