import intl from 'react-intl-universal';
import { useState, useEffect, useCallback, Key, useRef } from 'react';
import {
  TreeSelect,
  Tree,
  Input,
  Empty,
  Button,
  message,
  Modal,
  Tooltip,
  Typography,
} from 'antd';
import config from '@/utils/config';
import { PageContainer } from '@ant-design/pro-layout';
import Editor from '@monaco-editor/react';
import { request } from '@/utils/http';
import styles from './index.module.less';
import CodeMirror from '@uiw/react-codemirror';
import SplitPane from 'react-split-pane';
import { useOutletContext } from '@umijs/max';
import { SharedContext } from '@/layouts';
import { DeleteOutlined } from '@ant-design/icons';
import { depthFirstSearch } from '@/utils';
import debounce from 'lodash/debounce';
import uniq from 'lodash/uniq';
import useFilterTreeData from '@/hooks/useFilterTreeData';

const { Text } = Typography;

const Log = () => {
  const { headerStyle, isPhone, theme } = useOutletContext<SharedContext>();
  const [value, setValue] = useState(intl.get('请选择日志文件'));
  const [select, setSelect] = useState<string>(intl.get('请选择日志文件'));
  const [data, setData] = useState<any[]>([]);
  const [loading, setLoading] = useState(false);
  const [height, setHeight] = useState<number>();
  const treeDom = useRef<any>();
  const [expandedKeys, setExpandedKeys] = useState<string[]>([]);
  const [currentNode, setCurrentNode] = useState<any>();
  const [searchValue, setSearchValue] = useState('');

  const getLogs = () => {
    setLoading(true);
    request
      .get(`${config.apiPrefix}logs`)
      .then(({ code, data }) => {
        if (code === 200) {
          setData(data);
        }
      })
      .finally(() => setLoading(false));
  };

  const getLog = (node: any) => {
    request
      .get(`${config.apiPrefix}logs/${node.title}?path=${node.parent || ''}`)
      .then(({ code, data }) => {
        if (code === 200) {
          setValue(data);
        }
      });
  };

  const onSelect = (value: any, node: any) => {
    setCurrentNode(node);
    setSelect(value);

    if (node.key === select || !value) {
      return;
    }

    if (node.type === 'directory') {
      setValue(intl.get('请选择日志文件'));
      return;
    }

    setValue(intl.get('加载中...'));
    getLog(node);
  };

  const onTreeSelect = useCallback((keys: Key[], e: any) => {
    onSelect(keys[0], e.node);
  }, []);

  const onSearch = useCallback(
    (e) => {
      const keyword = e.target.value;
      debounceSearch(keyword);
    },
    [data],
  );

  const debounceSearch = useCallback(
    debounce((keyword) => {
      setSearchValue(keyword);
    }, 300),
    [data],
  );

  const { treeData: filterData, keys: searchExpandedKeys } = useFilterTreeData(
    data,
    searchValue,
    { treeNodeFilterProp: 'title' },
  );

  useEffect(() => {
    setExpandedKeys(uniq([...expandedKeys, ...searchExpandedKeys]));
  }, [searchExpandedKeys]);

  const deleteFile = () => {
    Modal.confirm({
      title: `确认删除`,
      content: (
        <>
          {intl.get('确认删除')}
          <Text style={{ wordBreak: 'break-all' }} type="warning">
            {select}
          </Text>
          {intl.get('文件')}
          {currentNode.type === 'directory' ? intl.get('夹下所以日志') : ''}
          {intl.get('，删除后不可恢复')}
        </>
      ),
      onOk() {
        request
          .delete(`${config.apiPrefix}logs`, {
            data: {
              filename: currentNode.title,
              path: currentNode.parent || '',
              type: currentNode.type,
            },
          })
          .then(({ code }) => {
            if (code === 200) {
              message.success(`删除成功`);
              let newData = [...data];
              if (currentNode.parent) {
                newData = depthFirstSearch(
                  newData,
                  (c) => c.key === currentNode.key,
                );
              } else {
                const index = newData.findIndex(
                  (x) => x.key === currentNode.key,
                );
                if (index !== -1) {
                  newData.splice(index, 1);
                }
              }
              setData(newData);
              initState();
            }
          });
      },
      onCancel() {
        console.log('Cancel');
      },
    });
  };

  const initState = () => {
    setSelect('');
    setCurrentNode(null);
    setValue(intl.get('请选择脚本文件'));
  };

  const onExpand = (expKeys: any) => {
    setExpandedKeys(expKeys);
  };

  useEffect(() => {
    getLogs();
  }, []);

  useEffect(() => {
    if (treeDom.current) {
      setHeight(treeDom.current.clientHeight);
    }
  }, [treeDom.current, data]);

  return (
    <PageContainer
      className="ql-container-wrapper log-wrapper"
      title={
        <>
          {select}
          {currentNode?.type === 'file' && (
            <span style={{ marginLeft: 6, fontSize: 12, color: '#999' }}>
              {(currentNode.size / 1024).toFixed(3)}KB
            </span>
          )}
        </>
      }
      loading={loading}
      extra={
        isPhone
          ? [
              <TreeSelect
                treeExpandAction="click"
                className="log-select"
                value={select}
                dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
                treeData={data}
                placeholder={intl.get('请选择日志')}
                fieldNames={{ value: 'key' }}
                treeNodeFilterProp="title"
                showSearch
                allowClear
                onSelect={onSelect}
              />,
            ]
          : [
              <Tooltip title={intl.get('删除')}>
                <Button
                  type="primary"
                  disabled={!select}
                  onClick={deleteFile}
                  icon={<DeleteOutlined />}
                />
              </Tooltip>,
            ]
      }
      header={{
        style: headerStyle,
      }}
    >
      <div className={`${styles['log-container']} log-container`}>
        {!isPhone && (
          /*// @ts-ignore*/
          <SplitPane split="vertical" size={200} maxSize={-100}>
            <div className={styles['left-tree-container']}>
              {data.length > 0 ? (
                <>
                  <Input.Search
                    className={styles['left-tree-search']}
                    onChange={onSearch}
                    placeholder={intl.get('请输入日志名')}
                    allowClear
                  ></Input.Search>
                  <div className={styles['left-tree-scroller']} ref={treeDom}>
                    <Tree
                      expandAction="click"
                      className={styles['left-tree']}
                      treeData={filterData}
                      showIcon={true}
                      height={height}
                      selectedKeys={[select]}
                      showLine={{ showLeafIcon: true }}
                      onSelect={onTreeSelect}
                      expandedKeys={expandedKeys}
                      onExpand={onExpand}
                    ></Tree>
                  </div>
                </>
              ) : (
                <div
                  style={{
                    display: 'flex',
                    justifyContent: 'center',
                    alignItems: 'center',
                    height: '100%',
                  }}
                >
                  <Empty
                    description={intl.get('暂无日志')}
                    image={Empty.PRESENTED_IMAGE_SIMPLE}
                  />
                </div>
              )}
            </div>
            <Editor
              language="shell"
              theme={theme}
              value={value}
              options={{
                readOnly: true,
                fontSize: 12,
                minimap: { enabled: false },
                lineNumbersMinChars: 3,
                folding: false,
                glyphMargin: false,
              }}
            />
          </SplitPane>
        )}
        {isPhone && (
          <CodeMirror
            value={value}
            readOnly={true}
            theme={theme.includes('dark') ? 'dark' : 'light'}
            onChange={(value, viewUpdate) => {
              setValue(value);
            }}
          />
        )}
      </div>
    </PageContainer>
  );
};

export default Log;
