import { Popover } from 'antd'
import styles from './style.module.css'
import { ClipboardEvent, KeyboardEvent, useCallback, useEffect, useRef, useState } from 'react'
import { promptRecommand } from '@/pages/api/base'
import * as _ from 'underscore'

interface IProps {
    height: number
    type: string
    promptChange: (value: string) => void
    value: string
    setValue: (value: string) => void
    placeholder: string
    pasteCallback: (value: string, selectionStart: number, selectionEnd: number) => void
}

interface Range {
    start: number
    end: number
    prefix: string
}

const wordRegex = /[a-zA-Z0-9'._-]/

const splitStr = ' --n '

const PromptInput = ({
    height,
    type,
    promptChange,
    value,
    setValue,
    placeholder,
    pasteCallback,
}: IProps) => {
    const [promptRecommands, setPromptRecommands] = useState<string[]>([])
    const [focus, setFocus] = useState(false)
    const prefixRef = useRef('')
    const textAreaRef = useRef<HTMLTextAreaElement>(null)
    const pasteEvent = useRef(false)

    const handlePaste = (event: ClipboardEvent<HTMLTextAreaElement>) => {
        const input = event.target as HTMLTextAreaElement
        const selectedText = input.value.substring(input.selectionStart, input.selectionEnd)
        const clipboardData = event.clipboardData
        const pastedText = clipboardData.getData('text/plain') as string
        if (pastedText.includes(splitStr)) {
            pasteEvent.current = type.includes('positive')
                ? selectedText != pastedText.split(splitStr)[0]
                : selectedText != pastedText.split(splitStr)[1]
            // 阻止默认粘贴行为
            event.preventDefault()
            const selectionStart = input.selectionStart
            const selectionEnd = input.selectionEnd
            pasteCallback(pastedText, selectionStart, selectionEnd)
        } else {
            pasteEvent.current = selectedText != pastedText
        }
    }

    const recommand = async (prefix: string) => {
        prefixRef.current = prefix
        const data = { prefix: prefix, noShowToast: true }
        const recommands = (await promptRecommand(data)) ?? []
        setPromptRecommands(recommands)
    }

    const prefixChange = useCallback(
        _.debounce((prefix: string) => {
            recommand(prefix)
        }, 100),
        [],
    )

    const replaceRecommend = (word: string) => {
        const element = textAreaRef.current
        if (element) {
            const value = element.value
            const index = element.selectionEnd
            const range = findIndexWordRange(value, index)
            if (range && range.prefix == prefixRef.current) {
                const { start, end } = range
                const addStr = ''
                const replace = `${value.slice(0, start)}${word}${addStr}${value.slice(
                    end,
                    value.length,
                )}`
                element.value = replace
                element.selectionEnd = start + word.length + addStr.length
                element.focus()
                setValue(replace)
            } else {
                element.focus()
            }
            setTimeout(() => {
                setPromptRecommands([])
            }, 5)
        }
    }

    const promptRecommandRequest = () => {
        if (pasteEvent.current) {
            pasteEvent.current = false
            return
        }
        const element = textAreaRef.current
        if (element) {
            const value = element.value
            const index = element.selectionEnd
            const range = findIndexWordRange(value, index)
            if (range) {
                prefixChange(range.prefix)
                return
            }
        }
        setPromptRecommands([])
    }

    useEffect(() => {
        if (!focus) {
            const timerId = setTimeout(() => {
                setPromptRecommands([])
            }, 800)
            return () => {
                clearTimeout(timerId)
            }
        }
    }, [focus])

    useEffect(() => {
        const element = document.getElementById(`${type}-recommend-0`)
        if (element) {
            element.scrollIntoView()
        }
    }, [promptRecommands])

    const findIndexWordRange = (str: string, index: number): Range | null => {
        let start: number | null = null
        for (let i = 0; i < str.length; i++) {
            if (start == null) {
                // 如果当前字符是字母或数字，则设置起始索引
                if (wordRegex.test(str[i])) {
                    start = i
                }
            } else {
                // 如果当前字符不是字母或数字，则将前一个区间添加到结果中，并重新设置起始索引
                if (!wordRegex.test(str[i])) {
                    if (i >= index && index >= start) {
                        return { start: start, end: i, prefix: str.substring(start, i) }
                    }
                    start = null
                }
            }
        }
        if (start != null) {
            return { start: start, end: str.length, prefix: str.substring(start, str.length) }
        }
        return null
    }

    const [indexRecommand, setIndexRecommand] = useState(0)

    useEffect(() => {
        setIndexRecommand(0)
    }, [promptRecommands])

    const handleKeyDown = (e: KeyboardEvent<HTMLTextAreaElement>) => {
        //mac下中文输入法的enter也会响应enter，所以需要isComposing判断
        if (promptRecommands.length && !e.nativeEvent.isComposing) {
            if (e.key === 'ArrowUp') {
                if (indexRecommand > 0) {
                    setIndexRecommand(indexRecommand - 1)
                } else {
                    setIndexRecommand(0)
                }
                e.preventDefault()
            } else if (e.key === 'ArrowDown') {
                if (indexRecommand < promptRecommands.length - 1) {
                    setIndexRecommand(indexRecommand + 1)
                } else {
                    setIndexRecommand(promptRecommands.length - 1)
                }
                e.preventDefault()
            } else if (e.key == 'Enter') {
                if (indexRecommand >= 0 && indexRecommand < promptRecommands.length) {
                    replaceRecommend(promptRecommands[indexRecommand])
                }
                e.preventDefault()
            }
        }
    }

    useEffect(() => {
        if (indexRecommand >= 0) {
            const element = document.getElementById(`${type}-recommend-${indexRecommand}`)
            if (element) {
                element.scrollIntoView({ behavior: 'smooth' })
            }
        }
    }, [indexRecommand])

    return (
        <Popover
            transitionName=""
            open={!!promptRecommands.length}
            arrow={false}
            placement="rightTop"
            overlayClassName={styles.popoverRecommendWrapper}
            content={
                <div className={styles.popoverRecommendList}>
                    {promptRecommands.map((item, index) => (
                        <div
                            key={index}
                            className={`ag14 ${styles.popoverRecommendItem} ${
                                indexRecommand === index ? styles.popoverRecommendItemIndexed : ''
                            }`}
                            id={`${type}-recommend-${index}`}
                            onClick={() => {
                                replaceRecommend(item)
                            }}
                        >
                            <span>{item}</span>
                            {indexRecommand === index ? (
                                <div className={styles.popoverRecommendBorder}></div>
                            ) : null}
                        </div>
                    ))}
                </div>
            }
        >
            <textarea
                key={`positivelyTextarea`}
                ref={textAreaRef}
                placeholder={placeholder}
                className={`${styles.textarea} ag16`}
                style={{ height: `${height}px` }}
                value={value}
                onBlur={() => {
                    promptChange(value)
                    setFocus(false)
                }}
                onFocus={() => {
                    setFocus(true)
                }}
                onChange={(e) => {
                    setValue(e.target.value)
                    promptRecommandRequest()
                }}
                onKeyDown={handleKeyDown}
                onPaste={handlePaste}
            ></textarea>
        </Popover>
    )
}

export default PromptInput
