import { MetaClassSchema } from "@devsun/form-generator";
import get from "lodash/get";

export interface ProcessStep {
  label: string;
  name: string;
  icon: string;
}

function recursiveGroupExpand(commonGroupList: any, attrList: string[]): string[] {
  const expandedAttrs: any[] = [...attrList];
  attrList.forEach((attr: any) => {
    const group = commonGroupList.find((g: any) => g.name === attr);
    if (group) {
      const attrsFromGroup = recursiveGroupExpand(commonGroupList, group.attrList);
      expandedAttrs.push(...attrsFromGroup);
    } else {
      expandedAttrs.push(attr);
    }
  })
  return expandedAttrs;
}

function getStepUniquePaths(step: ProcessStep, schema: any): Set<string> {
  const currentStepGroup = schema?.groupList
    .find((g: any) => g.name === step.name);
  if (!currentStepGroup) {
    return new Set();
  }

  const groups = [currentStepGroup];
  const childGroups = schema?.groupList
    .filter((g: any) => g.parent === currentStepGroup.name);
  if (childGroups?.length) {
    groups.push(...childGroups);
  }

  const allPaths: string[] = [];
  groups?.forEach((cg: any) => {
    if (cg.attrList) {
      const paths = recursiveGroupExpand(
        schema?.groupList, cg.attrList
      );
      allPaths.push(...paths);
    }
  })

  const allUniquePaths = new Set(allPaths);
  return allUniquePaths;
}

function getShouldNotClearSet(step: ProcessStep, schema: any, model: any): Set<string> {
  const paths = getStepUniquePaths(step, schema);
  for (let key of paths.keys()) {
    if (!get(model, key)) {
      paths.delete(key);
    }
  }
  return paths;
}

function getDataToClear(
  step: ProcessStep, shouldNotClear: string[], schema: any, model: any, currentStepIndex: number
): any[] {
  const paths = getStepUniquePaths(step, schema);
  const dataToClear: string[] = [];
  for (let path of paths.keys()) {
    const shouldClear = !shouldNotClear.includes(path);
    const hasValue = get(model, path);
    if (shouldClear && hasValue && !dataToClear.includes(path)) {
      dataToClear.push(path);
    }
  }
  return dataToClear;
}

function mergeSets(sets: Set<string>[]): string[] {
  // create a set to store unique values
  let uniqueValues = new Set<string>();
  // iterate over the array of sets
  for (let i = 0; i < sets.length; i++) {
    // get the current set
    let set = sets[i];
    // iterate over the values in the current set
    for (let value of set.values()) {
      // add the value to the unique values set
      uniqueValues.add(value);
    }
  }
  // return the set as an array
  return Array.from(uniqueValues);
}

function setHas(set: Set<string>, value: string) {
  let containsObject = false;
  for (const obj of set) {
    if (obj[0] === value) {
      containsObject = true;
      break;
    }
  }
  return containsObject;
}

function mergeArrays(arrays: any): string[] {
  const uniqueValues = new Set<string>();
  for (const innerArray of arrays) {
    for (const value of innerArray) {
      if (!setHas(uniqueValues, value)) {
        uniqueValues.add(value);
      }
    }
  }
  return Array.from(uniqueValues);
}

const stepsToSkip = ['documents', 'applicationForPrint'];

export function getPathsToClear(
  steps: ProcessStep[], currentStepIndex: number, schema: MetaClassSchema | null, model: any
): string[] {
  const notToClear: Set<string>[] = steps
    .filter((s: ProcessStep, stepIndex: number) =>
      stepIndex <= currentStepIndex && !stepsToSkip.includes(s.name))
    .map((s: ProcessStep) => getShouldNotClearSet(s, schema, model));
  const notToClearArr = mergeSets(notToClear);

  const toClear = steps
    .filter((s: ProcessStep, stepIndex: number) =>
      stepIndex > currentStepIndex && !stepsToSkip.includes(s.name))
    .map((s: ProcessStep) => getDataToClear(s, notToClearArr, schema, model, currentStepIndex));
  const toClearArr = mergeArrays(toClear);

  return toClearArr;
}

export function clearValue(value: any): any {
  if (Array.isArray(value)) {
    // If the value is an array, return an empty array
    return [];
  }

  // Use a switch statement to determine the type of the value
  switch (typeof value) {
    case "string":
      // If the value is a string, return an empty string
      return "";
    case "number":
      // If the value is a number, return 0
      return 0;
    case "boolean":
      // If the value is a boolean, return false
      return false;
    default:
      // If the value is any other type, return null
      return null;
  }
}
