import React, { RefObject } from "react";
import { tools } from "../utils/shell/tools";
import { Editor, Toolbar } from '@wangeditor/editor-for-react'
import '@wangeditor/editor/dist/css/style.css'
import { IDomEditor, ISelectMenu } from '@wangeditor/editor'
import { Button, Popconfirm, Select, Switch, Tooltip, message } from "antd";
import Input from "antd/lib/input/Input";
import Html from "./Html";
import ErrorBoundary from "./ErrorBound";





// 转化旧文本的key
const TRANSLATEKEY = 'TRANSLATEOLD'
// 转化旧文本的key
const TRANSLATERULESKEY = 'TRANSLATERULES'

interface SingleTemplate {
  name: string;
  htmlTemp: TreeNode[];
}
interface TranslateRules {
  lastActiveRule: string;
  showEmpty: boolean;
  templates: SingleTemplate[]
}
interface Props {
  disabled?: boolean;
  readOnly?: boolean;
  model?: string; //实际是value，用来显示值
  onRef?: (ref: any) => void;
  onModelChange?: (value: string) => void;
  placeholder?: string;
  onBlur?: () => void;
  onFocus?: () => void;
  name?: string;
}


const onlyNumberReg = /^[-+]?\d+(\.\d+)?$/
const onlyPriceReg = /[¥$€元][-+]?\d*(\.\d+)?/

// 文本内的字符情况 为了之后匹配行的时候进行使用 分别为 纯文本 纯数字 纯价格 混合
// 判断的时候纯价格要先行计算 之后再试纯文本 纯数字 最后是混合
type TextType = 'pureText' | 'pureNumber' | 'purePrice' | 'multiple';

interface TreeNode {
  nodeType: string; // 节点类型
  children: TreeNode[]; // 子代
  originText?: string;// 格式化的时候的原始文本
  originTextWidth?: number; // 格式化的时候的原始文本长度
  bold?: boolean; // 是否加粗
  underLine?: boolean; // 是否有下划线
  textFont?: string; // 文本字体
  textSize?: string; // 文本大小
  color?: string; // 文本颜色
  bgColor?: string; // 背景颜色
  textLineHeight?: string; // 文本行高
  textAlign?: string; // 文本位置
  lockOriginText?: string; // 锁定原文本
  textIndent?: string; // 缩进
  preWhiteSpceCount?: number, // 前空格计数
  afterWhiteSpceCount?: number, // 后空格计数
  textType?: TextType//文本类型
  [key: string]: any; // 还有其他的暂时没想到
}



class RichText extends React.Component<Props>{
  protected editorRef: RefObject<HTMLDivElement> = React.createRef<HTMLDivElement>();;
  protected editor: any | null;
  static defaultProps = {
    disabled: false,
    readOnly: false
  };
  state: { editor: IDomEditor | null, selectTempLate: string, originModel: string, templateName: string, clickCount: number, showEmpty: boolean } = {
    editor: null,
    originModel: '',
    clickCount: 0,
    selectTempLate: JSON.parse(localStorage.getItem(TRANSLATERULESKEY) as string)?.lastActiveRule,
    templateName: JSON.parse(localStorage.getItem(TRANSLATERULESKEY) as string)?.lastActiveRule,
    showEmpty: JSON.parse(localStorage.getItem(TRANSLATERULESKEY) as string)?.showEmpty,
  }
  watchInput = (e: any) => {
    if (e.code === 'KeyE')
      this.setState({ clickCount: this.state.clickCount + 1 })
    if (this.state.clickCount > 3) {
      localStorage.setItem(TRANSLATEKEY, '1')
    }
  }
  componentDidMount(): void {
    this.setState({ originModel: this.props.model })
    document.addEventListener('keydown', this.watchInput)
    window.editorInstance = this
  }
  edit = false;

  componentWillUnmount(): void {
    document.removeEventListener('keydown', this.watchInput)
  }
  componentDidUpdate(prevProps: Readonly<Props>, prevState: Readonly<{}>, snapshot?: any): void {
  }


  FontList = [
    { name: '小六(6.5)', value: '8px' },
    { name: '六号(7.5)', value: '10px' },
    { name: '小五(9)', value: '12px' },
    { name: '五号(10.5)', value: '14px' },
    { name: '小四(12)', value: '16px' },
    { name: '四号(14)', value: '18px' },
    { name: '小三(15)', value: '20px' },
    { name: '三号(16)', value: '21px' },
    { name: '小二(18)', value: '24px' },
    { name: '二号(22)', value: '29px' },
    { name: '小一(24)', value: '32px' },
    { name: '一号(26)', value: '34px' },
    { name: '小初(36)', value: '48px' },
    { name: '初号(42)', value: '59px' },
    '13px',
    '15px',
    '19px',
    '22px',
    '40px',
    { name: '10', value: '10pt' },
    { name: '30', value: '30pt' },
    { name: '50', value: '50pt' },
    { name: '70', value: '70pt' },
  ]

  strToHtmlEl(str: string): HTMLDivElement {
    const div = document.createElement('div');
    div.innerHTML = str;
    return div
  }

  templateStr: string

  structuralTextDataToDescripbe(htmlStr: string, templateName: string) {
    const structuralData = this.structuralTextData(htmlStr)
    const alignDescribe = { 'start': '居左', 'center': '居中', right: '居右' }
    let describe = `${templateName}\n`
    structuralData.map((_, index) => {
      let pText = `第${index + 1}行 ${_.textAlign ? ('文本位置：' + alignDescribe[_.textAlign || '']) : ''} 行高：${_.textLineHeight || '1'} ${_.textIndent ?? `缩进${_.textIndent}`}\n`
      _.children.map((text, textIndex) => {
        const textStr = ` 第${textIndex + 1}部分 字体:${text.textFont || '平台默认字体'} 字号:${text.textSize || '平台字号'} ${text.bold ? '加粗' : ''} ${text.underLine ? '下划线' : ''} 颜色:${text.color || '默认颜色'} 文字前空格：${text.afterWhiteSpceCount || 0}  文字后空格：${text.preWhiteSpceCount || 0} 原文字:${text.originText} |`

        pText += textStr + '\t'
      })
      pText += '\n'
      describe += pText
    })
    return describe
  }

  // 结构化富文本数据
  structuralTextData(htmlStr: string) {
    const rootEl = this.strToHtmlEl(htmlStr)
    const structChildTextNodeData = (childNodes: NodeListOf<ChildNode>): TreeNode[] => {
      const children = Array.from(childNodes)
      const treeArr: TreeNode[] = []
      // 文本节点
      children.map((_: HTMLElement) => {
        const textContent = _.textContent
        const nodeName = _.nodeName
        const defaultAttr: TreeNode = {
          nodeType: 'text',
          children: [],

        }
        const textArr = []
        // 如果中间有空格 - 分为多块
        if (textContent?.trim().split(' ') && !/^\s+$/.test(textContent)) {
          textArr.push(...textContent?.trim().split(/\s+/))
        } else {
          textArr.push(_)
        }
        textArr.map((childtext: string | HTMLElement, index) => {
          const whiteSpaceArr = String(_.textContent)?.trim().match(/\s+/g) || []
          const textContent: string = (childtext as HTMLElement).textContent || childtext as string
          // 如果是被拆分的空字符串就不用走
          if (!String(textContent)?.trim?.() && typeof childtext === 'string') return
          const attr = { ...defaultAttr }
          // 如果不是纯文本节点
          if (nodeName !== '#text') {
            const textStyle = _.style
            // 是否粗体
            attr.bold = _.innerHTML.includes('\<strong\>')
            // 是否下划线
            attr.underLine = _.innerHTML.includes('\<u\>')
            //文本字体
            attr.textFont = textStyle.fontFamily
            //文本大小
            attr.textSize = textStyle.fontSize
            //文本颜色
            attr.color = textStyle.color
            //背景颜色
            attr.bgColor = textStyle.backgroundColor
            // 元字符长度
            attr.originTextWidth = textContent?.length || 0
            attr.originText = typeof textContent === 'string' ? (textContent || '') : ''
            //前空格 能直接使用 whiteSpaceArr?.shift() 是因为去掉了首尾空格计算的 故 whiteSpaceArr必定是中间 的
            attr.preWhiteSpceCount = index === 0 ? _?.textContent?.match(/^\s+/g)?.[0]?.length : (whiteSpaceArr?.shift()?.length || 0)
            attr.afterWhiteSpceCount = (index === textArr.length - 1) ? _?.textContent?.match(/\s+$/g)?.[0]?.length : 0
            //文本类型
            if (onlyNumberReg.test(textContent?.trim?.() || ''))
              attr.textType = 'pureNumber'
            if (onlyPriceReg.test(textContent?.trim?.() || ''))
              attr.textType = 'purePrice'
          }

          treeArr.push(attr)
        })
      })
      const validResult: TreeNode[] = []
      // 前格式剩下的白字符
      let preRestWhite = 0
      treeArr.map(_ => {
        // 如果前面是纯空串
        if (/^\s+$/.test(_.originText || '')) {
          preRestWhite += _.originText?.length || 0
        } else {
          //遇到第一个有文本的内容就进行合并
          // 白字符合并
          _.preWhiteSpceCount = (_.preWhiteSpceCount || 0) + preRestWhite
          preRestWhite = 0
          validResult.push(_)
          // 如果有后空字符串 加入剩下的白字符串
          if (_.afterWhiteSpceCount) {
            preRestWhite += _.afterWhiteSpceCount
          }
        }
      })
      return validResult
    }
    // 结构树
    const structTree: TreeNode[] = []
    // 第一层 段落节点
    // 仅有段落功能可以使用
    Array.from(rootEl.children).map((_: HTMLElement) => {
      const ComputedStyle = _.style
      structTree.push({
        nodeType: 'P',
        textLineHeight: ComputedStyle.lineHeight,
        textAlign: ComputedStyle.textAlign,
        textIndent: ComputedStyle.textIndent,
        children: structChildTextNodeData(_.childNodes)
      })
    })
    return structTree
  }
  transFormatToHtml(ruleName: string, textTree?: string[][], showEmpty = true): string {
    const translateRuelsStorage: TranslateRules = JSON.parse(localStorage.getItem(TRANSLATERULESKEY) as string)
    const template = translateRuelsStorage.templates.find(_ => _.name === ruleName)
    const rootEl = this.strToHtmlEl('')
    let colorIndex = 0
    const ColorArr = textTree ? [''] : ['#a1c4fd', '#d4fc79', '#f5576c', '#fa71cd', '#008080', '#9B59B6', '#03A9F4']
    // 第一行段落
    // 如果是单行的 特殊处理下，根据模板数量自动补齐
    if (textTree?.length === 1) {
      const curTextTree: string[][] = []
      template?.htmlTemp.map(_ => {
        curTextTree.push(textTree?.[0]?.splice(0, _?.children?.length) || [])
      })
      textTree = curTextTree
    }
    template?.htmlTemp.map((pEl, index) => {
      const p = document.createElement('p');
      p.style.lineHeight = pEl.textLineHeight || ''
      p.style.textAlign = pEl.textAlign || ''
      p.style.textIndent = pEl.textIndent || ''
      p.style.margin = '0px'
      pEl.children.map((textChildren, childIndex) => {
        let lastChildEl
        const span = document.createElement('span');
        lastChildEl = span
        // 按照 下划线 粗体 来进行字体添加
        if (textChildren.underLine) {
          const tempEL = document.createElement('u')
          lastChildEl.append(tempEL)
          lastChildEl = tempEL
        }
        if (textChildren.bold) {
          const tempEL = document.createElement('strong')
          lastChildEl.append(tempEL)
          lastChildEl = tempEL
        }
        // 设置文本 如果展示空值 就显示预留文本-如果指定原值展示 就展示原值
        const showText = `${new Array(textChildren.preWhiteSpceCount).fill('&nbsp;').join('')}${(!textChildren.lockOriginText ? textTree?.[index]?.[childIndex] : textChildren.originText) || ''}`
        lastChildEl.innerHTML = showEmpty ? (textTree?.[index]?.[childIndex] ? showText : `组${childIndex + 1}：${new Array(textChildren.preWhiteSpceCount).fill('&nbsp;').join('')}${textChildren.originText || ''}`) : showText
        span.style.fontFamily = textChildren.textFont || ''
        span.style.fontSize = textChildren.textSize || ''
        span.style.color = textChildren.color || ''
        span.style.backgroundColor = textChildren.bgColor || ColorArr[colorIndex]
        colorIndex++
        if (colorIndex > ColorArr.length) colorIndex = 0
        p.append(span)
      })
      // 把剩下的加上去
      if ((textTree?.[index]?.length || 0) > pEl.children.length) {
        const lastChild = p.lastChild as HTMLElement
        if (lastChild?.innerText)
          lastChild.innerText += textTree?.[index].slice(pEl.children.length).join('') || ''
      }
      rootEl.appendChild(p)
    })
    return rootEl.innerHTML
  }
  // 手动添加样式
  addMarginToParagraphs(htmlText: string) {
    // 创建一个临时div元素，用于将 HTML 文本解析为 DOM 树
    const tempDiv = this.strToHtmlEl(htmlText)

    // 获取所有的 <p> 标签
    const paragraphs = tempDiv.querySelectorAll('p');

    // 遍历所有的 <p> 标签，为它们添加 margin: 0; 属性
    for (let i = 0; i < paragraphs.length; i++) {
      paragraphs[i].style.margin = '0';
    }

    // 返回修改后的 HTML 字符串
    return tempDiv.innerHTML;
  }
  // 装换editor的文本
  transFromEditor() {
    const editorText = this.state.editor?.getHtml()
    // 获取editor文本
    const editorEl = this.strToHtmlEl(editorText || '')

    // 文本树
    const textTree: any = []
    const children = Array.from(editorEl.childNodes)
    // 根据段落进行划分
    children.map((_, index) => {
      const pTree: any[] = []
      if (!_?.textContent?.includes('|')) {
        Array.from(_.childNodes).map(text => {
          const textArea: string[] = []
          const textContent = text?.textContent
          // 前后空行都去掉
          // if (!textContent?.trim() && !children[index - 1]?.textContent?.trim()) return
          // 纯空字符串不使用
          if (/^\s+$/.test(textContent || '')) return
          // 如果中间有空格-分为多块
          if (textContent?.trim().split(' ') && !/^\s+$/.test(textContent)) {
            textArea.push(...textContent?.trim().split(/\s+/))
          } else {
            textArea.push(textContent || '')
          }
          pTree.push(...textArea)
        })
      } else {
        pTree.push(..._?.textContent?.split('|') || [])
      }
      // 推入段落
      textTree.push(pTree)
    })
    // 前面是空行的情况全部去除
    while (textTree[0].length === 1 && !textTree[0][0]) {
      textTree.shift()
    }

    // 末尾非文字的空行的情况全部去除
    while (textTree[textTree.length - 1].length === 1 && !textTree[textTree.length - 1][0]) {
      textTree.pop()
    }
    console.log(textTree)

    this.props.onModelChange?.(this.transFormatToHtml(this.state.selectTempLate, textTree, this.state.showEmpty))
  }
  render() {
    const { model, onModelChange, readOnly, disabled, onRef } = this.props
    let cls = "rich-text-editor keyDownClass";
    this.props.readOnly && (cls += ' readOnly');
    this.props.disabled && (cls += ' disabled');
    const showTranslateButton = localStorage.getItem(TRANSLATEKEY)
    const defaultRules = { lastActiveRule: '', showEmpty: false, templates: [] }
    let translateRuelsStorage: TranslateRules = defaultRules
    if (showTranslateButton) {
      translateRuelsStorage = JSON.parse(localStorage.getItem(TRANSLATERULESKEY) as string)
      if (!translateRuelsStorage) {
        localStorage.setItem(TRANSLATERULESKEY, JSON.stringify(defaultRules))
        translateRuelsStorage = defaultRules
      }
    }
    return <>
      {showTranslateButton ? <div style={{ position: 'absolute', zIndex: 1, bottom: 0, right: 0 }}>
        <Button onClick={() => { this.setState({ clickCount: 0 }); localStorage.removeItem(TRANSLATEKEY) }}>隐藏</Button>

        <Popconfirm okText="确定" cancelText="取消" title={() => {
          return <Html html={this.transFormatToHtml(this.state.selectTempLate)}></Html>
        }}>
          <Button onClick={() => console.log(
            this.transFormatToHtml(this.state.selectTempLate)
          )}>预览</Button>
        </Popconfirm>

        <Button onClick={async () => {
          // 检查浏览器是否支持 Clipboard API
          if (!navigator.clipboard) {
            message.error('不支持复制到剪切板');
            return;
          }
          await navigator.clipboard.writeText(localStorage.getItem(TRANSLATERULESKEY) || '');
          message.success('导出成功,ctrl+v粘贴使用')
        }}>导出</Button>
        <Popconfirm okText="确定" cancelText="取消" onConfirm={() => {
          const translaterules: TranslateRules = JSON.parse(localStorage.getItem(TRANSLATERULESKEY) as string)
          const copyRule: TranslateRules = JSON.parse(this.templateStr)
          if (!this.templateStr || typeof copyRule !== 'object' || !copyRule.templates) return message.warn('模板不合法')
          // 合并操作
          translaterules.templates = [...translaterules.templates, ...copyRule.templates]
          const ruleMap = {}
          // 去除重复名字
          translaterules.templates.map(_ => {
            ruleMap[_.name] = _
          })
          translaterules.templates = Object.values(ruleMap)
          localStorage.setItem(TRANSLATERULESKEY, this.templateStr)
        }} title={() => {
          return <Input onChange={(e) => {
            this.templateStr = e.target.value
          }} placeholder="请输入导出时复制的模板"></Input>
        }}>
          <Button>导入</Button>
        </Popconfirm>
        <Tooltip overlay={() => {
          return <div>
            {`${translateRuelsStorage.showEmpty ? '保留空值' : '过滤空值'}，可以在文本中加入|符号进行手工分段，分段样式参照模板预览`}
            {/* <Switch title="是否过滤空值" checked={this.state.showEmpty} onChange={() => {
              this.setState({ showEmpty: !this.state.showEmpty })
              translateRuelsStorage.showEmpty = !translateRuelsStorage.showEmpty
              localStorage.setItem(TRANSLATERULESKEY, JSON.stringify(translateRuelsStorage))
            }}></Switch> */}
          </div>
        }}>
          <Button onClick={() => this.transFromEditor()}>应用模板</Button>
        </Tooltip>
        <Popconfirm title={() => {
          return <div>
            请输入模板名
            <Input style={{
              position: 'relative',
              marginTop: '8px',
              left: '-22px'
            }} value={this.state.templateName} onChange={e => { this.setState({ templateName: e.target.value }) }}></Input>
          </div>
        }} okText="确定" onConfirm={() => {
          const templateIndex = translateRuelsStorage.templates.findIndex(_ => _.name === this.state.templateName)
          const template = {
            name: this.state.templateName,
            htmlTemp: this.structuralTextData(this.state.editor?.getHtml() || ''),
          }
          if (templateIndex >= 0) {
            translateRuelsStorage.templates[templateIndex] = template
          } else {
            translateRuelsStorage.templates.push(template)
          }

          localStorage.setItem(TRANSLATERULESKEY, JSON.stringify(translateRuelsStorage))
          this.setState({ selectTempLate: this.state.templateName })
        }} cancelText="取消">
          <Button>抽出模板</Button>
        </Popconfirm>
        <Popconfirm title="是否确认删除模板" okText="确定" cancelText="取消"
          onConfirm={() => {
            const curTempIndex = translateRuelsStorage.templates.findIndex(_ => _.name === this.state.selectTempLate)
            if (curTempIndex >= 0) {
              translateRuelsStorage.templates.splice(curTempIndex, 1)
              localStorage.setItem(TRANSLATERULESKEY, JSON.stringify(translateRuelsStorage))
              this.setState({ selectTempLate: translateRuelsStorage.templates[0].name, templateName: translateRuelsStorage.templates[0].name })
            }
          }}
        >

          <Button >删除选中模板</Button>
        </Popconfirm>
        <Select style={{ width: '150px' }} value={this.state.selectTempLate || "请选择模板，无模板请抽出模板"} onChange={(value) => {
          translateRuelsStorage.lastActiveRule = value
          this.setState({ selectTempLate: value, templateName: value })
          localStorage.setItem(TRANSLATERULESKEY, JSON.stringify(translateRuelsStorage))
        }} placeholder="请选择模板，无模板请抽出模板" options={translateRuelsStorage.templates.map(_ => ({ lable: _.name, value: _.name })) || []
        }></Select></div> : null}
      <ErrorBoundary errorText="富文本无法解析，请联系开发人员">
        <div className={cls} style={{ position: 'relative' }} ref={this.editorRef} onTouchMove={e => e.stopPropagation()} >
          <Toolbar
            className="email-edit-content-body-toolbar"
            editor={this.state.editor}
            mode="simple"
            defaultConfig={{
              toolbarKeys: ['undo', 'redo', '|', 'fontFamily', 'fontSize', 'lineHeight', '|',
                'underline', 'italic', 'color', "bgColor",
                "indent", "delIndent", '|',
                'bulletedList', 'numberedList', 'justifyLeft', 'justifyRight', 'justifyCenter',]
            }}
          />
          <Editor
            className="email-edit-content-body-editor"
            defaultConfig={{
              hoverbarKeys: {
                text: {
                  menuKeys: ['fontFamily', 'fontSize', 'lineHeight', '|',
                    'underline', 'italic', 'color', "bgColor",
                    "indent", "delIndent", '|',
                    'justifyLeft', 'justifyRight', 'justifyCenter',]
                }
              },
              MENU_CONF: {
                fontFamily: {
                  fontFamilyList: [
                    "黑体",
                    "仿宋",
                    "楷体",
                    "标楷体",
                    "华文仿宋",
                    "华文楷体",
                    "宋体",
                    "微软雅黑",
                    "Arial",
                    "Tahoma",
                    "Verdana",
                    "Times New Roman",
                    "Courier New",
                    "思源黑体 CN Bold",
                    "思源黑体 CN Heavy",
                    "思源黑体 CN Medium",
                    "思源黑体 CN Normal",
                    "思源黑体 CN Regular",
                    "si"
                  ]
                },
                fontSize: {
                  fontSizeList: this.FontList,
                },
                lineHeight: {
                  lineHeightList: ['0', '0.125', '0.25', '0.375', '0.5', '0.75', '1', '1.25', '1.5', '1.75', '2', '2.25', '2.5', '5pt', '10pt', '15pt', '20pt', '25pt', '30pt', '35pt', '40pt']
                }
              },
              readOnly: readOnly || disabled
            }}
            mode="default"
            value={model}
            onCreated={(editor) => {
              this.state.editor?.getAllMenuKeys()
              editor.setHtml(model || '')
              this.setState({ editor: editor })
            }}
            onChange={(editor) => {
              onModelChange?.(this.addMarginToParagraphs(editor.getHtml()))
              onRef && onRef(editor)
            }}
          />
        </div >
      </ErrorBoundary>

    </>

  }
}

export default RichText
