// eslint-disable-next-line you-dont-need-lodash-underscore/get
import get from 'lodash/get';
import uniq from 'lodash/uniq';
import { CODE_EDITOR_MODES } from '../code-editor';
import 'codemirror/addon/hint/javascript-hint';
import 'codemirror/addon/hint/sql-hint';
import 'codemirror/addon/hint/anyword-hint';
const InjectCombinedHint = (CodeMirror, mode, customList, enquoteDangerousHintNames, quoteChar) => CodeMirror.registerHelper('hint', 'combined', (editor, options) => {
  const modeKey = mode === CODE_EDITOR_MODES.SQL ? 'sql' : mode ?? 'anyword';
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
  // @ts-ignore
  const modeHint = CodeMirror.hint[modeKey](editor, options);
  const anyhint = CodeMirror.hint.anyword(editor, options);
  const customListFiltered = matchCustomList(customList || [], editor, enquoteDangerousHintNames, quoteChar);
  let to;
  let from;
  if (modeHint.list.length > 0) {
    to = modeHint.to;
    from = modeHint.from;
  } else {
    // The codemirror types seems to be incorrect
    // eslint-disable-next-line @typescript-eslint/ban-ts-comment
    // @ts-ignore
    to = anyhint.to;
    // The codemirror types seems to be incorrect
    // eslint-disable-next-line @typescript-eslint/ban-ts-comment
    // @ts-ignore
    from = anyhint.from;
  }

  // Do not return a list of hints if the replaceable string has no length
  // prevents suggestions from being shown immediately after complete strings.
  if (!to || !from || to.ch === from.ch && to.line === from.line && customList?.length === 0) {
    return;
  }
  return {
    list: uniq([...get(modeHint, 'list', []), ...(customListFiltered || [])]),
    from,
    to
  };
});
function matchCustomList(list, editor, enquoteDangerousHintNames, quoteChar) {
  const WORD = /[\w$]+/;
  const cursor = editor.getCursor();
  const currentLine = editor.getLine(cursor.line); // Current row

  let start = cursor.ch;
  let end = start;
  while (end < currentLine.length && WORD.test(currentLine.charAt(end))) {
    ++end;
  }
  while (start && WORD.test(currentLine.charAt(start - 1))) {
    --start;
  }
  const currentWord = start !== end && currentLine.slice(start, end);
  const regex = new RegExp(`^${currentWord}`, 'i'); // regex for matches in custom list
  const resultList = !currentWord ? list : list.filter(item => item.match(regex)).sort();
  return enquoteDangerousHintNames ? enquoteDangerousNames(resultList, quoteChar) : resultList;
}
export const dangerousNameRegex = /[^\x00-\x7F]|[!@#$%^&*(),.?":{}|<> ]/gi;
export function enquoteDangerousNames(list, quoteChar) {
  return list && list.map(name => dangerousNameRegex.test(name) ? `${quoteChar}${name}${quoteChar}` : name);
}
export default InjectCombinedHint;