/**
 * Copyright (c) 2022 - present TinyVue Authors.
 * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd.
 *
 * Use of this source code is governed by an MIT-style license.
 *
 * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
 * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
 * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
 *
 */
import type {
  IProgressRenderlessParams,
  IProgressBarStyle,
  IProgressPathStyle,
  IProgressIconStyle,
  IProgressColorItem
} from '@/types'

export const computedBarStyle =
  ({ api, props }: Pick<IProgressRenderlessParams, 'api' | 'props'>) =>
  (): IProgressBarStyle => ({
    width: props.percentage + '%',
    backgroundColor: api.getCurrentColor(props.percentage)
  })

export const computedRelativeStrokeWidth =
  ({ constants, state }: Pick<IProgressRenderlessParams, 'constants' | 'state'>) =>
  (): number => {
    if (state.width === 0 || state.strokeWidth === 0) return constants.REL_STROKE_WIDTH
    return Number(((state.strokeWidth / state.width) * 100).toFixed(1))
  }

export const computedRadius =
  ({ constants, props, state }: Pick<IProgressRenderlessParams, 'constants' | 'props' | 'state'>) =>
  (): number =>
    props.type === constants.PROGRESS_TYPE.CIRCLE || props.type === constants.PROGRESS_TYPE.DASHBOARD
      ? parseInt(String(50 - parseFloat(state.relativeStrokeWidth) / 2), 10)
      : 0

export const computedTrackPath =
  ({ constants, props, state }: Pick<IProgressRenderlessParams, 'constants' | 'props' | 'state'>) =>
  (): string => {
    const radiusValue = state.radius
    const isDashboardType = props.type === constants.PROGRESS_TYPE.DASHBOARD

    return `
    M 50 50
    m 0 ${isDashboardType ? '' : '-'}${radiusValue}
    a ${radiusValue} ${radiusValue} 0 1 1 0 ${isDashboardType ? '-' : ''}${radiusValue * 2}
    a ${radiusValue} ${radiusValue} 0 1 1 0 ${isDashboardType ? '' : '-'}${radiusValue * 2}
    `
  }

export const computedPerimeter =
  ({ state }: Pick<IProgressRenderlessParams, 'state'>) =>
  (): number =>
    2 * Math.PI * state.radius

export const computedRate =
  ({ constants, props }: Pick<IProgressRenderlessParams, 'constants' | 'props'>) =>
  (): number =>
    props.type === constants.PROGRESS_TYPE.DASHBOARD ? 0.75 : 1

export const computedStrokeDashoffset =
  ({ state }: Pick<IProgressRenderlessParams, 'state'>) =>
  (): string =>
    `${(-1 * state.perimeter * (1 - state.rate)) / 2}px`

export const computedTrailPathStyle =
  ({ state }: Pick<IProgressRenderlessParams, 'state'>) =>
  (): IProgressPathStyle => ({
    strokeDasharray: `${state.perimeter * state.rate}px, ${state.perimeter}px`,
    strokeDashoffset: state.strokeDashoffset
  })

export const computedCircleStyle =
  ({ state }: Pick<IProgressRenderlessParams, 'state'>) =>
  () =>
    state.width ? { height: state.width + 'px', width: state.width + 'px' } : {}

export const computedCirclePathStyle =
  ({ props, state }: Pick<IProgressRenderlessParams, 'props' | 'state'>) =>
  (): IProgressPathStyle => ({
    strokeDasharray: `${state.perimeter * state.rate * (props.percentage / 100)}px, ${state.perimeter}px`,
    strokeDashoffset: state.strokeDashoffset,
    transition: 'stroke-dasharray 0.6s ease 0s, stroke 0.6s ease'
  })

export const computedStroke =
  ({ api, constants, props }: Pick<IProgressRenderlessParams, 'api' | 'constants' | 'props'>) =>
  (): string =>
    (props.color && api.getCurrentColor(props.percentage)) ||
    constants.STATUS_TO_COLOR[props.status] ||
    constants.STATUS_DEFAULT_COLOR

export const computedIconClass =
  ({ constants, props, mode }: Pick<IProgressRenderlessParams, 'constants' | 'props' | 'mode'>) =>
  (): string => {
    if (props.status === constants.PROGRESS_STATUS.SUCCESS) {
      const iconClasses =
        props.type === constants.PROGRESS_TYPE.LINE
          ? [constants.ICON_SUCCESS, constants.ICON_CIRCLE_SUCCESS]
          : [constants.ICON_CIRCLE_SUCCESS, constants.ICON_SUCCESS]
      return mode === 'mobile-first' ? iconClasses[1] : iconClasses[0]
    } else if (props.status === constants.PROGRESS_STATUS.WARNING) {
      return props.type === constants.PROGRESS_TYPE.LINE ? constants.ICON_WARNING : constants.ICON_CIRCLE_WARNING
    } else if (props.status === constants.PROGRESS_STATUS.EXCEPTION) {
      const iconClasses =
        props.type === constants.PROGRESS_TYPE.LINE
          ? [constants.ICON_EXCEPTION, constants.ICON_CIRCLE_EXCEPTION]
          : [constants.ICON_CIRCLE_EXCEPTION, constants.ICON_EXCEPTION]
      return mode === 'mobile-first' ? iconClasses[1] : iconClasses[0]
    } else {
      return ''
    }
  }

export const computedIconStyle =
  ({ constants, props, state }: Pick<IProgressRenderlessParams, 'constants' | 'props' | 'state'>) =>
  (): IProgressIconStyle<number> | {} => {
    if (props.type === constants.PROGRESS_TYPE.LINE) {
      return state.strokeWidth
        ? {
            width: constants.TEXT_XS + state.strokeWidth * constants.STROKE_WIDTH_RATE,
            height: constants.TEXT_XS + state.strokeWidth * constants.STROKE_WIDTH_RATE
          }
        : {}
    } else {
      return state.width
        ? { width: state.width / constants.WIDTH_RATE_TWO, height: state.width / constants.WIDTH_RATE_TWO }
        : {}
    }
  }

export const computedProgressTextSize =
  ({ constants, props, state, mode }: Pick<IProgressRenderlessParams, 'constants' | 'props' | 'state' | 'mode'>) =>
  (): number => {
    if (mode === 'mobile-first') {
      let fontSize = constants.TEXT_XS
      const sizeWidthMap = {
        small: constants.PROGRESS_SIZE_WIDTH.SMALL,
        medium: constants.PROGRESS_SIZE_WIDTH.MEDIUM,
        large: constants.PROGRESS_SIZE_WIDTH.LARGE
      }

      if (props.type === constants.PROGRESS_TYPE.LINE) {
        fontSize = state.strokeWidth
          ? constants.TEXT_XS + state.strokeWidth * constants.STROKE_WIDTH_RATE
          : props.size === constants.PROGRESS_SIZE.SMALL
          ? constants.TEXT_XS
          : constants.TEXT_SM
      } else {
        const width = state.width ? state.width : sizeWidthMap[props.size]
        fontSize = width / constants.WIDTH_RATE_THREE
        state.percentTextSize = width / constants.WIDTH_RATE_SIX
      }
      return fontSize
    } else {
      return props.type === constants.PROGRESS_TYPE.LINE
        ? constants.TEXT_XS + state.strokeWidth * constants.STROKE_WIDTH_RATE
        : state.width * 0.111111 + 2
    }
  }

export const computedContent =
  ({ props }: Pick<IProgressRenderlessParams, 'props'>) =>
  (): string =>
    typeof props.format === 'function' ? props.format() || '' : `${props.percentage}%`

export const getCurrentColor =
  ({ api, props }: Pick<IProgressRenderlessParams, 'api' | 'props'>) =>
  (percentage) => {
    if (typeof props.color === 'function') {
      return props.color(percentage)
    } else if (typeof props.color === 'string') {
      return props.color
    } else {
      return api.getLevelColor(percentage)
    }
  }

export const getLevelColor =
  ({ api }: Pick<IProgressRenderlessParams, 'api'>) =>
  (percentage: number): string => {
    const colorArray = api.getColorArray().sort((a, b) => a.percentage - b.percentage)

    for (let i = 0; i < colorArray.length; i++) {
      if (colorArray[i].percentage > percentage) {
        return colorArray[i].color
      }
    }

    return colorArray[colorArray.length - 1].color
  }

export const getColorArray =
  ({ props }: Pick<IProgressRenderlessParams, 'props'>) =>
  (): IProgressColorItem[] => {
    const color = props.color
    const span = 100 / color.length

    return color.map((seriesColor, index) => {
      if (typeof seriesColor === 'string') {
        return {
          color: seriesColor,
          progress: (index + 1) * span
        }
      }

      return seriesColor
    })
  }

export const customBeforeAppearHook =
  ({ props, state }: Pick<IProgressRenderlessParams, 'props' | 'state'>) =>
  (el: HTMLElement) => {
    if (props.type === 'line') {
      el.style.width = String(0)
    } else if (props.type === 'circle') {
      el.style.strokeDasharray = String(state.perimeter * state.content)
      el.style.strokeDashoffset = state.perimeter
    }
  }

export const customAppearHook = (el: HTMLElement) => {
  el.style.transition = 'all 0.5s'
}

export const customAfterAppearHook =
  ({ state, props }: Pick<IProgressRenderlessParams, 'state' | 'props'>) =>
  (el: HTMLElement) => {
    if (props.type === 'line') {
      el.style.width = state.barStyle.width
    } else if (props.type === 'circle') {
      el.style.strokeDashoffset = String(0)
    }
  }