import { isClient } from '@vueuse/core'
import { isNumber, isObject, isString } from '../types'
import { camelize } from '../strings'
import { entriesOf, keysOf } from '../objects'
import { debugWarn } from '../error'
import type { CSSProperties } from 'vue'

const SCOPE = 'utils/dom/style'

export const classNameToArray = (cls = '') => cls.split(' ').filter(item => !!item.trim())

export const hasClass = (el: Element, cls: string): boolean => {
    if (!el || !cls) return false
    if (cls.includes(' ')) throw new Error('className should not contain space.')
    return el.classList.contains(cls)
}

export const addClass = (el: Element, cls: string) => {
    if (!el || !cls.trim()) return
    el.classList.add(...classNameToArray(cls))
}

export const removeClass = (el: Element, cls: string) => {
    if (!el || !cls.trim()) return
    el.classList.remove(...classNameToArray(cls))
}

export const getStyle = (element: HTMLElement, styleName: keyof CSSProperties): string => {
    if (!isClient || !element || !styleName) return ''

    let key = camelize(styleName)
    if (key === 'float') key = 'cssFloat'
    try {
        const style = (element.style as any)[key]
        if (style) return style
        const computed: any = document.defaultView?.getComputedStyle(element, '')
        return computed ? computed[key] : ''
    } catch {
        return (element.style as any)[key]
    }
}

export const setStyle = (element: HTMLElement, styleName: CSSProperties | keyof CSSProperties, value?: string | number) => {
    if (!element || !styleName) return

    if (isObject(styleName)) {
        entriesOf(styleName).forEach(([prop, value]) => setStyle(element, prop, value))
    } else {
        const key: any = camelize(styleName)
        element.style[key] = value as any
    }
}

export const removeStyle = (element: HTMLElement, style: CSSProperties | keyof CSSProperties) => {
    if (!element || !style) return

    if (isObject(style)) {
        keysOf(style).forEach(prop => removeStyle(element, prop))
    } else {
        setStyle(element, style, '')
    }
}

export function addUnit(value?: string | number, defaultUnit = 'px') {
    if (!value) return ''
    if (isString(value)) {
        return value
    } else if (isNumber(value)) {
        return `${value}${defaultUnit}`
    }
    debugWarn(SCOPE, 'binding value must be a string or number')
}
