import { makeComponentProps } from '@/composables/component'
import { makeTagProps } from '@/composables/tag'
import { genericComponent, propsFactory } from '@/utils'
import {
  ref,
  computed,
  onMounted,
  nextTick,
  ExtractPropTypes,
  PropType,
} from 'vue'
import { UCheckbox, UBadge } from '@/components'
import Sizes from '@/types/sizes'
import BaseCheckboxVariant from '@/types/baseCheckboxVariants'

export const makeUTableCellProps = propsFactory(
  {
    isChecked: {
      type: [Boolean, undefined] as PropType<boolean | undefined>,
      default: undefined,
      required: false,
    },
    checkboxType: {
      type: String,
      default: 'default',
      required: false,
    },
    disabled: {
      type: Boolean,
      default: false,
      required: false,
    },
    badges: {
      type: [Array, String] as PropType<
        Array<{ text: string; color: string; size: string }> | string
      >,
      default: 'default',
      required: false,
    },
    width: {
      type: String,
      required: false,
    },
    height: {
      type: String,
      default: '72',
      required: false,
    },
    ...makeComponentProps(),
    ...makeTagProps(),
  },
  'UTableCell'
)

export type UTableCellProps = ExtractPropTypes<typeof makeUTableCellProps>

export type UTableCellSlots = {
  default: never
}

export const UTableCell = genericComponent<UTableCellSlots>()({
  name: 'UTableCell',

  props: makeUTableCellProps(),

  emits: {
    change: (value: boolean | undefined) => true,
    'update:isChecked': (value: boolean | undefined) => true,
  },

  setup(props, { emit, slots }) {
    const BadgesContainer = ref<HTMLElement | null>(null)
    const BadgesContainerPaddings = ref(0)
    const CountBadgeWidth = 50
    const badgesContainerWidth = ref(0)
    const BadgesElements = ref<HTMLElement[]>([])
    const badgesElementWidth = ref<number[]>([])

    // eslint-disable-next-line @typescript-eslint/ban-ts-comment
    // @ts-ignore
    const slotContent = ref(slots.default && slots.default()[0].type.name)

    const slotClasses = computed(() => {
      let classes = ''
      if (slotContent.value === 'UTableCellText') {
        classes = 'flex flex-col justify-center items-start'
      } else if (slotContent.value === 'UButton') {
        classes = 'overflow-visible flex gap-1 justify-center items-start'
      }
      return classes
    })

    onMounted(async () => {
      await nextTick()
      const container = BadgesContainer.value
      if (container) {
        const { width } = container.getBoundingClientRect()
        badgesContainerWidth.value = width
        const computedStyle = getComputedStyle(BadgesContainer.value as Element)
        BadgesContainerPaddings.value =
          parseFloat(computedStyle.paddingLeft) +
          parseFloat(computedStyle.paddingRight)
      }

      await nextTick()
      const badges: Element[] = []
      badges.push(
        ...(container?.querySelectorAll(
          '.badgesElements > *'
        ) as unknown as Element[])
      )
      badges.forEach((badge) => {
        const width = (badge as HTMLElement).clientWidth
        badgesElementWidth.value.push(width)
      })
    })

    const isWidthReady = computed(() => badgesElementWidth.value.length > 0)

    const getVisibleBadges = computed(() => {
      const padding = BadgesContainerPaddings.value
      const containerWidth = badgesContainerWidth.value - padding
      const badgesWidth = badgesElementWidth.value
      const visibleBadges = []
      let sumWidth = CountBadgeWidth

      for (let i = 0; i < badgesWidth.length; i++) {
        sumWidth += badgesWidth[i] + 4

        if (sumWidth < containerWidth) {
          visibleBadges.push(props.badges[i])
        } else {
          break
        }
      }
      const hiddenCount = props.badges.length - visibleBadges.length
      if (hiddenCount > 0) {
        const dynamicBadge = {
          text: `+${hiddenCount}`,
          color: 'indigo',
          size: 'sm',
        }
        visibleBadges.push(dynamicBadge)
      }
      return visibleBadges
    })

    const bgClasses = computed(() => {
      return props.disabled ? 'bg-gray-25' : `bg-transparent`
    })

    const switchCheckbox = (isChecked: boolean | undefined) => {
      emit('change', isChecked)
      emit('update:isChecked', isChecked)
    }

    return () => (
      <div
        class={[
          bgClasses.value,
          !props.disabled ? 'cursor-pointer' : 'cursor-not-allowed',
          `overflow-hidden table-cell align-middle border-b border-gray-200`,
        ]}
        style={`width: ${props.width}; height: ${props.height}px`}
        ref={BadgesContainer}
      >
        <div class={'px-4'}>
          {props.isChecked !== undefined ? (
            <span class="pr-3 z-10">
              <UCheckbox
                size={Sizes.md}
                enabled={!props.disabled}
                variant={props.checkboxType as BaseCheckboxVariant}
                checked={props.isChecked}
                onClick={() => switchCheckbox(props.isChecked)}
              ></UCheckbox>
            </span>
          ) : null}
          <div
            class={[
              slotClasses.value,
              'whitespace-nowrap overflow-hidden overflow-ellipsis',
            ]}
          >
            {slots.default?.()}
          </div>
          <div class="badgesElements flex gap-1" ref={BadgesElements}>
            {isWidthReady.value
              ? getVisibleBadges.value.map((badge, index) => {
                  if (typeof badge === 'string') {
                    return badge
                  }
                  return (
                    <UBadge key={index} size={badge.size} color={badge.color}>
                      {badge.text}
                    </UBadge>
                  )
                })
              : Array.isArray(props.badges)
              ? props.badges.map((badge, index) => {
                  if (typeof badge === 'string') {
                    return badge
                  }
                  return (
                    <UBadge
                      key={index}
                      size={badge.size}
                      color={badge.color}
                      ref="BadgesElement"
                    >
                      {badge.text}
                    </UBadge>
                  )
                })
              : null}
          </div>
        </div>
      </div>
    )
  },
})

export type UTableCell = InstanceType<typeof UTableCell>
