import { ComponentProps } from 'react'
import { MessageFormatOptions, MessageFormatPart } from './chatUtils'
import './MessageFormatted.css'

export const MessagePart = ({ part, formatOptions, ...props }: { part: MessageFormatPart, formatOptions?: MessageFormatOptions } & Pick<ComponentProps<'span'>, 'style' | 'className' | 'children'>) => {

  const { color: _color, italic, bold, underlined, strikethrough, text, clickEvent, hoverEvent, obfuscated } = part
  const color = _color ?? 'white'

  const applyStyles = [
    colorF(color.toLowerCase()) + ((formatOptions?.doShadow ?? true) ? `; text-shadow: 1px 1px 0px ${getColorShadow(colorF(color.toLowerCase()).replace('color:', ''))}` : ''),
    italic && messageFormatStylesMap.italic,
    bold && messageFormatStylesMap.bold,
    italic && messageFormatStylesMap.italic,
    underlined && messageFormatStylesMap.underlined,
    strikethrough && messageFormatStylesMap.strikethrough,
    obfuscated && messageFormatStylesMap.obfuscated
  ].filter(a => a !== false && a !== undefined).filter(Boolean)

  return <span style={parseInlineStyle(applyStyles.join(';'))} {...props}>{text}</span>
}

export default ({ parts, className, formatOptions }: { parts: readonly MessageFormatPart[], className?: string, formatOptions?: MessageFormatOptions }) => {
  return (
    <span className={`formatted-message ${className ?? ''}`}>
      {parts.map((part, i) => <MessagePart key={i} part={part} formatOptions={formatOptions} />)}
    </span>
  )
}

const colorF = (color) => {
  return color.trim().startsWith('#') ? `color:${color}` : messageFormatStylesMap[color] ?? undefined
}

export function getColorShadow (hex, dim = 0.25) {
  const color = parseInt(hex.replace('#', ''), 16)

  const r = Math.trunc((color >> 16 & 0xFF) * dim)
  const g = Math.trunc((color >> 8 & 0xFF) * dim)
  const b = Math.trunc((color & 0xFF) * dim)

  const f = (c) => ('00' + c.toString(16)).slice(-2)
  return `#${f(r)}${f(g)}${f(b)}`
}

export function parseInlineStyle (style: string): Record<string, any> {
  const obj: Record<string, any> = {}
  for (const rule of style.split(';')) {
    const [prop, value] = rule.split(':')
    const cssInJsProp = prop.trim().replaceAll(/-./g, (x) => x.toUpperCase()[1])
    obj[cssInJsProp] = value.trim()
  }
  return obj
}

export const messageFormatStylesMap = {
  black: 'color:color(display-p3 0 0 0)',
  dark_blue: 'color:color(display-p3 0 0 0.6667)',
  dark_green: 'color:color(display-p3 0 0.6667 0)',
  dark_aqua: 'color:color(display-p3 0 0.6667 0.6667)',
  dark_red: 'color:color(display-p3 0.6667 0 0)',
  dark_purple: 'color:color(display-p3 0.6667 0 0.6667)',
  gold: 'color:color(display-p3 1 0.6667 0)',
  gray: 'color:color(display-p3 0.6667 0.6667 0.6667)',
  dark_gray: 'color:color(display-p3 0.3333 0.3333 0.3333)',
  blue: 'color:color(display-p3 0.3333 0.3333 1)',
  green: 'color:color(display-p3 0.3333 1 0.3333)',
  aqua: 'color:color(display-p3 0.3333 1 1)',
  red: 'color:color(display-p3 1 0.3333 0.3333)',
  light_purple: 'color:color(display-p3 1 0.3333 1)',
  yellow: 'color:color(display-p3 1 1 0.3333)',
  white: 'color:color(display-p3 1 1 1)',
  bold: 'font-weight:900',
  strikethrough: 'text-decoration:line-through',
  underlined: 'text-decoration:underline',
  italic: 'font-style:italic',
  obfuscated: 'filter:blur(2px)',
  clickEvent: 'cursor:pointer',
}
