import { enToFaDigits, faToEnDigits } from "jb-core";
import { ValueSetterEventType, type JBInputValue } from "jb-input";
import { type TypeParameter, type NumberFieldParameter } from "./types";

export function standardValueForNumberInput(inputValueString: string, numberFieldParameters: NumberFieldParameter, typeParameter: TypeParameter, eventType: ValueSetterEventType): JBInputValue {
  if (inputValueString == '-' && numberFieldParameters!.acceptNegative == true) {
    //if user type - and we accept negative number we let user to continue typing
    return {
      displayValue: inputValueString,
      value: '-0'
    };
  }
  let valueString = inputValueString;
  //if  comma separator is used we need to remove it
  if (typeParameter.useThousandSeparator) {
    valueString = valueString.replace(new RegExp(`${typeParameter.thousandSeparator}`, 'g'), '');
  }
  const isNegativeNumber = valueString[0] == '-';
  //remove all unrelated char from value
  valueString = faToEnDigits(valueString).replace(/[^0-9.]/g, '');
  if (isNegativeNumber && numberFieldParameters.acceptNegative) {
    valueString = '-' + valueString;
  }
  //if our input type is number and user want to set it to new value we do necessary logic here
  let value = Number(valueString);
  if (isNaN(value)) {
    //replace arabic and persian number
    valueString = valueString.replace(/\u06F0/g, '0').replace(/\u06F1/g, '1').replace(/\u06F2/g, '2').replace(/\u06F3/g, '3').replace(/\u06F4/g, '4').replace(/\u06F5/g, '5').replace(/\u06F6/g, '6').replace(/\u06F7/g, '7').replace(/\u06F8/g, '8').replace(/\u06F9/g, '9');
    value = parseFloat(valueString);
    //if invalidity is not for persian number
    if (isNaN(value)) {
      //we change nothing
      valueString = typeParameter.invalidNumberReplacement;
    }
  }
  // in input process we dont check fom min & max and keep it for change event because user want to type freely and apply min & max on blur
  // for the second condition we must let user leave input empty but if he input something we must check min & max
  if (eventType !== "INPUT" && valueString.length !== 0) {
    //add max and min checker to prevent bigger value assignment
    if (numberFieldParameters.maxValue && value > numberFieldParameters.maxValue) {
      value = numberFieldParameters.maxValue;
      valueString = `${numberFieldParameters.maxValue}`;
    }
    if (numberFieldParameters.minValue && value < numberFieldParameters.minValue) {
      value = numberFieldParameters.minValue;
      valueString = `${numberFieldParameters.minValue}`;
    }
  }
  //remove end . if user not typing
  if(eventType !=="INPUT" && valueString.endsWith('.')){
    valueString = valueString.substring(0,valueString.length-1);
  }
  const [integerNumbers, decimalNumbers] = valueString.split('.');

  const decimalPrecisionCount = decimalNumbers ? decimalNumbers.length : 0;
  if (numberFieldParameters && !(numberFieldParameters.decimalPrecision === null || numberFieldParameters.decimalPrecision == undefined) && decimalPrecisionCount && decimalPrecisionCount > numberFieldParameters.decimalPrecision) {
    // truncate extra decimal
    const checkRegex = new RegExp(`^-?\\d+(?:\\.\\d{0,${numberFieldParameters!.decimalPrecision}})?`);
    const match = valueString.match(checkRegex);
    if (match && match[0]) {
      valueString = match[0];
    }
  }
  //remove start zero when number is more than one digit 065 => 65
  if (integerNumbers.startsWith('0') && integerNumbers.length > 1) {
    valueString = valueString.substring(1);
  }
  if (integerNumbers.startsWith('-') && integerNumbers.charAt(1) == '0' && integerNumbers.length > 2) {
    valueString = '-' + valueString.substring(2);
  }
  //remove end zero when number is decimal 65.00 => 65
  if(eventType !== "INPUT" && decimalNumbers && decimalNumbers.endsWith('0')){
    valueString = valueString.replace(/(\.\d*?[1-9])0+|\.0+$/, '$1');
  }
  const standardValueObject: JBInputValue = {
    displayValue: valueString,
    value: valueString,
  };
  // add thousand separator comma
  if (typeParameter.useThousandSeparator) {
    standardValueObject.displayValue = valueString.replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, typeParameter.thousandSeparator);
  }
  //convert en number to persian number
  if (typeParameter.showPersianNumber) {
    standardValueObject.displayValue = enToFaDigits(standardValueObject.displayValue);
  }
  return standardValueObject;
}

export function isStringIsNumber(value: string | null): boolean {
  if (value == null || value == undefined || value.trim().length == 0) {
    return false;
  } else {
    let isNumber = !isNaN(Number(value));
    if (!isNumber) {
      const replacedNumberValue = faToEnDigits(value);
      isNumber = !isNaN(Number(replacedNumberValue));
    }
    return isNumber;
  }
}