import { ExtractPropTypes } from 'vue'
import { makeComponentProps } from '@/composables/component'
import { IconValue, useIcon } from '@/composables/icons'
import { makeSizeProps, useSize } from '@/composables/size'
import { makeTagProps } from '@/composables/tag'
import { getIconComponentName } from '@/utils'
import './UIconStyles.scss'
import { UIconParentContainer } from './UIconParentContainer'

import { computed, ref, Text } from 'vue'
import {
  convertToUnit,
  flattenFragments,
  genericComponent,
  propsFactory,
  useRender,
} from '@/utils'

export const makeUIconProps = propsFactory(
  {
    color: { type: String, default: 'primary-700', required: false },
    icon: IconValue,
    isHover: Boolean,
    isActive: Boolean,
    /**
     * @variant = [default | lightCircle | lightCircleOutline |
     * darkCircle | lightSquare | midSquare | darkSquare]
     * */
    variant: {
      type: String,
      default: 'default',
      required: false,
    },

    ...makeComponentProps(),
    ...makeSizeProps(),
    ...makeTagProps({ tag: 'i' }),
  },
  'UIcon'
)

export type UIconProps = ExtractPropTypes<typeof makeUIconProps>

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

  props: makeUIconProps(),

  setup(props, { attrs, slots }) {
    const slotIcon = ref<string>()
    if (props.icon === '$undefined') {
      return useRender(() => <>{slots.default?.()}</>)
    }

    useRender(() => {
      const slotValue = slots.default?.()
      if (slotValue) {
        slotIcon.value = flattenFragments(slotValue).filter(
          (node) =>
            node.type === Text &&
            node.children &&
            typeof node.children === 'string'
        )[0]?.children as string
      }

      const { iconData } = useIcon(
        computed(() =>
          getIconComponentName((slotIcon.value || props.icon) as string)
        )
      )
      const { sizeClasses } = useSize(props)

      const iconColor = computed(() => {
        if (
          props.variant === 'lightCircleOutline' ||
          props.variant === 'lightCircle' ||
          props.variant === 'lightSquare' ||
          props.variant === 'default'
        ) {
          return props.color
        } else {
          return 'white'
        }
      })

      return props.variant === 'default' ? (
        <iconData.value.component
          color={iconColor.value}
          isHover={props.isHover}
          isActive={props.isActive}
          tag={props.tag}
          icon={iconData.value.icon}
          class={[
            `${sizeClasses.value}-icon`,
            {
              'v-icon--clickable': !!attrs.onClick,
            },
            props.class,
            'flex box-border',
          ]}
          style={[
            !sizeClasses.value && {
              height: convertToUnit(props.size),
              width: convertToUnit(props.size),
            },
            props.style,
          ]}
          role={attrs.onClick ? 'button' : undefined}
          aria-hidden={!attrs.onClick}
        >
          {slotValue}
        </iconData.value.component>
      ) : (
        <UIconParentContainer
          variant={props.variant}
          color={props.color}
          sizeClasses={sizeClasses.value}
          class={props.class}
          size={props.size}
        >
          <iconData.value.component
            color={iconColor.value}
            isHover={props.isHover}
            isActive={props.isActive}
            tag={props.tag}
            icon={iconData.value.icon}
            class={[
              `${sizeClasses.value}-icon`,
              {
                'v-icon--clickable': !!attrs.onClick,
              },
            ]}
            style={[
              !sizeClasses.value && {
                height: convertToUnit(props.size),
                width: convertToUnit(props.size),
              },
              props.style,
            ]}
            role={attrs.onClick ? 'button' : undefined}
            aria-hidden={!attrs.onClick}
          >
            {slotValue}
          </iconData.value.component>
        </UIconParentContainer>
      )
    })

    return {}
  },
})

export type UIcon = InstanceType<typeof UIcon>
