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 = {}
  cssText
    .replace(styleCommentRE, '')
    .split(listDelimiterRE)
    .forEach((item) => {
      if (item) {
        const tmp = item.split(propertyDelimiterRE)
        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 (let i = 0; i < styleArray.length; i++) {
      // 'font-size:20px;color:red;'，如此最后字符串有";"的话，会导致styleArray最后一个元素为空字符串，这里需要过滤
      if (styleArray[i]) {
        const item = styleArray[i].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 (let i = 0; i < value.length; i++) {
      const item = value[i]
      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 (let i = 0; i < value.length; i++) {
      const normalized = normalizeClass(value[i])
      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]))
}
