import type { Editor as TinyMCEEditor, EditorEvent } from "tinymce";
import { eventPropTypes, IEventPropTypes } from "./EditorPropTypes";
import { IAllProps } from "./rte";

export const isFunction = (x: unknown): x is (...args: any[]) => unknown =>
  typeof x === "function";

const isEventProp = (name: string): name is keyof IEventPropTypes =>
  name in eventPropTypes;

const eventAttrToEventName = <T extends string>(attrName: `on${T}`): T =>
  attrName.substr(2) as T;

type PropLookup = <K extends keyof IAllProps>(
  key: K
) => IAllProps[K] | undefined;

export const configHandlers2 = <H>(
  handlerLookup: PropLookup,
  on: (name: string, handler: H) => void,
  off: (name: string, handler: H) => void,
  adapter: <K extends keyof IEventPropTypes>(lookup: PropLookup, key: K) => H,
  prevProps: Partial<IAllProps>,
  props: Partial<IAllProps>,
  boundHandlers: Record<string, H>
): void => {
  const prevEventKeys = Object.keys(prevProps).filter(isEventProp);
  const currEventKeys = Object.keys(props).filter(isEventProp);

  const removedKeys = prevEventKeys.filter(
    (key: keyof IAllProps) => props[key] === undefined
  );
  const addedKeys = currEventKeys.filter(
    (key: keyof IAllProps) => prevProps[key] === undefined
  );

  removedKeys.forEach((key: any) => {
    // remove event handler
    const eventName = eventAttrToEventName(key);
    const wrappedHandler = boundHandlers[eventName];
    off(eventName, wrappedHandler);
    delete boundHandlers[eventName];
  });

  addedKeys.forEach((key: any) => {
    const wrappedHandler = adapter(handlerLookup, key);
    const eventName = eventAttrToEventName(key);
    boundHandlers[eventName] = wrappedHandler;
    on(eventName, wrappedHandler);
  });
};

export const configHandlers = (
  editor: TinyMCEEditor,
  prevProps: Partial<IAllProps>,
  props: Partial<IAllProps>,
  boundHandlers: Record<string, (event: EditorEvent<any>) => unknown>,
  lookup: PropLookup
): void =>
  configHandlers2(
    lookup,
    editor.on.bind(editor),
    editor.off.bind(editor),
    // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
    (handlerLookup, key) => (e) => handlerLookup(key)?.(e, editor),
    prevProps,
    props,
    boundHandlers
  );

let unique = 0;

export const uuid = (prefix: string): string => {
  const time = Date.now();
  const random = Math.floor(Math.random() * 1000000000);

  unique++;

  return prefix + "_" + random + unique + String(time);
};

export const isTextareaOrInput = (
  element: Element | null
): element is HTMLTextAreaElement | HTMLInputElement =>
  element !== null &&
  (element.tagName.toLowerCase() === "textarea" ||
    element.tagName.toLowerCase() === "input");

const normalizePluginArray = (plugins?: string | string[]): string[] => {
  if (typeof plugins === "undefined" || plugins === "") {
    return [];
  }

  return Array.isArray(plugins) ? plugins : plugins.split(" ");
};

// eslint-disable-next-line max-len
export const mergePlugins = (
  initPlugins: string | string[] | undefined,
  inputPlugins: string | string[] | undefined
): string[] =>
  normalizePluginArray(initPlugins).concat(normalizePluginArray(inputPlugins));

export const isBeforeInputEventAvailable = () =>
  window.InputEvent &&
  typeof (InputEvent.prototype as any).getTargetRanges === "function";

export const isInDoc = (elem: Node) => {
  if (!("isConnected" in Node.prototype)) {
    // Fallback for IE and old Edge
    let current = elem;
    let parent = elem.parentNode;
    while (parent != null) {
      current = parent;
      parent = current.parentNode;
    }
    return current === elem.ownerDocument;
  }

  return elem.isConnected;
};

export const setMode = (
  editor: TinyMCEEditor | undefined,
  mode: "readonly" | "design"
) => {
  if (editor !== undefined) {
    if (
      editor.mode != null &&
      typeof editor.mode === "object" &&
      typeof editor.mode.set === "function"
    ) {
      editor.mode.set(mode);
    } else {
      // support TinyMCE 4
      (editor as any).setMode(mode);
    }
  }
};


 export const isValidEthiopianPhone = (phone: string): boolean => {
   const normalized = phone.replace(/\s+/g, "");
   return (
     /^(\+2519\d{8}|09\d{8})$/.test(normalized) ||
     /^(\+2517\d{8}|07\d{8})$/.test(normalized)
   );
 };
 export const isValidEthiopianPhoneNum = (phone: string): boolean => {
   const normalized = phone.replace(/\s+/g, "");
   return (
     /^(\+2519\d{8}|09\d{8})$/.test(normalized) ||
     /^(\+2517\d{8}|07\d{8})$/.test(normalized) 
   );
 };
 
 export const isValidEmail = (email: string) => {
   const emailRegex = /^[^\s@]+@[^\s@]+\.[a-zA-Z]{2,}$/;
   return emailRegex.test(email);
 };
