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

import {
  Box,
  Button,
  Flex,
  Group,
  Select,
  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 {
  ActionMessage,
  AssistantMessage,
  TipsMessage,
  UserMessage
} from './Messages/Messages'
import { useMessages } from './Messages/useMessages'
// import { useFeedback } from './Feedback'

import './Messages/Messages.module.css'

const PRESET_MESSAGE = [
  `What does tidb_store_batch_size mean?`,
  'How to use fast plan binding?'
]
const INPUT_LIMIT = 600
const DOMAINS = [
  { value: 'tidb_v7.5', label: 'OP v7.5' },
  { value: 'tidb_v7.1', label: 'OP v7.1' },
  { value: 'tidb_v6.5', label: 'OP v6.5' },
  { value: 'tidbcloud', label: 'Cloud' }
]

export const Chats: React.FC = () => {
  // const { showFeedback, openFeedback, closeFeedback, like, dislike, feedback } =
  //   useFeedback()
  // const [wasCleared, setWasCleared] = useState(false)
  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 [domain, setDomain] = useState<string>(DOMAINS[0].value)
  const isCloud = domain === 'cloud'
  const domainValues = domain.split('_')
  const {
    messages,
    clearMessages,
    sendMessage: _sendMessage,
    regenerate,
    isMessagesLoading,
    createSession
  } = useMessages({
    domain: [domainValues[0]],
    version: isCloud ? undefined : domainValues[1],
    onMessagesChange: () =>
      scrollToLastMessage({ scrollToBottom, force: true }),
    onError: (e) => {
      setIsSendingMessage(false)
      setError(e)
    }
  })
  const sendMessage = (m: string) => {
    if (m === '' || isSendingMessage || isStreamLoading || !!error) {
      return false
    }

    setIsSendingMessage(true)
    _sendMessage(m)
    return true
  }
  const newSession = () => {
    clearMessages()
    setError(null)
    createSession()
  }

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

  const isSendMessageReady = !isMessagesLoading
  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>
  )

  return (
    <Stack spacing={0} h='100%' w='100%'>
      <Group pb='md' position='center'>
        <Text>Scope: </Text>
        <Select
          data={DOMAINS}
          placeholder='Pick scopes'
          value={domain}
          disabled={isMessagesLoading}
          onChange={(d) => {
            setDomain(d as string)
            newSession()
          }}
        />
      </Group>
      {/* {showFeedback && (
        <Feedback
          onFeedbackClose={() => {
            closeFeedback()
            // eventTracking('Close TiDB Bot feedback')
          }}
          onSubmit={(f) => {
            feedback(f)
            closeFeedback()
            // eventTracking('Submit TiDB Bot feedback')
          }}
        />
      )} */}
      <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 mt={!messages.length ? 40 : 0} mb='auto' ta='center'>
          <Text size='md' c='gray.6'>
            Your Clinic Copilot
          </Text>

          <Text size='md' c='gray.6' mt='sm'>
            Support Docs:
          </Text>
          <Text size='md' c='gray.6'>
            Latest TiDB Cloud Docs
          </Text>
          <Text size='md' c='gray.6'>
            TiDB OP v7.5, v7.1, v6.5 Docs
          </Text>
        </Box>
        <TipsMessage>Welcome back! What questions do you have?</TipsMessage>
        {messages.map((msg, i) =>
          msg.displayed.role === 'assistant' ? (
            <AssistantMessage
              isLinguflowApp={false}
              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}
      </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)
              // setWasCleared(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) => boolean
  isLoading: boolean
  disabled: boolean
}> = ({ sendMessage, isLoading, disabled }) => {
  const [inputValue, setInputValue] = useState('')
  const [focused, setFocused] = useState(false)
  const handleSendMessage = () => {
    const startSend = 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>
  )
}
