/**
 * Check if an object is not empty.
 * @param {Object} obj - The object to check.
 * @returns {boolean} - Returns true if the object is not empty, false otherwise.
 */
export const isObjectNotEmpty = (obj) => {
  if (!obj) {
    return false
  }
  return Object.keys(obj).length > 0
}

export const isNotEmptyArray = (array) => {
  return Array.isArray(array) && array.length
}

export const isEmptyArray = (array) => {
  return !isNotEmptyArray(array)
}

/**
 * ex) const params = {page:10, searchDvsnCd: 20}
 * @param {*} params
 * @returns page=10&searchDvsnCd=20
 */
export const queryStringFormatter = (params = {}) => {
  const queries = []
  Object.keys(params).forEach((parameterKey) => {
    const parameterValue = params[parameterKey]

    if (parameterValue === undefined || parameterValue === null) {
      return
    }

    // string trim
    if (typeof parameterValue === 'string' && !parameterValue.trim()) {
      return
    }

    // array to query string
    if (Array.isArray(parameterValue)) {
      // primitive type
      if (parameterValue.every((v) => typeof v === 'number' || typeof v === 'string')) {
        queries.push(`${encodeURIComponent(parameterKey)}=${parameterValue.map((v) => encodeURIComponent(v)).join(',')}`)
        return
      }
      // reference type
      if (parameterValue.every((v) => typeof v === 'object' && v !== null)) {
        parameterValue.map((pv, i) => {
          return Object.keys(pv).forEach((valueKey) => {
            queries.push(`${encodeURIComponent(`${parameterKey}[${i}].${valueKey}`)}=${encodeURIComponent(pv[valueKey])}`)
          })
        })
        return
      }
    }
    // 나머지
    queries.push(`${encodeURIComponent(parameterKey)}=${encodeURIComponent(parameterValue)}`)
  })
  return queries.join('&')
}

// 43000 --> 43,000
export const convertNumberToPriceDecimal = (value) => {
  if (value) return Number(value).toLocaleString()
  else if (value === 0) return 0
  else return ''
}

// 43000.458 --> 43,000.46
export const convertNumberToPriceDecimalToFixed = (value, fixed) => {
  if (value) return Number(value).toLocaleString(undefined, { minimumFractionDigits: fixed, maximumFractionDigits: fixed })
  else if (value === 0) return 0
  else return ''
}

// 전화번호, FAX 번호 숫자 or '-'만 입력 체크
export const inputTelNumberCheck = (e) => {
  const input = e.target
  if (/^[\d-]*$/g.test(input.value)) {
    input.value = input.value
  } else {
    input.value = input.value.replace(/[^\d-]/g, '')
  }
}

// 숫자만 입력 체크
export const inputNumberCheck = (e) => {
  const input = e.target
  if (/^[\d]*$/g.test(input.value)) {
    input.value = input.value
  } else {
    input.value = input.value.replace(/[^\d]/g, '')
  }
}

// 값이 숫자인지 확인
export const numberCheck = (value) => {
  return !isNaN(value)
}

/**
 * 파이프함수 정의
 * @param  {...any} fns 순수함수들
 * @returns
 */
export const pipe =
  (...fns) =>
  (x) =>
    fns.reduce((v, f) => f(v), x)

/**
 * 캔버스 각도에 따른 흐름 방향 계산
 * @param {number} canvasAngle
 * @returns {object} 흐름 방향 객체
 */
export const calculateFlowDirection = (canvasAngle) => {
  return {
    down: -canvasAngle,
    up: 180 - canvasAngle,
    left: 90 - canvasAngle < 180 ? 90 - canvasAngle : 90 - canvasAngle - 360,
    right: -90 - canvasAngle < -180 ? -90 - canvasAngle + 360 : -90 - canvasAngle,
  }
}

/**
 * 자바스크립트 객체로 쿼리스트링 생성
 * @param {javascript object} o 쿼리스트링 생성할 객체
 * @returns {string} 쿼리스트링
 */
export const getQueryString = (o) => {
  const queryString = Object.keys(o)
    .map((key) => `${key}=${o[key] ?? ''}`)
    .join('&')
  return `?${queryString}`
}

export const unescapeString = (str) => {
  const regex = /&(amp|lt|gt|quot|#39);/g
  const chars = {
    '&amp;': '&',
    '&lt;': '<',
    '&gt;': '>',
    '&quot;': '"',
    '&#39;': "'",
  }

  /*
  1. 한번 변환은 {&quot; 로 변환됨 : 에러 발생 => while 변경
  2. 변환할 내용이 없으면 리턴값이 undefined

  if (regex.test(str)) {
    return str.replace(regex, (matched) => chars[matched] || matched)
  }
  */

  while (regex.test(str)) {
    str = str.replace(regex, (matched) => chars[matched] || matched);
  }
  return str
}

export const isNullOrUndefined = (value) => {
  return value === null || value === undefined
}

export const isEqualObjects = (obj1, obj2) => {
  const keys1 = Object.keys(obj1)
  const keys2 = Object.keys(obj2)

  if (keys1.length !== keys2.length) return false

  for (let key of keys1) {
    const val1 = obj1[key]
    const val2 = obj2[key]
    const areObjects = isObject(val1) && isObject(val2)

    if (areObjects && !deepEqual(val1, val2)) return false
    if (!areObjects && val1 !== val2) return false
  }

  return true
}

function isObject(value) {
  return value !== null && typeof value === 'object'
}


// 카멜케이스를 스네이크케이스로 변환하는 함수
export const toSnakeCase = (str) => {
  return str.replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`);
}

// 객체의 키를 스네이크케이스로 변환하는 함수
export const convertToSnakeCase = (obj) => {
  if (obj === null || obj === undefined) return obj;
  
  if (Array.isArray(obj)) {
    return obj.map((item) => convertToSnakeCase(item))
  }

  if (typeof obj === 'object') {
    return Object.keys(obj).reduce((acc, key) => {
      const snakeKey = toSnakeCase(key).toUpperCase();
      acc[snakeKey] = convertToSnakeCase(obj[key]);
      return acc;
    }, {});
  }
  
  return obj;
}
