import { useWatch } from 'react-hook-form';

import useRules from 'src/hooks/useRules';
import { useLokaliseTranslation } from 'src/utils/i18n';

import { Boundary, FormulaTrendType } from '../../types';
import { nonEmptyString, nonNullable } from '../../utils';

const GOAL_FIELD_ORDER = [
  Boundary.STARTING_VALUE,
  Boundary.MIN_VALUE,
  Boundary.OBJECTIVE_VALUE,
  Boundary.MAX_VALUE,
] as const;

/**
 * Detects the trend direction based on starting and minimum values
 * @param startingValue - The initial value
 * @param minValue - The minimum value
 * @returns The trend type (INCREASING, DECREASING, or null)
 */
const detectTrend = (
  startingValue: number,
  minValue: number,
): FormulaTrendType | null => {
  if (minValue > startingValue) {
    return FormulaTrendType.INCREASING;
  }

  if (minValue < startingValue) {
    return FormulaTrendType.DECREASING;
  }

  return null;
};

export const useValueInputRules = (activeFields: string[] = []) => {
  const { t } = useLokaliseTranslation('goals');

  const watchedValues = useWatch({
    name: GOAL_FIELD_ORDER,
  });

  const requiredRules = useRules({
    required: true,
    decimalFormat: true,
  });

  const optionalRules = useRules({
    required: false,
    decimalFormat: true,
  });

  const validateSequence = (fieldName: Boundary, value: string | number) => {
    if (activeFields.length < 3) return true;

    const fieldIndex = GOAL_FIELD_ORDER.indexOf(fieldName);
    const fieldsBeforeCurrent = GOAL_FIELD_ORDER.slice(0, fieldIndex);
    const activeFieldsSet = new Set(activeFields);

    const previousField =
      fieldsBeforeCurrent.reverse().find(field => activeFieldsSet.has(field)) ||
      null;

    if (!previousField) return true;

    const numValue = Number(value);

    const previousFieldIndex = GOAL_FIELD_ORDER.indexOf(previousField);
    const previousFieldValue = watchedValues[previousFieldIndex];
    const previousValue = Number(previousFieldValue);

    const hasPreviousValue =
      nonNullable(previousFieldValue) && nonEmptyString(previousFieldValue);

    if (hasPreviousValue) {
      if (numValue === previousValue) {
        return t('simulator.equal_values_error');
      }

      const startingValueIndex = GOAL_FIELD_ORDER.indexOf(
        Boundary.STARTING_VALUE,
      );
      const minValueIndex = GOAL_FIELD_ORDER.indexOf(Boundary.MIN_VALUE);

      const startingValue = Number(watchedValues[startingValueIndex]);
      const minValue =
        fieldName === Boundary.MIN_VALUE
          ? Number(value)
          : Number(watchedValues[minValueIndex]);

      if (
        activeFields.includes(Boundary.MIN_VALUE) &&
        nonNullable(watchedValues[minValueIndex]) &&
        nonEmptyString(watchedValues[minValueIndex])
      ) {
        const trend = detectTrend(startingValue, minValue);

        if (trend) {
          if (
            trend === FormulaTrendType.INCREASING &&
            numValue < previousValue
          ) {
            return t('simulator.increasing_sequence_error');
          }
          if (
            trend === FormulaTrendType.DECREASING &&
            numValue > previousValue
          ) {
            return t('simulator.decreasing_sequence_error');
          }
        }
      }
    }

    return true;
  };

  return { requiredRules, optionalRules, validateSequence };
};
