function isDirty(
  obj1: Record<string, unknown> | null | undefined,
  obj2: Record<string, unknown> | null | undefined
): boolean {
  const actualObj1 = obj1 ?? {}
  const actualObj2 = obj2 ?? {}

  const filteredObj1 = filterIgnored(actualObj1)
  const filteredObj2 = filterIgnored(actualObj2)

  const allKeys = new Set([...Object.keys(filteredObj1), ...Object.keys(filteredObj2)])

  for (const key of allKeys) {
    const hasKey1 = Object.hasOwn(filteredObj1, key)
    const hasKey2 = Object.hasOwn(filteredObj2, key)
    
    // Различие в наличии ключа
    if (hasKey1 !== hasKey2) return true
    
    if (hasKey1 && hasKey2) {
      const val1 = filteredObj1[key]
      const val2 = filteredObj2[key]
      
      // Сравнение массивов
      if (Array.isArray(val1) && Array.isArray(val2)) {
        if (val1.length !== val2.length) return true
        const set2 = new Set(val2)
        if (!val1.every(item => set2.has(item))) return true
      } 
      // Один массив, другой - нет
      else if (Array.isArray(val1) || Array.isArray(val2)) {
        return true
      }
      // Сравнение строк
      else if (typeof val1 === 'string' && typeof val2 === 'string') {
        if (val1.trim() !== val2.trim()) return true
      } 
      // Сравнение примитивов
      else if (val1 !== val2) {
        return true
      }
    }
  }

  return false
}

function filterIgnored(obj: Record<string, unknown>): Record<string, string | number | boolean | (string | number)[]> {
  const filtered: Record<string, string | number | boolean | (string | number)[]> = {}

  for (const key in obj) {
    const value = obj[key]
    
    // Обработка массивов
    if (Array.isArray(value)) {
      // Отбрасываем пустые массивы
      if (value.length === 0) continue
      
      // Фильтруем массивы с некорректными элементами
      if (value.every(item => 
        typeof item === 'string' || 
        typeof item === 'number'
      )) {
        filtered[key] = value
      }
      continue
    }
    
    // Обработка примитивов
    if (typeof value !== 'string' && typeof value !== 'number' && typeof value !== 'boolean') {
      continue
    }

    // Обработка строк
    if (typeof value === 'string') {
      const trimmed = value.trim()
      if (trimmed === '') continue
      filtered[key] = trimmed
    } 
    // Обработка чисел и boolean
    else if (value !== 0 && value !== false) {
      filtered[key] = value
    }
  }

  return filtered
}

function parseIntString (s: string | string[] | undefined) :number | null {
  if (typeof s !== 'string') return null
  const regex = /^[+-]?\d+$/
  return regex.test(s) ? Number(s) : null 
}

export {
  isDirty,
  parseIntString
}