import { Parser } from '@json2csv/plainjs'
import { ActionIcon, Tabs, Text, Box, Flex, notifier } from '@tidbcloud/uikit'
import {
  IconDownload01,
  IconLayoutBottom,
  IconLayoutBottomFill,
  IconLayoutLeft,
  IconLayoutLeftFill,
  IconLayoutTop,
  IconLayoutTopFill,
  IconMenuRight
} from '@tidbcloud/uikit/icons'
import clsx from 'clsx'
import { ResizeCallback } from 're-resizable'
import React, { useState, useEffect, useMemo } from 'react'
import { CSVLink } from 'react-csv'

import ResizableContainer from 'dbaas/components/ResizableContainer'
import Chart from 'dbaas/screens/Chart'
import { getErrorMessage } from 'dbaas/services/errorCodes'
import { eventTracking } from 'dbaas/utils/tracking'

import {
  BOTTOM_PANEL_DEFAULT_HEIGHT,
  BOTTOM_PANEL_MIN_HEIGHT,
  DEFAULT_QUERY_LOG_LAYOUT,
  LEFT_PANEL_DEFAULT_WIDTH,
  useSQLEditorContext
} from '../context/editor-context'
import { Settings } from '../Editor/Settings'
import { useCommonStyles } from '../index.styles'
import { RequestStatus } from '../types'

import EmptyTips from './EmptyTips'
import { LayoutIcon } from './Layout'
import { QueryLog } from './QueryLog'
import Results from './Results'
import ResultSearch from './ResultSearch'
import { RunningTips, RunErrTips, RunWarningTips, RunSuccTips } from './RunningTips'

const EDITOR_PADDING = 16

const MessageLogs: React.FC<
  React.PropsWithChildren<{
    sqlRef: React.RefObject<HTMLDivElement>
    maxHeight: number
    isRun: boolean
    maxWidth: number
  }>
> = ({ maxHeight, maxWidth, isRun }) => {
  const [curIndex, setCurIndex] = useState(0)
  const runHeight = 340
  const defaultHeight = BOTTOM_PANEL_DEFAULT_HEIGHT
  const minHeight = BOTTOM_PANEL_MIN_HEIGHT
  const headerH = 40
  const [resizing, setResizing] = useState(false)
  const [currentTab, setCurrentTab] = useState<'result' | 'chart'>('result')
  const {
    sqlResultList,
    layout: { leftPanel, mainPanel, bottomPanel },
    setLayout,
    resetLeftPanelLayout,
    setLeftPanelLayout,
    setBottomPanelLayout,
    queryLogLayout,
    editedSqlFile,
    setQueryLogLayout
  } = useSQLEditorContext()
  const { classes } = useCommonStyles()
  const [searchKey, setSearchKey] = useState('')

  const maxMessageWidth = useMemo(() => {
    return maxWidth - (leftPanel.hidden ? 0 : leftPanel.width || LEFT_PANEL_DEFAULT_WIDTH)
  }, [maxWidth, leftPanel])
  const [settingVisible, setSettingVisible] = useState(false)

  useEffect(() => {
    if (sqlResultList.length) {
      setCurIndex(0)
    }
  }, [sqlResultList.length])

  useEffect(() => {
    if (isRun && (bottomPanel.hidden || (bottomPanel.height || 0) < runHeight)) {
      setBottomPanelLayout({
        height: runHeight,
        hidden: false
      })
    }
    // need to expand query log when run
    if (isRun) {
      setQueryLogLayout({
        hidden: false,
        width: DEFAULT_QUERY_LOG_LAYOUT.width
      })
    }
  }, [isRun, bottomPanel.height])

  useEffect(() => {
    if (sqlResultList.length > 5) {
      setQueryLogLayout({
        width: DEFAULT_QUERY_LOG_LAYOUT.width,
        hidden: false
      })
    }
  }, [sqlResultList])

  const messageItemClick = (index: number) => {
    setCurIndex(index)
  }

  const downFileSuffix = () => {
    const date = new Date()
    const year = date.getFullYear()
    const month = `${date.getMonth() + 1}`.padStart(2, '0')
    const day = `${date.getDate()}`.padStart(2, '0')
    const hour = `${date.getHours()}`.padStart(2, '0')
    const min = `${date.getMinutes()}`.padStart(2, '0')
    const sec = `${date.getSeconds()}`.padStart(2, '0')
    return `${year}-${month}-${day}-${hour}${min}${sec}`
  }

  const messlogResize = () => {
    setResizing(true)
  }

  const onResizeStop: ResizeCallback = (_event, _direction, _elementRef, delta) => {
    setResizing(false)
    const height = (bottomPanel.height || 0) + delta.height
    if (height <= minHeight + 60) {
      setBottomPanelLayout({
        hidden: true,
        height: minHeight
      })
      return
    }

    if (height < maxHeight - EDITOR_PADDING * 4) {
      setLayout({
        leftPanel: { ...leftPanel },
        mainPanel: {
          hidden: false
        },
        bottomPanel: {
          height: height,
          hidden: false
        }
      })
      return
    }
    if (height > maxHeight - EDITOR_PADDING * 4) {
      setLayout({
        leftPanel: { ...leftPanel },
        mainPanel: {
          hidden: true
        },
        bottomPanel: {
          height: maxHeight
        }
      })
      return
    }
    setBottomPanelLayout({
      height,
      hidden: false
    })
  }

  const cur = sqlResultList[curIndex] || {}
  const { columns = [], rows = [], query, databases, row_count, limit = 0 } = cur.res || {}
  const isDownloadReady = !!((rows || []).length || (columns || []).length)

  const downloadData = useMemo(() => {
    if (!isDownloadReady) return []

    try {
      if (!rows.length || !columns.length) {
        return []
      }

      const parser = new Parser({ header: false })
      const csv = parser.parse(rows || [])
      return csv
    } catch (e) {
      notifier.error(getErrorMessage(e))
      return []
    }
  }, [rows, columns, isDownloadReady])

  const DownloadIcon = (
    <ActionIcon
      variant="transparent"
      w={24}
      h={24}
      sx={(theme) => {
        return {
          color: isDownloadReady ? theme.colors.carbon[8] : theme.colors.carbon[6],
          '&:disabled': {
            color: theme.colors.carbon[6]
          },
          '&:hover': {
            backgroundColor: theme.colors.carbon[2]
          }
        }
      }}
      disabled={!isDownloadReady}
    >
      <IconDownload01 width={16} height={16} />
    </ActionIcon>
  )

  return (
    <ResizableContainer
      as="div"
      className={clsx('sql-editor-container', resizing ? '' : classes.resizerContainer)}
      size={{ width: '100%', height: (bottomPanel.hidden ? minHeight : bottomPanel.height || defaultHeight) - 9 }}
      enable={{ top: true }}
      minHeight={minHeight}
      maxHeight={maxHeight}
      onResize={messlogResize}
      onResizeStop={onResizeStop}
      handleClasses={{ top: classes.resizer }}
    >
      <Flex
        id="MessageLog"
        sx={(theme) => ({
          backgroundColor: theme.white,
          borderTop: `1px solid ${theme.colors.carbon[3]}`,
          height: '100%'
        })}
      >
        {/** Query log **/}
        <QueryLog curSelectedLog={curIndex} onLogClick={messageItemClick} maxWidth={maxMessageWidth} />
        {/** Results **/}

        <Box
          sx={() => ({
            flex: 1,
            minWidth: 140,
            position: 'relative'
          })}
        >
          <Flex
            sx={(theme) => ({
              padding: '0 16px 0 8px',
              height: 40,
              lineHeight: '40px',
              fontWeight: 500,
              color: theme.colors.carbon[8]
            })}
          >
            <Flex align="center" sx={{ flex: 1, overflow: 'hidden' }}>
              {queryLogLayout.hidden && (
                <LayoutIcon
                  mr={8}
                  onClick={() => {
                    setQueryLogLayout({
                      width: DEFAULT_QUERY_LOG_LAYOUT.width,
                      hidden: false
                    })
                    eventTracking('SQL Editor Query Log Expand Button Clicked')
                  }}
                >
                  <IconMenuRight size={16} />
                </LayoutIcon>
              )}
              <Tabs
                value={currentTab}
                styles={{
                  list: {
                    paddingLeft: 8,
                    '&::before': {
                      borderStyle: 'none'
                    }
                  }
                }}
                onChange={(val: 'result' | 'chart') => {
                  eventTracking('Chat2query Switch Tab', {
                    value: val
                  })
                  setCurrentTab(val)
                }}
              >
                <Tabs.List>
                  <Tabs.Tab value="result">Result</Tabs.Tab>
                  <Tabs.Tab value="chart">Chart</Tabs.Tab>
                </Tabs.List>
              </Tabs>
            </Flex>

            <Flex align="center">
              <ResultSearch disabled={!isDownloadReady} onChange={(val) => setSearchKey(val)} />
              {isDownloadReady ? (
                <CSVLink
                  data={downloadData}
                  headers={(columns || []).map((col: { col: string }) => col.col)}
                  filename={`results-${downFileSuffix()}`}
                  uFEFF={false}
                  onClick={() => {
                    eventTracking('SQL Editor Download Button Clicked')
                  }}
                >
                  {DownloadIcon}
                </CSVLink>
              ) : (
                DownloadIcon
              )}

              <Flex align="center">
                <LayoutIcon
                  data-testid="chat2query-layout-left"
                  onClick={() => {
                    if (leftPanel.hidden) {
                      eventTracking('Chat2Query Show SideMenu')
                      resetLeftPanelLayout()
                    } else {
                      eventTracking('Chat2Query Hide SideMenu')
                      setLeftPanelLayout({
                        hidden: true
                      })
                    }
                  }}
                >
                  <Box component={leftPanel.hidden ? IconLayoutLeft : IconLayoutLeftFill} size={16} />
                </LayoutIcon>
                <LayoutIcon
                  data-testid="chat2query-layout-bottom"
                  onClick={() => {
                    if (bottomPanel.hidden) {
                      eventTracking('Chat2Query Show Result Panel')
                      setLayout({
                        leftPanel: { ...leftPanel },
                        bottomPanel: {
                          ...bottomPanel,
                          height: defaultHeight,
                          hidden: false
                        },
                        mainPanel: {
                          hidden: false
                        }
                      })
                    } else {
                      eventTracking('Chat2Query Hide Result Panel')
                      setLayout({
                        leftPanel: { ...leftPanel },
                        bottomPanel: {
                          hidden: true
                        },
                        mainPanel: {
                          hidden: false
                        }
                      })
                    }
                  }}
                >
                  <Box component={bottomPanel.hidden ? IconLayoutBottom : IconLayoutBottomFill} size={16} />
                </LayoutIcon>
                <LayoutIcon
                  data-testid="chat2query-layout-top"
                  onClick={() => {
                    if (mainPanel.hidden) {
                      eventTracking('Chat2Query Show Editor Panel')
                      setLayout({
                        leftPanel: { ...leftPanel },
                        bottomPanel: {
                          ...bottomPanel,
                          height: defaultHeight,
                          hidden: false
                        },
                        mainPanel: {
                          hidden: false
                        }
                      })
                    } else {
                      eventTracking('Chat2Query Hide Editor Panel')
                      setLayout({
                        leftPanel: { ...leftPanel },
                        bottomPanel: {
                          ...bottomPanel,
                          height: maxHeight,
                          hidden: false
                        },
                        mainPanel: {
                          hidden: true
                        }
                      })
                    }
                  }}
                >
                  <Box component={mainPanel.hidden ? IconLayoutTop : IconLayoutTopFill} size={16} />
                </LayoutIcon>
              </Flex>
            </Flex>
          </Flex>

          <Box
            sx={{
              position: 'absolute',
              top: 40,
              left: 0,
              right: 0,
              bottom: 0,
              '&::-webkit-scrollbar': {
                width: 0,

                '&:horizontal': {
                  height: 0
                }
              }
            }}
          >
            {!sqlResultList.length && <EmptyTips />}

            {!!(cur.status !== RequestStatus.Error && columns && columns.length && currentTab === 'result') && (
              <Results
                columns={columns || []}
                list={rows || []}
                message={''}
                highlightKey={searchKey}
                height={bottomPanel.height ? Math.ceil(bottomPanel.height - headerH) : 0}
                showTips={bottomPanel.hidden ? false : !!sqlResultList.length}
                tips={
                  <>
                    {row_count !== undefined && (
                      <>
                        showing{' '}
                        {row_count > limit ? (
                          <>
                            <Text component="a" c="peacock.7" mr={4} onClick={() => setSettingVisible(true)}>
                              {limit}
                            </Text>
                            rows out of {row_count}
                          </>
                        ) : (
                          <>{row_count} rows</>
                        )}
                      </>
                    )}
                    {databases ? ` from database ${databases.join(', ')}` : ''}
                  </>
                }
              />
            )}

            <Chart
              className={
                cur.status !== RequestStatus.Error && columns && columns.length && currentTab === 'chart'
                  ? undefined
                  : classes.hidden
              }
              sql={cur.statement?.content}
              sqlFileName={editedSqlFile.name}
              containerSize={{ width: queryLogLayout.width, height: bottomPanel.height }}
              chartData={{ rows, columns }}
            />

            {!!sqlResultList.length &&
              cur.status === RequestStatus.Success &&
              !columns?.length &&
              !cur.res?.warn_count && (
                <Box p={24}>
                  <RunSuccTips message={query} />
                </Box>
              )}

            {RequestStatus.Loading === cur.status && (
              <Flex direction="column" p={24}>
                <RunningTips />
              </Flex>
            )}

            {!!(RequestStatus.Error === cur.status || cur.res?.warn_count) && (
              <Flex direction="column" p={24}>
                {cur.status === RequestStatus.Error && <RunErrTips data={cur} />}
                {!!cur.res?.warn_count && !columns?.length && <RunWarningTips message={cur.res.warn_messages} />}
              </Flex>
            )}
          </Box>
        </Box>

        {settingVisible && <Settings defaultVisible={true} onClose={() => setSettingVisible(false)} />}
      </Flex>
    </ResizableContainer>
  )
}

export default MessageLogs
