import { makeComponentProps } from '@/composables/component'
import { makeTagProps } from '@/composables/tag'
import { genericComponent, propsFactory, useRender } from '@/utils'
import { ExtractPropTypes, Ref } from 'vue'
import { ref, computed, onMounted, watch, nextTick, reactive } from 'vue'
import { UTabItem } from './UTabItem'
import { TabItemData } from '@/types/tabsData'

export const makeUTabsProps = propsFactory(
  {
    size: {
      type: String,
      default: 'sm',
      required: false,
    },
    fullWidth: {
      type: Boolean,
      default: false,
      required: false,
    },
    variant: {
      type: String,
      default: 'underlined',
      required: false,
    },
    tabItems: {
      type: Array as () => TabItemData[],
      default: [],
      required: false,
    },
    activeIndex: {
      type: Number,
      default: 0,
      required: false,
    },

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

export type UTabsProps = ExtractPropTypes<typeof makeUTabsProps>

export type UTabsSlots = {
  //
}

export const UTabs = genericComponent<UTabsSlots>()({
  name: 'UTabs',

  props: makeUTabsProps(),

  emits: {
    change: (value: { key: number }) => true,
  },

  setup(props, { emit }) {
    const lineWidth = ref(0)
    const lineLeft = ref(0)
    const activeTabIndex = ref(props.activeIndex)
    const indexValue = ref(props.activeIndex)
    const itemRefs = reactive<(UTabItem | null)[]>([])

    const calculateLineParams = (index: number) => {
      const tabItem = itemRefs[index]
      const parentContainer = tabItem?.$el.parentElement
      if (parentContainer) {
        const tabItemRect = tabItem.$el.getBoundingClientRect()
        const parentRect = parentContainer.getBoundingClientRect()

        lineWidth.value = tabItemRect.width
        lineLeft.value = tabItemRect.left - parentRect.left
      }
    }

    const lineStyle = computed(() => ({
      width: `${lineWidth.value}px`,
      left: `${lineLeft.value}px`,
      bottom: `0px`,
    }))

    watch(
      () => activeTabIndex.value,
      (newValue, oldValue) => {
        calculateDuration(oldValue, newValue)
      }
    )

    watch([() => props.size, () => props.tabItems], () => {
      nextTick(() => {
        calculateLineParams(activeTabIndex.value)
      })
    })

    const duration = ref(300)

    const calculateDuration = (prev: number, current: number) => {
      if (Math.abs(current - prev) >= 2) {
        duration.value = 300
      } else {
        duration.value = 200
      }
    }

    watch(
      () => props.fullWidth,
      async () => {
        await nextTick()
        calculateLineParams(activeTabIndex.value)
      }
    )

    onMounted(() => {
      if (props.tabItems.length > 0) {
        nextTick(() => {
          const defaultActiveTab = props.tabItems[props.activeIndex]
          const defaultActiveTabIndex = props.tabItems.findIndex(
            (tabItem) => tabItem === defaultActiveTab
          )
          switchActiveState(defaultActiveTab, defaultActiveTabIndex)

          setTimeout(() => {
            calculateLineParams(defaultActiveTabIndex)
          }, 100)
        })
      }
    })

    const switchActiveState = (tabItem: TabItemData, index: number) => {
      activeTabIndex.value = index
      indexValue.value = index
      calculateLineParams(index)

      emit('change', { key: index })
    }

    useRender(() => (
      <div
        class={[
          'relative',
          props.fullWidth
            ? 'w-full flex justify-between gap-0'
            : 'w-fit mx-auto flex justify-center items-center',
        ]}
      >
        {props.tabItems.map((tabItem, index) => {
          const itemRef: Ref<UTabItem | null> = ref(null)
          itemRefs[index] = itemRef.value

          return (
            <UTabItem
              key={index}
              title={tabItem.title}
              variant={tabItem.variant}
              badge={tabItem.badge}
              active={activeTabIndex.value === index}
              size={props.size}
              fullWidth={props.fullWidth}
              onClick={() => switchActiveState(tabItem, index)}
              ref={(el) => (itemRefs[index] = el as UTabItem)}
            />
          )
        })}
        {activeTabIndex.value === indexValue.value ? (
          <div
            class={`absolute h-0.5 bg-primary-600 transition-all duration-${duration.value} 
            ease-in`}
            style={lineStyle.value}
          ></div>
        ) : null}
      </div>
    ))
    return {
      switchActiveState,
    }
  },
})

export type UTabs = InstanceType<typeof UTabs>
