import {ClearOutlined, UserOutlined} from '@ant-design/icons'
import {Bubble, Sender, useXAgent, useXChat, Welcome} from '@ant-design/x'
import {fetchEventSource} from '@echofly/fetch-event-source'
import {useUnmount} from 'ahooks'
import {Button, Collapse, Flex, Typography} from 'antd'
import {isStrBlank, trim} from 'licia'
import {useRef, useState} from 'react'
import styled from 'styled-components'
import {commonInfo} from '../../util/amis.tsx'
import MarkdownRender from '../../util/Markdown.tsx'

const ConversationDiv = styled.div`
    height: calc(100vh - 76px);
    display: flex;
    flex-direction: column;
    padding: 10px;

    .conversation-welcome {
        flex: 1;
        width: 70%;
        margin: 30px auto 30px;
    }

    .conversation-list {
        flex: 1;
        margin-bottom: 30px;
        padding-left: 30px;
        padding-right: 30px;
    }

    .conversation-sender {
        height: 100px;
        padding-left: 30px;
        padding-right: 30px;
    }
`

type ChatMessage = { role: string, content?: string, reason?: string }

function Conversation() {
  const abortController = useRef<AbortController | null>(null)
  const [input, setInput] = useState<string>('')

  useUnmount(() => {
    abortController.current?.abort()
  })

  const [agent] = useXAgent<ChatMessage>({
    request: async (info, callbacks) => {
      await fetchEventSource(`${commonInfo.baseAiUrl}/chat/async`, {
        method: 'POST',
        headers: commonInfo.authorizationHeaders,
        body: JSON.stringify(info.messages),
        signal: abortController.current?.signal,
        onmessage: ev => {
          callbacks.onUpdate({
            id: ev.id,
            event: 'delta',
            data: ev.data,
          })
        },
        onclose: () => callbacks.onSuccess([]),
        onerror: error => callbacks.onError(error),
      })
    },
  })
  const {onRequest, messages, setMessages} = useXChat({
    agent,
    transformMessage: ({originMessage, chunk}) => {
      let content = '', reason = ''
      try {
        if (chunk?.data) {
          let map = JSON.parse(chunk.data)
          if (map['content'])
            content = map['content']
          if (map['reason'])
            reason = map['reason']
        }
      } catch (error) {
        console.error(error)
      }
      return {
        role: 'assistant',
        content: (originMessage?.content || '') + content,
        reason: (originMessage?.reason || '') + reason,
      }
    },
    resolveAbortController: controller => {
      abortController.current = controller
    },
  })

  return (
    <ConversationDiv>
      {messages.length > 0
        ? (<Bubble.List
          className="conversation-list"
          roles={{
            assistant: {
              placement: 'start',
              avatar: {
                icon: <img src="icon.png" alt=""/>,
                style: {
                  background: 'transparent',
                },
              },
              messageRender: item => {
                let content = '', reason = ''
                if (!isStrBlank(item['reason'])) {
                  reason = trim(item['reason'])
                }
                content = trim(item['content'])
                return (
                  <div>
                    {isStrBlank(reason)
                      ? <span/>
                      : <Collapse
                        size="small"
                        defaultActiveKey={0}
                        items={[
                          {
                            key: 0,
                            label: '思考链',
                            children: (
                              <MarkdownRender content={reason}/>
                            ),
                          },
                        ]}
                      />}
                    <MarkdownRender content={content}/>
                  </div>
                )
              },
            },
            user: {
              placement: 'end',
              avatar: {
                icon: <UserOutlined/>,
              },
              messageRender: item => {
                return (
                  <Typography>{trim(item['content'])}</Typography>
                )
              },
            },
          }}
          items={messages.map(({id, message}) => {
            return {
              key: id,
              role: message.role,
              content: message,
            }
          })}
        />)
        : (<div className="conversation-welcome">
          <Welcome
            variant="borderless"
            icon={<img src="icon.png" alt="icon"/>}
            title="你好，我是基于大模型深度思考技术构建的 AI 运营助手"
            description="我可以帮你查询、检索Hudi 服务的运行情况，分析、处理 Hudi 服务的运营故障，输出、解读 Hudi 系统整体运营报告"
          />
        </div>)}
      <div className="conversation-sender">
        <Sender
          value={input}
          onChange={setInput}
          onSubmit={message => {
            onRequest({
              message: {
                role: 'user',
                content: message,
              },
              stream: true,
            })
            setInput('')
          }}
          onCancel={() => abortController.current?.abort()}
          footer={({components}) => {
            const {SendButton, LoadingButton} = components
            return (
              <Flex justify="space-between" align="center">
                <Flex gap="small" align="center">
                  <Button
                    icon={<ClearOutlined/>}
                    type="text"
                    size="small"
                    onClick={() => setMessages([])}
                  >
                    清空对话
                  </Button>
                </Flex>
                <Flex align="center">
                  {agent.isRequesting() ? (
                    <LoadingButton type="default"/>
                  ) : (
                    <SendButton type="primary" disabled={false}/>
                  )}
                </Flex>
              </Flex>
            )
          }}
          actions={false}
        />
      </div>
    </ConversationDiv>
  )
}

export default Conversation