import { useEffect, useRef, useState } from "react";

export type EntityListType = Array<{key: string; value: string;}>;

export const FUNCTION_PREFIX = "#";

export const useDynamicEntityList = (list: EntityListType | undefined, updateDelay = 1000, executeFunction = querySelector): EntityListType | undefined => {
  const keys = list?.map(item => item.key);
  const values = list?.map(item => item.value);
  const [resultList, setResultList] = useState(list);
  const resultListRef = useRef<EntityListType>();

  if (resultListRef) {
    resultListRef.current = resultList;
  }

  useEffect(() => {
    if (!keys || !values || !keys.some(key => key?.includes(FUNCTION_PREFIX))
      && !values.some(value => value?.includes(FUNCTION_PREFIX))) {
        if (list?.map(item => item.key + item.value).toString() !==
          resultListRef.current?.map(item => item.key + item.value).toString()) {
          setResultList(list);
        }

        return;
    }

    const keyFunctions = parseFunctionList(keys);
    const valueFunctions = parseFunctionList(values);

    const handler = setInterval(() => {
      const result = keys.map((key, index) => {
        const kf = keyFunctions[index];
        const keyResult = kf ? executeFunction<string>(kf[1], kf[0]) : key;

        const vf = valueFunctions[index];
        const valueResult = vf ? executeFunction<string>(vf[1], vf[0]) : key;

        return {key: keyResult ?? "", value: valueResult ?? ""};
      });

      if (resultListRef.current?.map(item => item.key + item.value).toString() !==
      result?.map(item => item.key + item.value).toString()) {
        setResultList(result);
      }
    }, updateDelay);

    return () => clearInterval(handler);
  }, [keys?.toString(), values?.toString()]);

  return resultList;
};

export const querySelector = <ResultT,>(selector: string, propName: string): ResultT | undefined => {
  let node;

  try {
    node = document.querySelector(selector);
  } catch(e) {

  }

  if (!node || !propName) {
    return undefined;
  }

  return node[propName];
};

const parseFunctionList = (list: string[]) => list.map(item => parseFunction(item));

const parseFunction = (exp: string) => {
  if (exp?.startsWith(FUNCTION_PREFIX)) {
    // Extract the function name and parameter from the string
    const functionName = exp.slice(FUNCTION_PREFIX.length, exp.indexOf("("));
    const param = exp.slice(exp.indexOf("(") + 1, -1);

    // Check if the function name is valid
    if (/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(functionName)) {
      // Create and return a new function
      return [functionName, param];
    } else {
      undefined;
    }
  } else {
    undefined;
  }
}
