import { renderOptions } from "./renderOptions"

import { RTEMarkType, RTERenderMark } from "@/types/rte/node"
import { RTETypeEnum } from "@/types/rte/enums"

import type { EmbedByUid } from "@/types/components/jsontohtml"
import type { Node } from "@/types/requests/utils/edges"
import type { RenderOptions } from "@/types/rte/option"
import type {
  RTENode,
  RTETextNode,
  RTERenderOptionComponent,
} from "@/types/rte/node"
import type { Embeds } from "@/types/requests/embeds"

export function groupEmbedsByUid(embedsArray: Node<Embeds>[]) {
  const embedsByUid = embedsArray.reduce<EmbedByUid>((acc, embed) => {
    if (embed.node.system.uid) {
      acc[embed.node.system.uid] = embed
    }
    return acc
  }, {})

  return embedsByUid
}

export function nodeChildrenToHtml(
  nodes: RTENode[],
  embeds: EmbedByUid,
  fullRenderOptions: RenderOptions
): any {
  return nodes.map((node, i) => {
    // This function either returns a JSX element or null
    return {
      ...nodeToHtml(node, embeds, fullRenderOptions),
      key: `child-rte-${i}`,
    }
  })
}

export function textNodeToHtml(
  node: RTETextNode,
  fullRenderOptions: RenderOptions
) {
  let text = <>{node.text}</>

  if (node.classname || node.id) {
    text = (fullRenderOptions[RTEMarkType.classnameOrId] as RTERenderMark)(
      text,
      node.classname,
      node.id
    )
  }
  if (node.break) {
    text = (fullRenderOptions[RTEMarkType.break] as RTERenderMark)(text)
  }
  if (node.superscript) {
    text = (fullRenderOptions[RTEMarkType.superscript] as RTERenderMark)(text)
  }
  if (node.subscript) {
    text = (fullRenderOptions[RTEMarkType.subscript] as RTERenderMark)(text)
  }
  if (node.inlineCode) {
    text = (fullRenderOptions[RTEMarkType.inlineCode] as RTERenderMark)(text)
  }
  if (node.strikethrough) {
    text = (fullRenderOptions[RTEMarkType.strikethrough] as RTERenderMark)(text)
  }
  if (node.underline) {
    text = (fullRenderOptions[RTEMarkType.underline] as RTERenderMark)(text)
  }
  if (node.italic) {
    text = (fullRenderOptions[RTEMarkType.italic] as RTERenderMark)(text)
  }
  if (node.bold) {
    text = (fullRenderOptions[RTEMarkType.bold] as RTERenderMark)(text)
  }

  return text
}

function next(
  nodes: RTENode[],
  embeds: EmbedByUid,
  fullRenderOptions: RenderOptions
) {
  return nodeChildrenToHtml(nodes, embeds, fullRenderOptions)
}

export function nodeToHtml(
  node: RTENode,
  embeds: EmbedByUid,
  fullRenderOptions: RenderOptions
) {
  if ("type" in node === false) {
    return textNodeToHtml(node, fullRenderOptions)
  } else {
    if (fullRenderOptions[node.type] !== undefined) {
      if (node.type === RTETypeEnum.doc) {
        return null
      }
      return (fullRenderOptions[node.type] as RTERenderOptionComponent)(
        node,
        embeds,
        next,
        fullRenderOptions
      )
    } else {
      return next(node.children, embeds, fullRenderOptions)
    }
  }
}

export function nodesToHtml(
  nodes: RTENode[],
  embedsArray: Node<Embeds>[],
  overrideRenderOptions: RenderOptions
) {
  const embeds = groupEmbedsByUid(embedsArray)
  const fullRenderOptions = { ...renderOptions, ...overrideRenderOptions }
  return nodes.map((node) => nodeToHtml(node, embeds, fullRenderOptions))
}
