import jsonPatch from "fast-json-patch";
import pick from "lodash/pick";

interface PatchOptions {
  actions?:
    | "add"
    | "remove"
    | "replace"
    | "move"
    | "copy"
    | "test"
    | "_get"
    | string[];
  ignoreFields?: string[];
}

export class JSONService {
  static getPatch = (target: any, source: any, options: PatchOptions = {}) => {
    if (typeof target !== "object" || typeof source !== "object") return {};
    const s = jsonPatch.deepClone(source);
    const t = jsonPatch.deepClone(target);

    // remove ignore field before compare
    if (options?.ignoreFields && options?.ignoreFields.length > 0) {
      for (const field of options?.ignoreFields) {
        field in s && delete s[field];
        field in t && delete t[field];
      }
    }

    const patch = jsonPatch.compare(s, t);

    if (typeof options?.actions === "string") {
      return pick(
        target,
        patch
          .filter((p) => p.op === options?.actions)
          .map(
            (p) =>
              p.path
                .split("/")
                .filter((p) => p !== "" && p !== null && p !== undefined)[0]
          )
      );
    }

    if (options?.actions && Array.isArray(options?.actions)) {
      return pick(
        target,
        patch
          .filter((p) => options?.actions?.includes(p.op))
          .map(
            (p) =>
              p.path
                .split("/")
                .filter((p) => p !== "" && p !== null && p !== undefined)[0]
          )
      );
    }

    return pick(
      target,
      patch.map(
        (p) =>
          p.path
            .split("/")
            .filter((p) => p !== "" && p !== null && p !== undefined)[0]
      )
    );
  };
}
