import { makeComponentProps } from '@/composables/component'
import { makeTagProps } from '@/composables/tag'
import { genericComponent, propsFactory } from '@/utils'
import {
  ExtractPropTypes,
  ref,
  shallowRef,
  watch,
  computed,
  onMounted,
  PropType,
} from 'vue'
import { USemiCircleXXS } from './UProgressCircleSVG/USemiCircleXXS'
import { USemiCircleXS } from './UProgressCircleSVG/USemiCircleXS'
import { USemiCircleSM } from './UProgressCircleSVG/USemiCircleSM'
import { USemiCircleMD } from './UProgressCircleSVG/USemiCircleMD'
import { USemiCircleLG } from './UProgressCircleSVG/USemiCircleLG'

export const makeUProgressCircleProps = propsFactory(
  {
    progress: {
      type: Number,
      default: 0,
      required: false,
    },
    shape: {
      type: String,
      default: 'circle',
      required: false,
    },
    size: {
      type: String,
      required: false,
    },
    label: {
      type: [String, undefined] as PropType<string | undefined>,
      default: undefined,
      required: false,
    },

    ...makeComponentProps(),
    ...makeTagProps(),
  },
  'UProgressCircle'
)

export type UProgressCircleProps = ExtractPropTypes<
  typeof makeUProgressCircleProps
>

export const UProgressCircle = genericComponent()({
  name: 'UProgressCircle',

  props: makeUProgressCircleProps(),

  setup(props) {
    const progress = ref(0)
    const size = ref(64)
    const cx = ref(32)
    const cy = ref(32)
    const r = ref(26)
    const strokeWidth = ref(6)
    const textSize = ref('text-text-sm')
    const strokeDasharray = ref(163.3)
    const strokeDashoffset = ref(98)
    const rotate = ref('-rotate-90')
    const progressDashoffset = ref(0)
    const semiCircleIcon = shallowRef<
      | typeof USemiCircleXXS
      | typeof USemiCircleXS
      | typeof USemiCircleSM
      | typeof USemiCircleMD
      | typeof USemiCircleLG
      | null
    >(null)
    const XXS_SCALE = 3.9
    const XS_SCALE = 1.59
    const SM_SCALE = 1.27
    const MD_SCALE = 1.05

    const label = computed(() => {
      return props.label
    })

    const labelSize = computed(() => {
      return props.size
    })

    onMounted(() => {
      cx.value = size.value / 2
      cy.value = size.value / 2
      r.value = size.value / 2 - strokeWidth.value

      strokeDasharray.value = 2 * Math.PI * r.value
      strokeDashoffset.value =
        strokeDasharray.value * ((100 - progress.value) / 100)

      rotate.value = '-rotate-90'

      if (props.size === 'xxs') {
        progressDashoffset.value = (-props.progress / XXS_SCALE) * 3.6 + 360
      } else if (props.size === 'xs') {
        progressDashoffset.value = (-props.progress / XS_SCALE) * 3.6 + 360
      } else if (props.size === 'sm') {
        progressDashoffset.value = (-props.progress / SM_SCALE) * 3.6 + 360
      } else if (props.size === 'md') {
        progressDashoffset.value = (-props.progress / MD_SCALE) * 3.6 + 360
      } else if (props.size === 'lg') {
        progressDashoffset.value = (1 - props.progress / 100) * 395
      }
    })

    watch([() => props.size, () => props.shape], ([sizeValue, shapeValue]) => {
      if (shapeValue === 'semi-circle' && sizeValue === 'xxs') {
        semiCircleIcon.value = USemiCircleXXS
      } else if (shapeValue === 'semi-circle' && sizeValue === 'xs') {
        semiCircleIcon.value = USemiCircleXS
      } else if (shapeValue === 'semi-circle' && sizeValue === 'sm') {
        semiCircleIcon.value = USemiCircleSM
      } else if (shapeValue === 'semi-circle' && sizeValue === 'md') {
        semiCircleIcon.value = USemiCircleMD
      } else if (shapeValue === 'semi-circle' && sizeValue === 'lg') {
        semiCircleIcon.value = USemiCircleLG
      }
    })

    watch(
      () => props.progress,
      (progressValue) => {
        progress.value = progressValue
        if (props.size === 'xxs') {
          progressDashoffset.value = (-progressValue / XXS_SCALE) * 3.6 + 360
        } else if (props.size === 'xs') {
          progressDashoffset.value = (-progressValue / XS_SCALE) * 3.6 + 360
        } else if (props.size === 'sm') {
          progressDashoffset.value = (-progressValue / SM_SCALE) * 3.6 + 360
        } else if (props.size === 'md') {
          progressDashoffset.value = (-progressValue / MD_SCALE) * 3.6 + 360
        } else if (props.size === 'lg') {
          progressDashoffset.value = (1 - progressValue / 100) * 395
        }
      }
    )

    watch(
      [() => props.size, () => r.value, () => props.progress],
      ([sizeValue, rValue, progressValue]) => {
        if (sizeValue === 'xxs') {
          strokeWidth.value = 6
          size.value = 64
          textSize.value = 'text-text-sm'
        } else if (sizeValue === 'xs') {
          strokeWidth.value = 16
          size.value = 160
          textSize.value = 'text-display-xs'
        } else if (sizeValue === 'sm') {
          strokeWidth.value = 20
          size.value = 200
          textSize.value = 'text-display-sm'
        } else if (sizeValue === 'md') {
          strokeWidth.value = 24
          size.value = 240
          textSize.value = 'text-display-md'
        } else {
          strokeWidth.value = 28
          size.value = 280
          textSize.value = 'text-display-lg'
        }

        cx.value = size.value / 2
        cy.value = size.value / 2
        r.value = size.value / 2 - strokeWidth.value
        progress.value = progressValue

        strokeDasharray.value = 2 * Math.PI * rValue
        strokeDashoffset.value =
          strokeDasharray.value * ((100 - progressValue) / 100)

        rotate.value = '-rotate-90'
      }
    )

    const textAlignClasses = computed(() => {
      let alignClasses = ''
      if (
        (props.shape === 'circle' && props.size !== 'xxs') ||
        (props.label === undefined && props.shape === 'circle')
      ) {
        alignClasses = `top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2`
      } else if (
        props.shape === 'semi-circle' &&
        props.size !== 'xxs' &&
        props.label === undefined
      ) {
        alignClasses = `left-1/2 transform -translate-x-1/2 top-0.33`
      } else if (
        props.shape === 'semi-circle' &&
        props.size === 'xxs' &&
        props.label === undefined
      ) {
        alignClasses = `left-1/2 transform -translate-x-1/2 top-0.28`
      } else if (props.shape === 'semi-circle' && props.label !== undefined) {
        alignClasses = `left-1/2 transform -translate-x-1/2 top-0.26`
      } else if (
        props.shape === 'circle' &&
        props.size === 'xxs' &&
        props.label !== undefined
      ) {
        alignClasses = `gap-5 left-1/2 transform -translate-x-1/2 top-0.37`
      }

      return alignClasses
    })

    const TextClasses = computed<string>(
      () =>
        `absolute ${textAlignClasses.value} text-gray-900 flex flex-col items-center align-center`
    )

    const textClasses = computed(() => ({
      [TextClasses.value]: true,
    }))

    return () => (
      <div class={props.class}>
        <div class="relative">
          {props.shape === 'circle' ? (
            <svg
              style={`width: ${size.value}px; height: ${size.value}px;`}
              class={rotate.value}
              stroke-dashoffset={`${strokeDashoffset.value}px`}
            >
              <circle
                class="stroke-gray-200"
                cx={cx.value}
                cy={cy.value}
                r={r.value}
                fill="transparent"
                stroke-width={strokeWidth.value}
              />
              <circle
                class="stroke-primary-600"
                stroke-dasharray={`${strokeDasharray.value}px`}
                stroke-dashoffset={`${strokeDashoffset.value}px`}
                stroke-linecap="round"
                cx={cx.value}
                cy={cy.value}
                r={r.value}
                fill="transparent"
                stroke-width={strokeWidth.value}
              />
            </svg>
          ) : semiCircleIcon.value ? (
            <semiCircleIcon.value
              shape={props.shape}
              size={props.size}
              progress={props.progress}
              progressDashoffset={progressDashoffset.value}
            />
          ) : null}
          <span class={textClasses.value}>
            {label.value !== undefined && labelSize.value !== 'xxs' ? (
              <span
                class={[
                  labelSize.value === 'md' || labelSize.value === 'ld'
                    ? 'text-text-sm'
                    : 'text-text-xs',
                  'font-medium',
                ]}
              >
                {props.label}
              </span>
            ) : null}
            <span
              class={[
                textSize.value,
                'font-medium transition-all duration-500 ease-in-out',
              ]}
            >
              {props.progress}%
            </span>
            {label.value !== undefined && labelSize.value === 'xxs' ? (
              <span class="text-text-sm font-medium">{props.label}</span>
            ) : null}
          </span>
        </div>
      </div>
    )
  },
})

export type UProgressCircle = InstanceType<typeof UProgressCircle>
