import { Button, Col, Row, Space } from 'antd';
import { Alert, Mentions } from 'antd5';
import type { MentionsRef } from 'antd5/es/mentions';
import _ from 'lodash';
import type { CSSProperties } from 'react';
import { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
import { useIntl } from 'umi';
import { AuditContainerContext } from '.';
import { queryUser } from '../server';
import { formatUserRender } from '../utils';
import { replyMessage } from './api';
import lessStyle from './index.less';

const styles: Record<
  'root' | 'input' | 'mention' | 'button' | 'alert' | 'insert' | 'alertBody',
  CSSProperties
> = {
  root: {
    width: '100%',
    display: 'flex',
    alignItems: 'start',
    justifyContent: 'space-between',
  },
  input: {
    width: 'calc(100% - 100px)',
  },
  mention: {
    height: 100,
  },
  button: {
    marginTop: (100 - 32) / 2,
  },
  alert: {
    height: '100%',
  },
  insert: {
    float: 'right',
    margin: '4px 0 4px 4px',
    clear: 'both',
  },
  alertBody: {
    overflow: 'hidden',
    fontSize: 14,
  },
};

const formatValue = (nameZh: string, account: string) => {
  return `${nameZh}(${account})`;
};

type SelectedType = {
  id: number;
  nameZh: string;
  account: string;
};

export interface ReplyProps {
  chainId?: string;
  readOnly?: boolean;
  auditDetail?: { presetReplyMsg?: string[] };
  style?: CSSProperties;
  onReplied?: () => void;
}

const Reply = (props: ReplyProps) => {
  const { chainId, readOnly, auditDetail, style, onReplied } = props;
  const [replyText, setReplyText] = useState<string>('');
  const { formatMessage } = useIntl();
  const [loading, setLoading] = useState(false);
  const [users, setUsers] = useState<any[]>([]);
  const [selected, setSelected] = useState<SelectedType[]>([]);
  const searchRef = useRef<string>();
  const [replying, setReplying] = useState(false);
  const { wrapperRef } = useContext(AuditContainerContext);
  const scrollBottomRef = useRef<boolean>(false);

  const onReply = useCallback(async () => {
    try {
      if (_.isEmpty(replyText) || !chainId) return;
      setReplying(true);
      const options = Mentions.getMentions(replyText);
      await replyMessage({
        chainId,
        message: replyText,
        mentions: options
          .map((v) => {
            return selected.find((sv) => {
              return v.value === formatValue(sv.nameZh, sv.account);
            });
          })
          .filter((v) => v),
      });
      onReplied?.();
      setReplyText('');
      setSelected([]);
      scrollBottomRef.current = true;
    } catch (e) {
    } finally {
      setReplying(false);
    }
  }, [chainId, onReplied, replyText, selected]);

  const scrollTimeoutRef = useRef<NodeJS.Timeout>();

  // 在回复成功后，滚动到底部，保持最新消息可见
  useEffect(() => {
    const ele = wrapperRef?.current;
    if (scrollBottomRef.current && ele) {
      clearTimeout(scrollTimeoutRef.current);
      scrollTimeoutRef.current = setTimeout(() => {
        ele.scrollTo({ behavior: 'smooth', top: ele.scrollHeight });
      }, 300);
    }
    scrollBottomRef.current = false;
  }, [auditDetail, wrapperRef]);

  const searchUser = useMemo<(key: string) => void>(() => {
    return _.debounce((key: string) => {
      if (_.isEmpty(key)) {
        setUsers([]);
        return;
      }
      queryUser(key, 1)
        .then(({ data }) => {
          if (searchRef.current !== key) return;
          setUsers(data?.list ?? []);
        })
        .finally(() => {
          if (searchRef.current !== key) return;
          setLoading(false);
        });
    }, 800);
  }, []);

  const onSearch = useCallback(
    (search: string) => {
      searchRef.current = search;
      setLoading(!!search);
      setUsers([]);
      searchUser(search);
    },
    [searchUser],
  );

  const onSelect = useCallback(
    (o: any) => {
      const { data } = o;
      if (!selected.find((v) => v.id === data.id)) {
        setSelected((old) => [...old, data as SelectedType]);
      }
    },
    [selected],
  );

  const options = useMemo(() => {
    return users.map((v) => {
      const { userName, nameEn, nameZh, cnName, id } = v;
      const nz = nameZh || cnName;
      const ac = userName || nameEn;
      const value = formatValue(nz, ac);
      const label = formatUserRender(v, false, false);
      const data = { id, nameZh: nz, account: ac };
      return { value, label, data };
    });
  }, [users]);

  const mentionsRef = useRef<MentionsRef>(null);
  const cursorTimeoutRef = useRef<NodeJS.Timeout>();

  const onInsert = useCallback(
    (v: string) => {
      const text = `${replyText ?? ''}${v}`;
      setReplyText(text);
      // 将光标移至末尾
      clearTimeout(cursorTimeoutRef.current);
      cursorTimeoutRef.current = setTimeout(() => {
        mentionsRef.current?.focus();
        const input = mentionsRef.current?.nativeElement.querySelector('textarea');
        if (input instanceof HTMLTextAreaElement) {
          input.setSelectionRange(text.length, text.length);
        }
      }, 400);
    },
    [replyText],
  );

  const { presetReplyMsg } = auditDetail ?? {};
  const presetReply = useMemo(
    () => presetReplyMsg?.filter((t) => t?.trim()) ?? [],
    [presetReplyMsg],
  );

  return (
    <div style={{ ...styles.root, ...style }}>
      <Space direction={'vertical'} style={styles.input}>
        <Mentions
          className={lessStyle.mentions}
          allowClear
          loading={loading}
          rows={3}
          options={options}
          disabled={readOnly}
          value={replyText}
          placeholder={formatMessage({ id: 'component.AuditList.reply.input.hint' })}
          style={styles.mention}
          onChange={setReplyText}
          onSearch={onSearch}
          onSelect={onSelect}
          onClear={() => setSelected([])}
          ref={mentionsRef}
        />

        {presetReply.length > 0 && (
          <Row wrap gutter={[8, 8]}>
            {presetReply.map((text, i) => (
              // eslint-disable-next-line react/no-array-index-key
              <Col key={`pre_text_${i}`} span={6}>
                <Alert
                  description={
                    <div style={styles.alertBody}>
                      <Button
                        size={'small'}
                        type={'primary'}
                        disabled={readOnly}
                        style={styles.insert}
                        onClick={() => onInsert(text)}
                      >
                        {formatMessage({ id: 'component.AuditList.reply.insert' })}
                      </Button>
                      {text}
                    </div>
                  }
                  type={'success'}
                  style={styles.alert}
                />
              </Col>
            ))}
          </Row>
        )}
      </Space>

      <Button
        disabled={_.isEmpty(replyText) || readOnly}
        type={'primary'}
        onClick={onReply}
        loading={replying}
        style={styles.button}
      >
        {formatMessage({ id: 'base.reply.message' })}
      </Button>
    </div>
  );
};

export default Reply;
