import {
  Actions,
  ICondition,
  IConditionList,
  IConditionRule,
  IConditionsResult,
  IConditionsStore,
} from "@/widget/shared/types/app/conditions.type";
import { useFieldsStore } from "@/widget/app/providers/stores/fieldsStore.ts";
import {
  Field,
  FieldWithMultipleDisplayView,
  IOptions,
} from "@/widget/shared/types/fields";
import { useSingleField } from "@/widget/actions/fields/composable/useSingleField.ts";
import { useDatePickerFieldHelper } from "@/widget/actions/fields/composable/useDatePickerFieldHelper.ts";
import { useCallbackStore } from "@/widget/app/providers/stores/callbackStore.ts";
import { useAppStore } from "@/widget/app/providers/stores/appStore.ts";
import { useConditionsStore } from "@/widget/app/providers/stores/conditionsStore.ts";
import { useFields } from "../../fields/composable/useFields";
import { ref } from "vue";

const timeout = ref<ReturnType<typeof setTimeout> | null>(null);

const multipleOptionsField: string[] = [
  "checkbox",
  "checkbox_with_img",
  "toggle",
];

const singleOptionsField: string[] = [
  "dropDown",
  "dropDown_with_img",
  "radio",
  "radio_with_img",
];

function addConditions(rawConditions: IConditionList[]): void {
  const structuredConditions: IConditionsStore = {};

  rawConditions.forEach(({ optionsTo, optionsFrom, condition }) => {
    if (!structuredConditions[optionsFrom]) {
      structuredConditions[optionsFrom] = {};
    }

    if (!structuredConditions[optionsFrom][optionsTo]) {
      structuredConditions[optionsFrom][optionsTo] = [];
    }
    condition.forEach(({ action, conditions, setVal, setOptions, sort }) => {
      structuredConditions[optionsFrom][optionsTo].push({
        optionTo: optionsTo,
        optionFrom: optionsFrom,
        conditions,
        setVal,
        setOptions,
        action,
        sort,
      });
    });
  });

  const conditionsStore = useConditionsStore();
  conditionsStore.setConditions(structuredConditions);
}

function triggerCondition() {
  const appStore = useAppStore();
  if (!appStore.isProActive) {
    return;
  }

  const fieldsInstance = useFields();
  const fields = fieldsInstance.getFields();
  const validFields: Field[] = [];

  for (const field of fields) {
    if (field.alias && field.fieldName !== "total") {
      if (
        field.fieldName === "section" &&
        "fields" in field &&
        field.fields instanceof Map
      ) {
        validFields.push(...field?.fields.values());
      } else {
        validFields.push(field);
      }
    }
  }

  for (const field of validFields) {
    applyConditionForField(field.alias);
  }
}

function applyConditionForField(fieldAlias: string): void {
  const conditionsStore = useConditionsStore();

  if (!conditionsStore.conditions[fieldAlias]) {
    const keys = Object.keys(conditionsStore.conditions)?.filter((key) =>
      key.includes("total"),
    );

    if (timeout.value) {
      clearTimeout(timeout.value);
    }

    timeout.value = setTimeout(() => {
      for (const key of keys) {
        applyConditionForField(key);
      }
    }, 300);

    return;
  }

  const fieldStore = useFieldsStore();
  const singleFieldMixins = useSingleField();

  const affectedFields = Object.keys(conditionsStore.conditions[fieldAlias]);

  const triggerField: Field | undefined = fieldStore.getField(fieldAlias);

  if (!triggerField) return;

  for (const affectedAlias of affectedFields) {
    const fieldConditions =
      conditionsStore.conditions[fieldAlias][affectedAlias];
    let targetField: Field = fieldStore.getField(affectedAlias) as Field;
    if (!targetField) return;

    fieldConditions.forEach((condition: ICondition) => {
      const fieldValue: number | undefined = triggerField.value;
      const conditionResultData: Array<boolean | string> = [];
      condition.conditions.forEach(
        (conditionRule: IConditionRule, index: number) => {
          let conditionResult: boolean = false;

          switch (conditionRule.condition) {
            case "==":
              if (
                singleOptionsField.includes(triggerField.fieldName) &&
                "selectedOption" in triggerField &&
                !Array.isArray(triggerField.selectedOption)
              ) {
                const selectedIdx: string | undefined =
                  triggerField?.selectedOption?.optionValue?.split("_")[1] ||
                  undefined;

                if (selectedIdx === undefined) {
                  conditionResult = false;
                } else {
                  conditionResult =
                    conditionRule.key === "any"
                      ? !!selectedIdx
                      : +selectedIdx === +conditionRule.key;
                }
              } else if (
                triggerField.fieldName === "geolocation" &&
                "geoType" in triggerField &&
                triggerField.geoType === "multiplyLocation" &&
                "multiplyLocations" in triggerField &&
                "userSelectedOptions" in triggerField &&
                "userLocation" in triggerField
              ) {
                let conditionCoordinates = (
                  triggerField.multiplyLocations[
                    Number(conditionRule.key)
                  ] as any
                )?.coordinates;
                let userSelectedCoordinates = (
                  triggerField.userSelectedOptions as any
                ).coordinates
                  ? (triggerField.userSelectedOptions as any).coordinates.lat +
                    ", " +
                    (triggerField.userSelectedOptions as any).coordinates.lng
                  : "";
                if (conditionRule.key === "any") {
                  conditionResult = userSelectedCoordinates.length > 0;
                } else {
                  conditionResult =
                    conditionCoordinates == userSelectedCoordinates;
                }
              } else {
                conditionResult = fieldValue === +conditionRule.value;
              }
              break;
            case "!=":
              if (
                singleOptionsField.includes(triggerField.fieldName) &&
                "selectedOption" in triggerField &&
                !Array.isArray(triggerField.selectedOption)
              ) {
                if (!triggerField.selectedOption) {
                  conditionResult = true;
                } else {
                  const selectedIdx: string | undefined =
                    triggerField?.selectedOption?.optionValue?.split("_")[1] ||
                    undefined;

                  if (selectedIdx === undefined) {
                    conditionResult = false;
                  } else {
                    conditionResult =
                      conditionRule.key === "any"
                        ? !!selectedIdx
                        : +selectedIdx !== +conditionRule.key;
                  }
                }
              } else {
                conditionResult = fieldValue !== +conditionRule.value;
              }
              break;
            case ">=":
              conditionResult = Number(fieldValue || 0) > +conditionRule.value;
              break;
            case "<=":
              conditionResult = Number(fieldValue || 0) < +conditionRule.value;
              break;
            case "in":
              if (
                multipleOptionsField.includes(triggerField.fieldName) &&
                "selectedOption" in triggerField
              ) {
                const selectedOption: IOptions[] = Array.isArray(
                  triggerField.selectedOption,
                )
                  ? triggerField.selectedOption
                  : [];

                const values: number[] =
                  selectedOption?.map(
                    (f: IOptions) => +f.optionValue?.split("_")[1],
                  ) || [];

                conditionResult = Array.from(conditionRule.checkedValues).every(
                  (idx: number) => values.includes(idx),
                );
              }

              break;
            case "not in":
              if (
                multipleOptionsField.includes(triggerField.fieldName) &&
                "selectedOption" in triggerField
              ) {
                const selectedOption = Array.isArray(
                  triggerField.selectedOption,
                )
                  ? triggerField.selectedOption
                  : [];

                const values: number[] =
                  selectedOption.map(
                    (f: IOptions) => +f.optionValue?.split("_")[1],
                  ) || [];

                conditionResult = Array.from(conditionRule.checkedValues).every(
                  (idx: number) => !values.includes(idx),
                );
              }

              break;
            case "contains":
              if (
                multipleOptionsField.includes(triggerField.fieldName) &&
                "selectedOption" in triggerField
              ) {
                const selectedOptions: IOptions[] = Array.isArray(
                  triggerField.selectedOption,
                )
                  ? triggerField.selectedOption
                  : [];

                const values: number[] =
                  selectedOptions.map(
                    (f: IOptions) => +f.optionValue?.split("_")[1],
                  ) || [];

                conditionResult =
                  conditionRule.key === "any"
                    ? values.length > 0
                    : values.includes(Number(conditionRule.key));
              }

              break;
            default:
              conditionResult = false;
          }

          conditionResultData.push(conditionResult);
          if (
            condition.conditions.length > 1 &&
            index !== condition.conditions.length - 1
          ) {
            conditionResultData.push(conditionRule.logicalOperator);
          }
        },
      );

      let conditionResult: boolean = evaluateExpression(conditionResultData);

      if (triggerField.hidden && !triggerField.calculateHidden) {
        conditionResult = false;
      }

      switch (condition.action) {
        case "hide":
          targetField = hide(conditionResult, targetField, condition);
          break;
        case "show":
          targetField = show(conditionResult, targetField, condition);
          break;
        case "disable":
          targetField = disable(conditionResult, targetField, condition);
          break;
        case "unset":
          targetField = unset(conditionResult, targetField, condition);
          break;
        case "unset_option":
          targetField = unsetOption(conditionResult, targetField, condition);
          break;
        case "set_value":
          targetField = setValue(conditionResult, targetField, condition);
          break;
        case "set_value_and_disable":
          targetField = disable(
            conditionResult,
            targetField,
            condition,
            "set_value",
          );
          break;
        case "select_option":
          targetField = selectOption(conditionResult, targetField, condition);
          break;
        case "disable_option":
          targetField = disable(conditionResult, targetField, condition);
          break;
        case "select_option_and_disable":
          targetField = disable(
            conditionResult,
            targetField,
            condition,
            "select_option",
          );
          break;
        case "set_date":
          targetField = setDate(conditionResult, targetField, condition);
          break;
        case "set_date_and_disable":
          targetField = disable(
            conditionResult,
            targetField,
            condition,
            "set_date",
          );
          break;
        case "set_period":
          targetField = setPeriod(conditionResult, targetField, condition);
          break;
        case "set_period_and_disable":
          targetField = disable(
            conditionResult,
            targetField,
            condition,
            "set_period",
          );
          break;
        case "set_time":
          targetField = setTime(conditionResult, targetField, condition);
          break;
        case "set_time_and_disable":
          targetField = setTime(conditionResult, targetField, condition, true);
          break;
        case "set_location":
          targetField = setLocation(conditionResult, targetField, condition);
          break;
        case "set_location_and_disable":
          targetField = setLocation(
            conditionResult,
            targetField,
            condition,
            true,
          );
          break;
        case "hide_leave_in_total":
          targetField = hideAndLeaveTotal(
            conditionResult,
            targetField,
            condition,
          );
          break;
      }
    });

    if (
      [...multipleOptionsField, ...singleOptionsField].includes(
        targetField.fieldName,
      )
    ) {
      targetField.displayValue =
        singleFieldMixins.getMultipleOptionsFieldDisplayView(
          targetField as FieldWithMultipleDisplayView,
        );
    } else {
      if (
        ![
          "datePicker",
          "validated_form",
          "timePicker",
          "text",
          "geolocation",
        ].includes(targetField.fieldName)
      ) {
        targetField.displayValue = singleFieldMixins.getCommonFieldDisplayView(
          targetField,
          targetField.value?.toString(),
        );
      }
    }

    fieldStore.updateField(targetField.alias, targetField, true);
  }
}

function setLocation(
  result: boolean,
  targetField: Field,
  targetCondition: ICondition,
  disable?: boolean,
): Field {
  const callbackStore = useCallbackStore();
  if (result) {
    if ("selectedPoint" in targetField) {
      const pointIndex = targetCondition.setVal;
      if (typeof pointIndex === "undefined") return targetField;
      const data = targetField.multiplyLocations[Number(pointIndex)];
      targetField.selectedPoint = data;

      callbackStore.runCallback("updateGeolocation", targetField.alias);
    }

    if (disable) {
      targetField.disabled = true;
    }
  } else if (disable) {
    targetField.disabled = false;
  }

  setTimeout(() => {
    if (
      (!targetField.hidden || targetField.calculateHidden) &&
      targetCondition.optionFrom !== targetCondition.optionTo
    ) {
      applyConditionForField(targetField.alias);
    }
  });

  return targetField;
}

function hide(
  result: boolean,
  targetField: Field,
  targetCondition: ICondition,
): Field {
  const cHistory = checkInConditionHistory(targetCondition);

  if (!targetField.hidden && result) {
    addConditionHistory(targetCondition);
    targetField.hidden = true;
    updateGroupElements(targetField);
  } else if (cHistory.length && !result) {
    removeFromConditionHistory(targetCondition);

    const conditionsStore = useConditionsStore();
    const check = conditionsStore.getConditionHistory.filter(
      (d) =>
        d.optionTo === targetCondition.optionTo &&
        d.action === targetCondition.action,
    );

    if (!check.length) {
      targetField.hidden = false;
    }

    updateGroupElements(targetField);

    setTimeout(() => {
      if (
        targetField.calculateHidden &&
        targetCondition.optionFrom !== targetCondition.optionTo
      ) {
        applyConditionForField(targetField.alias);
      }
    });
  }
  return targetField;
}

function hideAndLeaveTotal(
  result: boolean,
  targetField: Field,
  targetCondition: ICondition,
): Field {
  const cHistory = checkInConditionHistory(targetCondition);
  if (result) {
    addConditionHistory(targetCondition);
    targetField.hideAndLeaveTotal = true;
  } else if (cHistory.length && !result) {
    const conditionsStore = useConditionsStore();
    removeFromConditionHistory(targetCondition);
    const check = conditionsStore.getConditionHistory.filter(
      (d) =>
        d.optionTo === targetCondition.optionTo &&
        d.action === targetCondition.action,
    );

    if (!check.length) {
      targetField.hideAndLeaveTotal = false;
    }
  }

  return targetField;
}

function show(
  result: boolean,
  targetField: Field,
  targetCondition: ICondition,
): Field {
  const cHistory = checkInConditionHistory(targetCondition);
  if (result && !cHistory.length) {
    addConditionHistory(targetCondition);
    targetField.hidden = false;

    updateGroupElements(targetField);

    setTimeout(() => {
      if (targetCondition.optionFrom !== targetCondition.optionTo) {
        applyConditionForField(targetField.alias);
      }
    });
  } else if (cHistory.length && !result) {
    setTimeout(() => {
      if (targetCondition.optionFrom !== targetCondition.optionTo) {
        applyConditionForField(targetField.alias);
      }
    });

    removeFromConditionHistory(targetCondition);

    const conditionsStore = useConditionsStore();
    const check = conditionsStore.getConditionHistory.filter(
      (d) =>
        d.optionTo === targetCondition.optionTo &&
        d.action === targetCondition.action,
    );

    if (!check.length) {
      targetField.hidden = true;
    }

    updateGroupElements(targetField);
  }

  return targetField;
}

function disable(
  result: boolean,
  targetField: Field,
  targetCondition: ICondition,
  action?: Actions,
): Field {
  const cHistory = checkInConditionHistory(targetCondition);
  const callbackStore = useCallbackStore();

  if (result && !cHistory.length) {
    if (
      singleOptionsField.includes(targetField.fieldName) &&
      targetCondition.action === "disable_option"
    ) {
      conditionHistoryLeaveOnlyCurrent(targetCondition);
    }

    removeFromConditionHistory(targetCondition);
    addConditionHistory(targetCondition);

    if (targetCondition.action === "disable_option") {
      const disableOptions: number[] = [];
      const optionsFromCondition: string[] =
        targetCondition.setVal?.toString()?.split(",") || [];

      optionsFromCondition.forEach((option: string) => {
        disableOptions.push(+option);
      });

      if ("disableOptions" in targetField) {
        targetField.disableOptions = disableOptions;
        callbackStore.runCallback(
          "updateDisableOptions",
          targetField.alias,
          targetField.disableOptions,
        );
      }
    } else {
      targetField.disabled = true;
    }

    if (action) {
      switch (action) {
        case "set_value":
          targetField = setValue(result, targetField, targetCondition);
          break;
        case "select_option":
          targetField = selectOption(result, targetField, targetCondition);
          break;
        case "set_period":
          targetField = setPeriod(result, targetField, targetCondition);
          break;
        case "set_date":
          targetField = setDate(result, targetField, targetCondition);
          break;
      }
    }
  } else if (cHistory.length && !result) {
    removeFromConditionHistory(targetCondition);

    if (
      targetCondition.action === "disable_option" &&
      "disableOptions" in targetField
    ) {
      targetField.disableOptions = [];
      callbackStore.runCallback(
        "updateDisableOptions",
        targetField.alias,
        targetField.disableOptions,
      );
    } else {
      const conditionsStore = useConditionsStore();
      const check = conditionsStore.getConditionHistory.filter(
        (d) =>
          d.optionTo === targetCondition.optionTo &&
          d.action === targetCondition.action,
      );

      if (!check.length) {
        targetField.disabled = false;
      }
    }
  }

  return targetField;
}

function unset(
  result: boolean,
  targetField: Field,
  targetCondition: ICondition,
): Field {
  const callbackStore = useCallbackStore();
  if (result) {
    targetField.value = fieldMinValue(targetField);
    if (
      multipleOptionsField.includes(targetField.fieldName) &&
      "selectedOption" in targetField
    ) {
      targetField.selectedOption = [];
    }

    if (
      singleOptionsField.includes(targetField.fieldName) &&
      "selectedOption" in targetField
    ) {
      targetField.selectedOption = undefined;
    }

    if (
      targetField.fieldName === "datePicker" &&
      "selectedDate" in targetField
    ) {
      targetField.selectedDate = undefined;
      callbackStore.runCallback(
        "updateDatePicker",
        targetField.selectedDate,
        targetField.alias,
        true,
      );
    }
  }

  setTimeout(() => {
    if (
      (!targetField.hidden || targetField.calculateHidden) &&
      targetCondition.optionFrom !== targetCondition.optionTo
    ) {
      applyConditionForField(targetField.alias);
    }
  });

  return targetField;
}

function unsetOption(
  result: boolean,
  targetField: Field,
  targetCondition: ICondition,
): Field {
  if (result) {
    targetField.value = fieldMinValue(targetField);
    if (
      multipleOptionsField.includes(targetField.fieldName) &&
      "selectedOption" in targetField
    ) {
      const values: number[] =
        targetCondition.setVal
          ?.toString()
          ?.split(",")
          ?.map((n: string) => +n) || [];

      const selectedOption = targetField.options.filter(
        (_, idx: number) => !values.includes(idx),
      );

      targetField.selectedOption = selectedOption || [];
      let value: number = 0;
      for (const option of selectedOption) {
        value += +option.optionValue.split("_")[0] || 0;
      }

      targetField.value = +value;
    }
  }

  setTimeout(() => {
    if (
      (!targetField.hidden || targetField.calculateHidden) &&
      targetCondition.optionFrom !== targetCondition.optionTo
    ) {
      applyConditionForField(targetField.alias);
    }
  });

  return targetField;
}

function setValue(
  result: boolean,
  targetField: Field,
  targetCondition: ICondition,
): Field {
  if (result) {
    const value: number = Number(targetCondition?.setVal || 0);
    const parseValue = prepareSetValue(targetField, value);

    if ("originalValue" in targetField) {
      targetField.originalValue = parseValue;
    }

    const callbackStore = useCallbackStore();

    if (result && targetField.fieldName === "quantity") {
      callbackStore.runCallback(
        "updateQuantity",
        true,
        parseValue,
        targetField.alias,
        true,
      );
    }

    if (result && targetField.fieldName === "range") {
      callbackStore.runCallback(
        "updateRange",
        parseValue,
        targetField.alias,
        true,
      );
    }
  }

  setTimeout(() => {
    if (
      (!targetField.hidden || targetField.calculateHidden) &&
      targetCondition.optionFrom !== targetCondition.optionTo
    ) {
      applyConditionForField(targetField.alias);
    }
  });

  return targetField;
}

function setPeriod(
  result: boolean,
  targetField: Field,
  targetCondition: ICondition,
): Field {
  const callbackStore = useCallbackStore();

  if (result) {
    const data = JSON.parse(targetCondition?.setVal?.toString() || "{}");

    if (typeof data.start === "undefined" || typeof data.end === "undefined")
      return targetField;

    if (targetField.fieldName === "multi_range") {
      let value = 0;
      const { start, end } = data;

      if (end - start > 0) {
        value = end - start;
      }

      targetField.value = value;
      if ("values" in targetField) {
        targetField.values = [start, end];
        callbackStore.runCallback(
          "updateMultiRange",
          targetField.values,
          targetField.alias,
          true,
        );
      }
    } else if (targetField.fieldName === "datePicker") {
      const { parseDate } = useDatePickerFieldHelper();
      const { start, end } = data;
      const parsedStart = parseDate(start);
      const parsedEnd = parseDate(end);
      if ("selectedDate" in targetField) {
        targetField.selectedDate = [parsedStart, parsedEnd];
        callbackStore.runCallback(
          "updateDatePicker",
          targetField.selectedDate,
          targetField.alias,
        );
      }
    }
  }

  setTimeout(() => {
    if (
      (!targetField.hidden || targetField.calculateHidden) &&
      targetCondition.optionFrom !== targetCondition.optionTo
    ) {
      applyConditionForField(targetField.alias);
    }
  });

  return targetField;
}

function setTime(
  result: boolean,
  targetField: Field,
  targetCondition: ICondition,
  disable?: boolean,
): Field {
  const callbackStore = useCallbackStore();

  const targetFieldRange = "range" in targetField && targetField.range;

  if (result) {
    if (targetFieldRange) {
      const data = JSON.parse(targetCondition?.setVal?.toString() || "{}");

      if (data.start && data.end) {
        callbackStore.runCallback(
          "updateRangeTimePicker",
          data,
          targetField.alias,
        );
      }
    } else {
      callbackStore.runCallback(
        "updateSingleTimePicker",
        targetCondition.setVal,
        targetField.alias,
      );
    }

    if (disable) {
      targetField.disabled = true;
    }
  } else if (disable) {
    targetField.disabled = false;
  }

  setTimeout(() => {
    if (
      (!targetField.hidden || targetField.calculateHidden) &&
      targetCondition.optionFrom !== targetCondition.optionTo
    ) {
      applyConditionForField(targetField.alias);
    }
  });

  return targetField;
}

function setDate(
  result: boolean,
  targetField: Field,
  targetCondition: ICondition,
): Field {
  const callbackStore = useCallbackStore();
  if (result && targetField.fieldName === "datePicker") {
    if (
      ("range" in targetField && targetField.range) ||
      !targetCondition.setVal
    ) {
      return targetField;
    }

    const { parseDate } = useDatePickerFieldHelper();
    const date: Date = parseDate(targetCondition?.setVal?.toString());
    if ("selectedDate" in targetField) {
      targetField.selectedDate = date;
      callbackStore.runCallback(
        "updateDatePicker",
        targetField.selectedDate,
        targetField.alias,
      );
    }
  }

  setTimeout(() => {
    if (
      (!targetField.hidden || targetField.calculateHidden) &&
      targetCondition.optionFrom !== targetCondition.optionTo
    ) {
      applyConditionForField(targetField.alias);
    }
  });

  return targetField;
}

function selectOption(
  result: boolean,
  targetField: Field,
  targetCondition: ICondition,
): Field {
  if (result) {
    targetField.value = fieldMinValue(targetField);
    if (
      multipleOptionsField.includes(targetField.fieldName) &&
      "selectedOption" in targetField
    ) {
      targetField.selectedOption = [];

      const values: number[] =
        targetCondition.setVal
          ?.toString()
          ?.split(",")
          ?.map((n: string) => +n) || [];

      const options: IOptions[] = targetField.options.filter((_, idx: number) =>
        values.includes(idx),
      );
      targetField.selectedOption = options || [];

      let value: number = 0;
      if (options?.length) {
        const optionValues: number[] = options.map((o: IOptions) => {
          const optionValue: string = o.optionValue?.split("_")[0];
          return +optionValue || 0;
        });

        for (const val of optionValues) {
          value += val;
        }
      }

      targetField.value = +value;
    }

    if (
      singleOptionsField.includes(targetField.fieldName) &&
      "selectedOption" in targetField
    ) {
      targetField.selectedOption = undefined;
      const option = targetField.options.find(
        (_, idx: number) => idx === Number(targetCondition.setVal || 0),
      );
      targetField.selectedOption = option;

      let value: number | string = 0;
      if (option) {
        value = option.optionValue.split("_")[0] || 0;
      }

      targetField.value = +value;
    }
  }

  setTimeout(() => {
    if (
      (!targetField.hidden || targetField.calculateHidden) &&
      targetCondition.optionFrom !== targetCondition.optionTo
    ) {
      applyConditionForField(targetField.alias);
    }
  });

  return targetField;
}

function addConditionHistory(data: ICondition): ICondition[] {
  const conditionsStore = useConditionsStore();
  const conditionsHistory = conditionsStore.getConditionHistory;

  const check = checkInConditionHistory(data);

  if (!check.length) {
    conditionsHistory.push(data);
  }

  conditionsStore.updateConditionHistory(conditionsHistory);

  return conditionsHistory;
}

function removeFromConditionHistory(data: ICondition): ICondition[] {
  const conditionsStore = useConditionsStore();
  const conditionsHistory = conditionsStore.getConditionHistory;
  const idx = conditionsStore.getConditionHistory.findIndex(
    (d) =>
      d.optionTo === data.optionTo &&
      d.optionFrom === data.optionFrom &&
      d.action === data.action &&
      d.sort === data.sort,
  );

  if (idx !== -1) {
    conditionsHistory.splice(idx, 1);
  }

  conditionsStore.updateConditionHistory(conditionsHistory);

  return conditionsHistory;
}

function checkInConditionHistory(data: ICondition) {
  const conditionsStore = useConditionsStore();
  const result = conditionsStore.getConditionHistory.filter(
    (d) =>
      d.optionTo === data.optionTo &&
      d.optionFrom === data.optionFrom &&
      d.action === data.action &&
      d.sort === data.sort,
  );

  if (data.action === "disable_option") {
    return result.filter((d) => d.setVal === data.setVal);
  }

  return result;
}

function conditionHistoryLeaveOnlyCurrent(data: ICondition) {
  const conditionsStore = useConditionsStore();
  const conditionsHistory = conditionsStore.getConditionHistory;
  const indexesToRemove = [];
  for (let i = 0; i < conditionsHistory.length; i++) {
    const current = conditionsHistory[i];
    if (
      current.optionTo === data.optionTo &&
      current.optionFrom === data.optionFrom &&
      current.action === data.action &&
      current.sort !== data.sort
    ) {
      indexesToRemove.push(i);
    }
  }

  for (let i = indexesToRemove.length - 1; i >= 0; i--) {
    conditionsHistory.splice(indexesToRemove[i], 1);
  }

  conditionsStore.updateConditionHistory(conditionsHistory);
}

function evaluateExpression(expression: (boolean | string)[]): boolean {
  let result = expression[0] as boolean;

  for (let i = 1; i < expression.length; i += 2) {
    const operator = expression[i] as string;
    const nextValue = expression[i + 1] as boolean;

    if (operator === "||") {
      result = result || nextValue;
    } else if (operator === "&&") {
      result = result && nextValue;
    }
  }

  return result;
}

function fieldMinValue(field: Field): number {
  if ("minValue" in field) {
    return Number(field.minValue || 0);
  }

  if ("min" in field) {
    return +field.min;
  }
  return 0;
}

export function prepareSetValue(field: Field, value: number) {
  const minValue: number = fieldMinValue(field);
  if (minValue && minValue > value) {
    return minValue;
  }

  const min: number = fieldMinValue(field);
  if (min && min > value) {
    return min;
  }

  return value;
}

function updateGroupElements(targetField: Field) {
  const fieldStore = useFieldsStore();
  if (targetField.fieldName === "group" && "groupElements" in targetField) {
    targetField.groupElements.forEach((elements, _) =>
      Array.from(elements.entries()).forEach(([_, element]) => {
        element.hidden = targetField.hidden;
        fieldStore.updateField(element.alias, element, true);
      }),
    );
  }
}

export function useConditions(): IConditionsResult {
  return { addConditions, applyConditionForField, triggerCondition };
}
