import { describe, it, expect } from 'vitest'
import { DEFAULT_FUNCTIONS } from './functions'

describe('DEFAULT_FUNCTIONS', () => {
  // ==================== Математические ====================

  describe('СУММ', () => {
    it('суммирует числа', () => {
      expect(DEFAULT_FUNCTIONS.СУММ(1, 2, 3)).toBe(6)
    })
    it('суммирует массив', () => {
      expect(DEFAULT_FUNCTIONS.СУММ([1, 2, 3])).toBe(6)
    })
    it('игнорирует не-числа', () => {
      expect(DEFAULT_FUNCTIONS.СУММ(1, 'abc', 3)).toBe(4)
    })
    it('возвращает 0 без аргументов', () => {
      expect(DEFAULT_FUNCTIONS.СУММ()).toBe(0)
    })
  })

  describe('СРЗНАЧ', () => {
    it('считает среднее', () => {
      expect(DEFAULT_FUNCTIONS.СРЗНАЧ(2, 4, 6)).toBe(4)
    })
    it('игнорирует не-числа', () => {
      expect(DEFAULT_FUNCTIONS.СРЗНАЧ(2, 'abc', 4)).toBe(3)
    })
    it('возвращает 0 если нет чисел', () => {
      expect(DEFAULT_FUNCTIONS.СРЗНАЧ('a', 'b')).toBe(0)
    })
  })

  describe('СЧЁТ', () => {
    it('считает количество чисел', () => {
      expect(DEFAULT_FUNCTIONS['СЧЁТ'](1, 'a', 2, null, 3)).toBe(3)
    })
    it('возвращает 0 без чисел', () => {
      expect(DEFAULT_FUNCTIONS['СЧЁТ']('a', 'b')).toBe(0)
    })
  })

  describe('МАКС', () => {
    it('возвращает максимум', () => {
      expect(DEFAULT_FUNCTIONS.МАКС(3, 7)).toBe(7)
    })
    it('ошибка при не-числах', () => {
      expect(DEFAULT_FUNCTIONS.МАКС('a' as any, 1)).toBe('#ЗНАЧ!')
    })
    it('ошибка при Infinity', () => {
      expect(DEFAULT_FUNCTIONS.МАКС(Infinity, 1)).toBe('#ЧИСЛО!')
    })
  })

  describe('МИН', () => {
    it('возвращает минимум', () => {
      expect(DEFAULT_FUNCTIONS.МИН(3, 7, 1)).toBe(1)
    })
    it('работает с массивом', () => {
      expect(DEFAULT_FUNCTIONS.МИН([3, 7, 1])).toBe(1)
    })
    it('возвращает 0 без чисел', () => {
      expect(DEFAULT_FUNCTIONS.МИН('a', 'b')).toBe(0)
    })
  })

  describe('ABS', () => {
    it('возвращает модуль', () => {
      expect(DEFAULT_FUNCTIONS.ABS(-5)).toBe(5)
      expect(DEFAULT_FUNCTIONS.ABS(5)).toBe(5)
      expect(DEFAULT_FUNCTIONS.ABS(0)).toBe(0)
    })
    it('ошибка при не-числе', () => {
      expect(DEFAULT_FUNCTIONS.ABS('abc' as any)).toBe('#ЗНАЧ!')
    })
    it('ошибка при Infinity', () => {
      expect(DEFAULT_FUNCTIONS.ABS(Infinity)).toBe('#ЧИСЛО!')
    })
  })

  describe('КОРЕНЬ', () => {
    it('возвращает корень', () => {
      expect(DEFAULT_FUNCTIONS['КОРЕНЬ'](9)).toBe(3)
      expect(DEFAULT_FUNCTIONS['КОРЕНЬ'](0)).toBe(0)
    })
    it('ошибка при отрицательном числе', () => {
      expect(DEFAULT_FUNCTIONS['КОРЕНЬ'](-4)).toBe('#ЧИСЛО!')
    })
    it('ошибка при не-числе', () => {
      expect(DEFAULT_FUNCTIONS['КОРЕНЬ']('abc' as any)).toBe('#ЗНАЧ!')
    })
  })

  describe('СТЕПЕНЬ', () => {
    it('возводит в степень', () => {
      expect(DEFAULT_FUNCTIONS['СТЕПЕНЬ'](2, 3)).toBe(8)
      expect(DEFAULT_FUNCTIONS['СТЕПЕНЬ'](5, 0)).toBe(1)
      expect(DEFAULT_FUNCTIONS['СТЕПЕНЬ'](9, 0.5)).toBe(3)
    })
    it('ошибка при не-числе', () => {
      expect(DEFAULT_FUNCTIONS['СТЕПЕНЬ']('a' as any, 2)).toBe('#ЗНАЧ!')
    })
    it('ошибка при Infinity', () => {
      expect(DEFAULT_FUNCTIONS['СТЕПЕНЬ'](Infinity, 2)).toBe('#ЧИСЛО!')
    })
    it('ошибка при переполнении', () => {
      expect(DEFAULT_FUNCTIONS['СТЕПЕНЬ'](10, 1000)).toBe('#ЧИСЛО!')
    })
  })

  // ==================== Сравнение ====================

  describe('БОЛЬШЕ', () => {
    it('возвращает true когда первое больше', () => {
      expect(DEFAULT_FUNCTIONS['БОЛЬШЕ'](5, 3)).toBe(true)
    })
    it('возвращает false когда первое меньше', () => {
      expect(DEFAULT_FUNCTIONS['БОЛЬШЕ'](3, 5)).toBe(false)
    })
    it('возвращает false при равенстве', () => {
      expect(DEFAULT_FUNCTIONS['БОЛЬШЕ'](5, 5)).toBe(false)
    })
    it('ошибка при не-числах', () => {
      expect(DEFAULT_FUNCTIONS['БОЛЬШЕ']('a' as any, 1)).toBe('#ЗНАЧ!')
    })
    it('ошибка при Infinity', () => {
      expect(DEFAULT_FUNCTIONS['БОЛЬШЕ'](Infinity, 1)).toBe('#ЧИСЛО!')
    })
  })

  describe('МЕНЬШЕ', () => {
    it('возвращает true когда первое меньше', () => {
      expect(DEFAULT_FUNCTIONS['МЕНЬШЕ'](3, 5)).toBe(true)
    })
    it('возвращает false когда первое больше', () => {
      expect(DEFAULT_FUNCTIONS['МЕНЬШЕ'](5, 3)).toBe(false)
    })
    it('возвращает false при равенстве', () => {
      expect(DEFAULT_FUNCTIONS['МЕНЬШЕ'](5, 5)).toBe(false)
    })
    it('ошибка при не-числах', () => {
      expect(DEFAULT_FUNCTIONS['МЕНЬШЕ']('a' as any, 1)).toBe('#ЗНАЧ!')
    })
  })

  describe('ЕПУСТО', () => {
    it('true для null', () => {
      expect(DEFAULT_FUNCTIONS['ЕПУСТО'](null)).toBe(true)
    })
    it('true для undefined', () => {
      expect(DEFAULT_FUNCTIONS['ЕПУСТО'](undefined)).toBe(true)
    })
    it('true для пустой строки', () => {
      expect(DEFAULT_FUNCTIONS['ЕПУСТО']('')).toBe(true)
    })
    it('false для числа', () => {
      expect(DEFAULT_FUNCTIONS['ЕПУСТО'](0)).toBe(false)
    })
    it('false для строки', () => {
      expect(DEFAULT_FUNCTIONS['ЕПУСТО']('текст')).toBe(false)
    })
    it('false для false', () => {
      expect(DEFAULT_FUNCTIONS['ЕПУСТО'](false)).toBe(false)
    })
  })

  // ==================== Логические ====================

  describe('ЕСЛИ', () => {
    it('возвращает значение при истине', () => {
      expect(DEFAULT_FUNCTIONS['ЕСЛИ'](true, 'да', 'нет')).toBe('да')
    })
    it('возвращает значение при лжи', () => {
      expect(DEFAULT_FUNCTIONS['ЕСЛИ'](false, 'да', 'нет')).toBe('нет')
    })
  })

  describe('И', () => {
    it('true когда все true', () => {
      expect(DEFAULT_FUNCTIONS['И'](true, true, true)).toBe(true)
    })
    it('false когда хоть один false', () => {
      expect(DEFAULT_FUNCTIONS['И'](true, false, true)).toBe(false)
    })
  })

  describe('ИЛИ', () => {
    it('true когда хоть один true', () => {
      expect(DEFAULT_FUNCTIONS['ИЛИ'](false, true, false)).toBe(true)
    })
    it('false когда все false', () => {
      expect(DEFAULT_FUNCTIONS['ИЛИ'](false, false, false)).toBe(false)
    })
  })

  describe('НЕ', () => {
    it('инвертирует true', () => {
      expect(DEFAULT_FUNCTIONS['НЕ'](true)).toBe(false)
    })
    it('инвертирует false', () => {
      expect(DEFAULT_FUNCTIONS['НЕ'](false)).toBe(true)
    })
  })

  // ==================== Строковые ====================

  describe('СЦЕПИТЬ', () => {
    it('объединяет строки', () => {
      expect(DEFAULT_FUNCTIONS['СЦЕПИТЬ']('Привет', ' ', 'мир')).toBe(
        'Привет мир'
      )
    })
  })

  describe('ДЛСТР', () => {
    it('возвращает длину строки', () => {
      expect(DEFAULT_FUNCTIONS['ДЛСТР']('hello')).toBe(5)
    })
    it('возвращает 0 для пустого', () => {
      expect(DEFAULT_FUNCTIONS['ДЛСТР']('')).toBe(0)
    })
  })

  describe('ПРОПИСН', () => {
    it('переводит в верхний регистр', () => {
      expect(DEFAULT_FUNCTIONS['ПРОПИСН']('hello')).toBe('HELLO')
    })
  })

  describe('СТРОЧН', () => {
    it('переводит в нижний регистр', () => {
      expect(DEFAULT_FUNCTIONS['СТРОЧН']('HELLO')).toBe('hello')
    })
  })

  describe('СЖПРОБЕЛЫ', () => {
    it('удаляет пробелы по краям', () => {
      expect(DEFAULT_FUNCTIONS['СЖПРОБЕЛЫ']('  hello  ')).toBe('hello')
    })
  })

  // ==================== Округление ====================

  describe('ОКРУГЛ', () => {
    it('округляет до целого', () => {
      expect(DEFAULT_FUNCTIONS['ОКРУГЛ'](3.7)).toBe(4)
      expect(DEFAULT_FUNCTIONS['ОКРУГЛ'](3.2)).toBe(3)
    })
    it('округляет до разрядов', () => {
      expect(DEFAULT_FUNCTIONS['ОКРУГЛ'](3.456, 2)).toBe(3.46)
    })
  })

  describe('ОКРУГЛВВЕРХ', () => {
    it('округляет вверх', () => {
      expect(DEFAULT_FUNCTIONS['ОКРУГЛВВЕРХ'](3.1)).toBe(4)
    })
    it('округляет вверх с разрядами', () => {
      expect(DEFAULT_FUNCTIONS['ОКРУГЛВВЕРХ'](3.411, 1)).toBe(3.5)
    })
  })

  describe('ОКРУГЛВНИЗ', () => {
    it('округляет вниз', () => {
      expect(DEFAULT_FUNCTIONS['ОКРУГЛВНИЗ'](3.9)).toBe(3)
    })
  })

  describe('ОКРВВЕРХ', () => {
    it('округляет вверх до кратного', () => {
      expect(DEFAULT_FUNCTIONS['ОКРВВЕРХ'](7, 5)).toBe(10)
    })
    it('возвращает 0 при кратном 0', () => {
      expect(DEFAULT_FUNCTIONS['ОКРВВЕРХ'](7, 0)).toBe(0)
    })
  })

  describe('ОКРВНИЗ', () => {
    it('округляет вниз до кратного', () => {
      expect(DEFAULT_FUNCTIONS['ОКРВНИЗ'](7, 5)).toBe(5)
    })
  })

  describe('ЦЕЛОЕ', () => {
    it('отбрасывает дробную часть вниз', () => {
      expect(DEFAULT_FUNCTIONS['ЦЕЛОЕ'](3.9)).toBe(3)
      expect(DEFAULT_FUNCTIONS['ЦЕЛОЕ'](-3.1)).toBe(-4)
    })
  })

  describe('ОТБР', () => {
    it('отбрасывает дробную часть', () => {
      expect(DEFAULT_FUNCTIONS['ОТБР'](3.9)).toBe(3)
      expect(DEFAULT_FUNCTIONS['ОТБР'](-3.9)).toBe(-3)
    })
    it('с разрядами', () => {
      expect(DEFAULT_FUNCTIONS['ОТБР'](3.456, 2)).toBe(3.45)
    })
  })

  describe('ОКРУГЛТ', () => {
    it('округляет до кратного', () => {
      expect(DEFAULT_FUNCTIONS['ОКРУГЛТ'](7, 5)).toBe(5)
      expect(DEFAULT_FUNCTIONS['ОКРУГЛТ'](8, 5)).toBe(10)
    })
    it('возвращает 0 при кратном 0', () => {
      expect(DEFAULT_FUNCTIONS['ОКРУГЛТ'](7, 0)).toBe(0)
    })
  })

  // ==================== Случайные ====================

  describe('СЛУЧ', () => {
    it('возвращает число от 0 до 1', () => {
      const result = DEFAULT_FUNCTIONS['СЛУЧ']()
      expect(result).toBeGreaterThanOrEqual(0)
      expect(result).toBeLessThan(1)
    })
  })

  describe('СЛУЧМЕЖДУ', () => {
    it('возвращает целое число в диапазоне', () => {
      for (let i = 0; i < 20; i++) {
        const result = DEFAULT_FUNCTIONS['СЛУЧМЕЖДУ'](1, 10) as number
        expect(result).toBeGreaterThanOrEqual(1)
        expect(result).toBeLessThanOrEqual(10)
        expect(Number.isInteger(result)).toBe(true)
      }
    })
  })

  describe('СЛУЧДР', () => {
    it('возвращает число в диапазоне', () => {
      for (let i = 0; i < 20; i++) {
        const result = DEFAULT_FUNCTIONS['СЛУЧДР'](1, 10, 2) as number
        expect(result).toBeGreaterThanOrEqual(1)
        expect(result).toBeLessThanOrEqual(10)
      }
    })
    it('ошибка при не-числах', () => {
      expect(DEFAULT_FUNCTIONS['СЛУЧДР']('a' as any, 10, 2)).toBe('#ЗНАЧ!')
    })
    it('ошибка при Infinity', () => {
      expect(DEFAULT_FUNCTIONS['СЛУЧДР'](Infinity, 10, 2)).toBe('#ЧИСЛО!')
    })
    it('меняет местами если низ > верх', () => {
      for (let i = 0; i < 20; i++) {
        const result = DEFAULT_FUNCTIONS['СЛУЧДР'](10, 1, 0) as number
        expect(result).toBeGreaterThanOrEqual(1)
        expect(result).toBeLessThanOrEqual(10)
      }
    })
  })
})
