import type { CSSProperties } from 'vue'
import { hyphenate } from './common'
import { isArray, isEmpty, isNumber, isObject, isString } from './is'
import type { CommonProps } from './props'

export type NormalizedStyle = Record<string, string | number>

const listDelimiterRE = /;(?![^(]*\))/g
const propertyDelimiterRE = /:([\s\S]+)/
const styleCommentRE = /\/\*.*?\*\//g

export function parseStringStyle(cssText: string): NormalizedStyle {
  const ret: NormalizedStyle = {}
  for (const item of cssText.replace(styleCommentRE, '').split(listDelimiterRE)) {
    if (item) {
      const tmp = item.split(propertyDelimiterRE)
      // eslint-disable-next-line @typescript-eslint/no-unused-expressions
      tmp.length > 1 && (ret[tmp[0].trim()] = tmp[1].trim())
    }
  }
  return ret
}

export function stringifyStyle(styles: NormalizedStyle | string | undefined): string {
  let ret = ''
  if (!styles || isString(styles)) return ret

  for (const key in styles) {
    const value = styles[key]
    const normalizedKey = key.startsWith('--') ? key : hyphenate(key)
    if (isString(value) || typeof value === 'number') {
      // only render valid values
      ret += `${normalizedKey}:${value};`
    }
  }
  return ret
}

export function getPx(value: string | number, unit = false) {
  if (isNumber(value)) return unit ? `${value}px` : Number(value)

  return unit ? `${Number.parseInt(value)}px` : Number.parseInt(value)
}

/**
 * @description 样式转换
 * 对象转字符串，或者字符串转对象
 * @param {object | string} customStyle 需要转换的目标
 * @param {string} target 转换的目的，object-转为对象，string-转为字符串
 */
export function addStyle(customStyle: string | object, target = 'object') {
  // 字符串转字符串，对象转对象情形，直接返回
  if (isEmpty(customStyle) || (typeof customStyle === 'object' && target === 'object') || (target === 'string' && typeof customStyle === 'string')) {
    return customStyle
  }

  // 字符串转对象
  if (target === 'object') {
    // 去除字符串样式中的两端空格(中间的空格不能去掉，比如padding: 20px 0如果去掉了就错了)，空格是无用的
    customStyle = trim(customStyle)
    // 根据";"将字符串转为数组形式
    const styleArray = customStyle.split(';')
    const style: any = {}
    // 历遍数组，拼接成对象
    for (const element_ of styleArray) {
      // 'font-size:20px;color:red;'，如此最后字符串有";"的话，会导致styleArray最后一个元素为空字符串，这里需要过滤
      if (element_) {
        const item = element_.split(':')
        style[trim(item[0])] = trim(item[1])
      }
    }
    return style
  }
  // 这里为对象转字符串形式
  let string = ''
  for (const i in customStyle as any) {
    // 驼峰转为中划线的形式，否则css内联样式，无法识别驼峰样式属性名
    const key = i.replace(/([A-Z])/g, '-$1').toLowerCase()
    string += `${key}:${customStyle[i]};`
  }
  // 去除两端空格
  return trim(string)
}

/**
 * @description 去除空格
 * @param str 需要去除空格的字符串
 * @param pos both(左右)|left|right|all 默认both
 */
export function trim(str: string, pos = 'both') {
  str = String(str)
  if (pos === 'both') return str.replace(/^\s+|\s+$/g, '')

  if (pos === 'left') return str.replace(/^\s*/, '')

  if (pos === 'right') return str.replace(/(\s*$)/g, '')

  if (pos === 'all') return str.replace(/\s+/g, '')

  return str
}

export function normalizeStyle(value: unknown): NormalizedStyle | string | undefined {
  if (isArray(value)) {
    const res: NormalizedStyle = {}
    for (const item of value) {
      const normalized = isString(item) ? parseStringStyle(item) : (normalizeStyle(item) as NormalizedStyle)
      if (normalized) {
        for (const key in normalized) {
          if (!isEmpty(normalized[key])) res[key] = normalized[key]
        }
      }
    }

    return res
  }
  if (isString(value)) return value

  if (isObject(value)) return value
}

export function normalizeClass(value: unknown): string {
  let res = ''
  if (isString(value)) {
    res = value
  } else if (isArray(value)) {
    for (const element_ of value) {
      const normalized = normalizeClass(element_)
      if (normalized) res += `${normalized} `
    }
  } else if (isObject(value)) {
    for (const name in value) {
      if (value[name]) res += `${name} `
    }
  }
  return res.trim()
}

export function getMainClass(props: CommonProps, componentName: string, cls?: object) {
  return normalizeClass([props.customClass, { [componentName]: true }, cls])
}

export function getMainStyle(props: CommonProps, style?: CSSProperties) {
  return stringifyStyle(normalizeStyle([props.customStyle, style]))
}
