import React, { isValidElement } from 'react'
import Markdown from 'markdown-to-jsx'
import SyntaxHighlighter from 'react-syntax-highlighter'
import atomOneLight from './styles/atom-one-light'
import { View } from '../view'
import { Button } from '../button'
import { Text } from '../text'

function textFromChildren (node) {
  if (node == null || node === false) return ''
  if (typeof node === 'string' || typeof node === 'number') return String(node)
  if (Array.isArray(node)) return node.map(textFromChildren).join(' ')
  if (isValidElement(node)) return textFromChildren(node.props?.children)
  return ''
}

function asId (children) {
  const t = textFromChildren(children).trim()
  if (!t) return undefined
  return t.toLowerCase().replace(/\s+/g, '-')
}

/** Map react-markdown-style `components={{ h1: fn }}` into markdown-to-jsx overrides. */
function normalizeComponentOverrides (components) {
  if (!components || typeof components !== 'object') return {}
  const out = {}
  for (const [tag, value] of Object.entries(components)) {
    if (value == null) continue
    if (typeof value === 'function') out[tag] = value
    else if (typeof value === 'object' && typeof value.component === 'function') out[tag] = value
    else out[tag] = value
  }
  return out
}

const defaultOverrides = {
  /** Drop the outer `<pre>` so fenced blocks are shaped like the old ReactMarkdown output. */
  pre: ({ children }) => <>{children}</>,

  h1: ({ children, id, ...rest }) => (
    <Text id={id || asId(children)} as="h1" variant="heading-primary" {...rest} style={{ marginBottom: 'var(--space-l)' }}>{children}</Text>
  ),
  h2: ({ children, id, ...rest }) => (
    <Text id={id || asId(children)} as="h2" variant="heading-secondary" {...rest} style={{ marginBottom: 'var(--space-m)', marginTop: 'var(--space-l)' }}>{children}</Text>
  ),
  h3: ({ children, id, ...rest }) => (
    <Text id={id || asId(children)} as="h3" variant="heading-tertiary" {...rest} style={{ marginBottom: 'var(--space-m)' }}>{children}</Text>
  ),
  h4: ({ children, id, ...rest }) => (
    <Text id={id || asId(children)} as="h4" variant="heading-tertiary" {...rest} style={{ marginBottom: 'var(--space-m)' }}>{children}</Text>
  ),
  h5: ({ children, id, ...rest }) => (
    <Text id={id || asId(children)} as="h5" variant="heading-tertiary" {...rest} style={{ marginBottom: 'var(--space-m)' }}>{children}</Text>
  ),
  p: (props) => <Text {...props} style={{ marginBottom: 'var(--space-m)' }} />,
  ul: (props) => <ul {...props} style={{ listStyle: 'inside', paddingLeft: 'var(--space-l)' }} />,
  li: (props) => <Text as="li" {...props} style={{ marginBottom: 'var(--space-m)' }} />,
  a: ({ children, href, ...rest }) => (
    <Button as={href ? 'a' : 'button'} href={href} {...rest} variant="link">{children}</Button>
  ),
  code: ({ className, children, ...props }) => {
    const m = (className || '').match(/(?:language|lang)-(\w+)/)
    const language = m ? m[1] : null
    const inline = !language

    if (inline) {
      return (
        <View inset="xs" surface="primary" roundness="s" style={{ display: 'inline-block' }} {...props}>
          <SyntaxHighlighter
            style={{
              display: 'inline',
              ...atomOneLight,
              hljs: {
                display: 'inline',
                color: '#383a42',
                background: 'transparent',
              },
            }}
            language={language}
            PreTag="span"
            {...props}
          >
            {children}
          </SyntaxHighlighter>
        </View>
      )
    }

    return (
      <View inset="m" surface="primary" roundness="m" data-component="MarkdownViewer">
        <style href="@ossy/design-system/markdown-viewer/MarkdownViewer" precedence="high">
          {`
        [data-component="MarkdownViewer"] {
          margin: var(--space-s) 0;
        }

        [data-component="MarkdownViewer"] pre {
          margin: 0;
        }
      `}
        </style>
        <SyntaxHighlighter
          style={{
            ...atomOneLight,
            hljs: {
              display: 'block',
              overflowX: 'auto',
              color: '#383a42',
              background: 'transparent',
            },
          }}
          language={language}
          {...props}
        >
          {children}
        </SyntaxHighlighter>
      </View>
    )
  },
}

function markdownString (markdown, children) {
  if (typeof markdown === 'string') return markdown
  if (typeof children === 'string') return children
  if (children == null && markdown == null) return ''
  if (Array.isArray(children) && children.every((c) => typeof c === 'string' || typeof c === 'number')) {
    return children.join('')
  }
  return String(markdown ?? children ?? '')
}

export const MarkdownViewer = ({
  markdown,
  children,
  components = {},
  ...rest
}) => {
  const source = markdownString(markdown, children)

  return (
    <Markdown
      options={{
        disableParsingRawHTML: true,
        overrides: {
          ...defaultOverrides,
          ...normalizeComponentOverrides(components),
        },
      }}
      {...rest}
    >
      {source}
    </Markdown>
  )
}
