import React, { useCallback, useEffect, useRef, useState } from 'react'

import {
  Anchor,
  Box,
  Button,
  Flex,
  Group,
  Stack,
  Text,
  Textarea
} from '@mantine/core'
import { IconSend } from '@tabler/icons-react'
import { throttle } from 'lodash'

// import { eventTracking } from 'dbaas/utils/tracking'

// import { Feedback, useFeedback } from '../Feedback'
import { LinguflowMsgWithInteractionId, sendLinguflowMsg } from './api'
import {
  ActionMessage,
  AssistantMessage,
  TipsMessage,
  UserMessage
} from './Messages/Messages'
import './Messages/Messages.module.css'
import { Message } from './Messages/useMessages'

const PRESET_MESSAGE = [
  'List clusters with a version less than "v7.1.1". Include cluster id, cluster name, tenant id, tenant name, and version fields.',
  'How many TiDB instances are there in clusterid 1379661944646413143?',
  'What are the differences in TiDB variables between clusters 1379661944646413143 and 1379661944646413655?'
]
const INPUT_LIMIT = 600
const MAGIC_MIRROR_APP_ID = '55efc784-160e-49fd-afa5-f91b80eee96f'

export const MigicMirrorChats: React.FC = () => {
  const [isSendingMessage, setIsSendingMessage] = useState(false)
  const [isStreamLoading, setIsStreamLoading] = useState(false)
  const [error, setError] = useState<any>(null)
  const messagesRef = useRef<HTMLDivElement>(null)
  const [scrollToBottom, setScrollToBottom] = useState(true)
  const releaseScroll = () => {
    const canReleaseScroll =
      messagesRef.current?.scrollHeight! -
        messagesRef.current?.offsetHeight! -
        messagesRef.current?.scrollTop! >
      10
    setScrollToBottom(!canReleaseScroll)
  }
  // for throttle
  // eslint-disable-next-line react-hooks/exhaustive-deps
  const throttleReleaseScroll = useCallback(throttle(releaseScroll, 100), [])
  // eslint-disable-next-line react-hooks/exhaustive-deps
  const scrollToLastMessage = useCallback(
    throttle(
      ({
        scrollToBottom,
        force = false,
        delay = 100
      }: {
        scrollToBottom: boolean
        force?: boolean
        delay?: number
      }) => {
        if (!scrollToBottom && !force) {
          return
        }
        setTimeout(
          () =>
            messagesRef.current?.scroll({
              top: Number.MAX_SAFE_INTEGER,
              behavior: (force ? 'instant' : 'smooth') as ScrollBehavior
            }),
          delay
        )
      },
      100
    ),
    []
  )
  const [messages, setMessages] = useState<Message[]>([])
  const clearMessages = () => {
    setMessages([])
  }
  const sendMessage = async (m: string, regenerate = false) => {
    if (
      (m === '' || isSendingMessage || isStreamLoading || !!error) &&
      !regenerate
    ) {
      return false
    }

    if (!regenerate) {
      setMessages((msgs) => [
        ...msgs,
        {
          displayed: {
            role: 'user',
            content: m
          }
        }
      ])
    }
    setIsSendingMessage(true)

    scrollToLastMessage({ scrollToBottom, force: true })
    let res: LinguflowMsgWithInteractionId
    try {
      res = await sendLinguflowMsg(
        MAGIC_MIRROR_APP_ID,
        regenerate
          ? [...messages.map((m) => m.displayed.content!)]
          : [...messages.map((m) => m.displayed.content!), m]
      )
    } catch (e) {
      setIsSendingMessage(false)
      setError(e)
      return false
    }
    setMessages((msgs) => [
      ...msgs,
      {
        currentId: res.interactionId,
        displayed: {
          role: 'assistant',
          content: res.msg
        }
      }
    ])
    scrollToLastMessage({ scrollToBottom, force: true })
    setIsSendingMessage(false)
    return true
  }
  const newSession = () => {
    clearMessages()
    setError(null)
  }

  const scrollWhenInit = useRef(() =>
    scrollToLastMessage({ scrollToBottom, force: true, delay: 0 })
  )
  useEffect(() => {
    scrollWhenInit.current()
  }, [])

  const isSendMessageReady = !isSendingMessage
  const isSendMessageDisabled = !!error

  const PresetMessages = (
    <Stack spacing='xs'>
      {PRESET_MESSAGE.map((m) => (
        <ActionMessage
          key={m}
          onClick={() => {
            if (!isSendMessageReady || isSendMessageDisabled) {
              return
            }
            sendMessage(m)
            // eventTracking('Clicked TiDB Bot preset question', { question: m })
          }}
        >
          {m}
        </ActionMessage>
      ))}
    </Stack>
  )

  const GeneratingTips = (
    <TipsMessage>
      <Text miw={105} c='gray.5' className='ai-loading'>
        AI Generating...
      </Text>
    </TipsMessage>
  )

  const regenerate = () => {
    setError(null)
    const lastUserMsg = messages.filter((m) => m.displayed.role === 'user')[0]

    sendMessage(lastUserMsg.displayed.content!, true)
  }
  const RegenerateTips = (
    <TipsMessage>
      <Text>
        Sorry, the OpenAI server has reached the rate limit for now. Please try
        again later by clicking on "
        <Anchor onClick={regenerate}>Regenerate</Anchor>".
      </Text>
    </TipsMessage>
  )

  return (
    <Stack spacing={0} h='100%' w='100%'>
      <Flex
        ref={messagesRef}
        direction='column'
        gap={8}
        // for y-scroll bar offset
        mx='-md'
        px='md'
        pt='xl'
        pb={34}
        sx={{
          flex: '1 1 0%',
          overflowY: 'auto'
          // display: showFeedback ? 'none' : 'flex'
        }}
        onScroll={throttleReleaseScroll}
      >
        <Box mb='auto' ta='center'>
          <Text size='md' c='gray.6'>
            Your Clinic Copilot
          </Text>

          <Text size='md' c='gray.6' mt='sm'>
            Support Queryable data:
          </Text>
          <Text size='md' c='gray.6'>
            Cluster List, Version, Create Time,
          </Text>
          <Text size='md' c='gray.6'>
            Real-Time CPU, Memory, Storage,
          </Text>
          <Text size='md' c='gray.6'>
            Configuration, Variables, Events
          </Text>

          <Text size='md' c='gray.6' mt='sm'>
            Querying data will take some time
          </Text>
          <Text size='md' c='gray.6'>
            Please be patient
          </Text>
        </Box>
        <TipsMessage>Welcome back! What questions do you have?</TipsMessage>
        {messages.map((msg, i) =>
          msg.displayed.role === 'assistant' ? (
            <AssistantMessage
              isLinguflowApp={true}
              key={i}
              msg={msg}
              generating={
                isStreamLoading && i === messages.length - 1 && !error
              }
              error={i === messages.length - 1 && error}
              alwaysShowFeedback={!isStreamLoading && i === messages.length - 1}
              onStreamChange={() => {
                setIsSendingMessage(false)
                setIsStreamLoading(true)
                scrollToLastMessage({ scrollToBottom })
              }}
              onStreamFinished={() => {
                setIsStreamLoading(false)
                scrollToLastMessage({ scrollToBottom })
              }}
              onStreamError={(e) => {
                setIsStreamLoading(false)
                setError(e)
              }}
              onRegenerate={() => {
                setIsSendingMessage(true)
                setError(null)
                // regenerate()
              }}
              onLike={() => {
                // like(msg.currentId!)
                // eventTracking('Clicked TiDB Bot like button')
              }}
              onDislike={() => {
                // dislike(msg.currentId!)
                // eventTracking('Clicked TiDB Bot dislike button')
              }}
              onOpenFeedback={() => {
                // openFeedback(msg.currentId!)
              }}
            />
          ) : (
            <UserMessage key={i} msg={msg} />
          )
        )}
        {isSendingMessage && GeneratingTips}
        {!!error && RegenerateTips}
      </Flex>
      {!messages?.length && PresetMessages}
      <Stack
        mx='-md'
        px='md'
        pt={16}
        sx={{
          flex: 'none',
          zIndex: 99,
          boxShadow: scrollToBottom ? '' : '0 -4px 8px -6px rgba(0, 0, 0, 0.2)'
          // display: showFeedback ? 'none' : 'flex'
        }}
      >
        <TextInput
          sendMessage={sendMessage}
          isLoading={!isSendMessageReady}
          disabled={isSendMessageDisabled}
        />
        <Group w='100%' position='apart'>
          <Button
            variant='default'
            c='gray.6'
            fw='normal'
            size='xs'
            disabled={
              isSendingMessage ||
              isStreamLoading ||
              !messages.length ||
              !isSendMessageReady
            }
            onClick={() => {
              newSession()
              setScrollToBottom(true)
              // eventTracking('Clicked TiDB Bot clear session button')
            }}
            data-mp-event='mp-cleartopic-1691461015818'
          >
            Clear Topic
          </Button>
        </Group>
      </Stack>
    </Stack>
  )
}

const TextInput: React.FC<{
  sendMessage: (v: string) => Promise<boolean>
  isLoading: boolean
  disabled: boolean
}> = ({ sendMessage, isLoading, disabled }) => {
  const [inputValue, setInputValue] = useState('')
  const [focused, setFocused] = useState(false)
  const handleSendMessage = async () => {
    const startSend = await sendMessage(inputValue.trim())
    startSend && setInputValue('')
    // eventTracking('Send message to TiDB Bot')
  }

  return (
    <Box w='100%' sx={{ position: 'relative' }}>
      <Textarea
        disabled={isLoading || disabled}
        autosize
        maxLength={INPUT_LIMIT}
        minRows={2}
        maxRows={10}
        rightSection={
          <Stack h='100%' spacing={8} py={8} justify='flex-start'>
            <Box
              p={8}
              pb={0}
              m={-8}
              ta='center'
              sx={(theme) => ({
                cursor: 'pointer',
                color: focused ? theme.colors.gray[8] : theme.colors.gray[5]
              })}
              onClick={handleSendMessage}
            >
              <IconSend size={16} />
            </Box>
            {!!inputValue.length && (
              <Text size='xs' color='gray.5' ta='center'>
                {INPUT_LIMIT - inputValue.length}
              </Text>
            )}
          </Stack>
        }
        rightSectionWidth={32}
        styles={{
          input: {
            lineHeight: 1.4,
            paddingLeft: '8px',
            paddingTop: '8px!important',
            paddingBottom: '8px!important'
          }
        }}
        placeholder={!isLoading ? 'Ask me anything about TiDB' : 'Loading...'}
        value={inputValue}
        onFocus={() => setFocused(true)}
        onBlur={() => setFocused(false)}
        onChange={(e: React.ChangeEvent<HTMLTextAreaElement>) =>
          setInputValue(e.target.value)
        }
        onKeyDown={(e: React.KeyboardEvent<HTMLTextAreaElement>) => {
          // see ignore IME composition events
          // https://developer.mozilla.org/en-US/docs/Web/API/Element/keydown_event
          if (
            (e.key === 'Enter' && !e.currentTarget.value) ||
            e.keyCode === 229
          ) {
            e.preventDefault()
            return
          }
          if (e.key === 'Enter' && !e.shiftKey && !e.metaKey) {
            e.preventDefault()
            handleSendMessage()
          }
        }}
      />
    </Box>
  )
}
