<!-- eslint-disable vue/no-template-shadow -->
<!-- eslint-disable vue/no-v-html -->
<!-- eslint-disable vue/no-v-text-v-html-on-component -->
<template>
  <UCard v-if="component" class="relative flex flex-col" body-class="px-4 py-5 sm:p-6 relative" footer-class="flex flex-col flex-1 overflow-hidden">
    <div class="flex justify-center">
      <component :is="`U${defaultProps[params.component].component.name}`" v-if="defaultProps[params.component] && defaultProps[params.component].component" v-bind="defaultProps[params.component].component.props" />

      <component :is="is" v-bind="{ ...boundProps, ...eventProps }">
        <template v-for="[key, slot] of Object.entries(defaultProps[params.component]?.slots || {}) || []" #[key]>
          <template v-if="Array.isArray(slot)">
            <div :key="key">
              <component
                :is="slot.component ? `U${slot.component.name}` : slot.tag"
                v-for="(slot, index) of slot"
                :key="index"
                :class="slot.class"
                v-bind="slot.component?.props || defaultProps[slot.component]"
                v-html="slot.html"
              />
            </div>
          </template>
          <template v-else>
            <component :is="`U${slot.component.name}`" v-if="slot.component" :key="`${key}-component`" v-bind="slot.component?.props || defaultProps[slot.component]" />
            <component :is="slot.tag" v-else :key="`${key}-tag`" :class="slot.class" v-html="slot.html" />
          </template>
        </template>
      </component>
    </div>

    <template v-if="props.length" #footer>
      <div class="border-b u-border-gray-200">
        <pre class="text-sm leading-6 u-text-gray-900 flex-1 relative flex ligatures-none overflow-x-hidden px-4 sm:px-6 py-5 sm:py-6">
          <code class="flex-none min-w-full whitespace-pre-wrap break-all">{{ code }}</code>

          <UButton
            class="absolute top-0 right-0"
            :icon="copied ? 'i-heroicons-clipboard-document-check' : 'i-heroicons-clipboard-document'"
            variant="transparent"
            size="sm"
            :custom-class="copied ? '!text-green-500' : ''"
            @click="onCopy"
          />
        </pre>
      </div>

      <div class="flex-1 px-4 py-5 sm:p-6 space-y-3">
        <UFormGroup
          v-for="prop of props"
          :key="prop.key"
          class="capitalize"
          :name="prop.key"
          :label="prop.key"
        >
          <UToggle
            v-if="prop.type === 'Boolean'"
            v-model="prop.value"
            :name="prop.key"
            :label="prop.key"
          />
          <USelect
            v-else-if="prop.values"
            v-model="prop.value"
            :name="prop.key"
            placeholder="Choose one..."
            :options="prop.values"
            size="sm"
          />
          <UInput
            v-else-if="prop.type === 'String'"
            v-model="prop.value"
            :name="prop.key"
            size="sm"
            autocomplete="off"
          />
          <UInput
            v-else-if="prop.type === 'Number'"
            v-model="prop.value"
            type="number"
            :name="prop.key"
            size="sm"
          />
          <UTextarea
            v-else
            :model-value="prop.value && JSON.stringify(prop.value)"
            :name="prop.key"
            size="sm"
            :rows="8"
            autoresize
            @update:model-value="value => prop.value = JSON.parse(value)"
          />
        </UFormGroup>
      </div>
    </template>
  </UCard>
</template>

<script setup>
import { useClipboard } from '@vueuse/core'
import $ui from '#build/ui'

const nuxtApp = useNuxtApp()
const { params } = useRoute()

const is = `U${params.component}`

const component = nuxtApp.vueApp.component(is)

const people = [
  { id: 1, label: 'Durward Reynolds', disabled: false },
  { id: 2, label: 'Kenton Towne', disabled: false },
  { id: 3, label: 'Therese Wunsch', disabled: false },
  { id: 4, label: 'Benedict Kessler', disabled: true },
  { id: 5, label: 'Katelyn Rohan', disabled: false }
]

const selectCustom = ref(people[0])
const commandPalette = ref(people[0])
const alertDialog = ref(false)
const toggle = ref(false)
const modal = ref(false)
const slideover = ref(false)

const defaultProps = {
  Button: {
    label: 'Button text'
  },
  Badge: {
    label: 'Badge'
  },
  Alert: {
    title: 'A new software update is available. See what’s new in version 2.0.4.'
  },
  AlertDialog: {
    icon: 'i-heroicons-exclamation-triangle',
    title: 'Deactivate account',
    description: 'Are you sure you want to deactivate your account? All of your data will be permanently removed from our servers forever. This action cannot be undone.',
    modelValue: alertDialog,
    'onUpdate:modelValue': (v) => { alertDialog.value = v },
    component: {
      name: 'Button',
      props: {
        variant: 'secondary',
        label: 'Open modal',
        onClick: () => { alertDialog.value = true }
      }
    }
  },
  Avatar: {
    src: 'https://picsum.photos/200/300'
  },
  AvatarGroup: {
    group: ['https://images.unsplash.com/photo-1491528323818-fdd1faba62cc?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80', 'https://images.unsplash.com/photo-1550525811-e5869dd03032?ixlib=rb-1.2.1&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80', 'https://images.unsplash.com/photo-1500648767791-00dcc994a43e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2.25&w=256&h=256&q=80', 'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80']
  },
  Dropdown: {
    items: [
      [{
        label: 'Edit',
        icon: 'i-heroicons-pencil-square-20-solid'
      }, {
        label: 'Duplicate',
        icon: 'i-heroicons-document-duplicate-20-solid'
      }],
      [{
        label: 'Archive',
        icon: 'i-heroicons-archive-box-20-solid'
      }, {
        label: 'Move',
        icon: 'i-heroicons-arrow-right-circle-20-solid'
      }],
      [{
        label: 'Delete',
        icon: 'i-heroicons-trash-20-solid'
      }]
    ]
  },
  VerticalNavigation: {
    links: [
      {
        label: 'Home',
        icon: 'i-heroicons-home',
        to: '/'
      },
      {
        label: 'Examples',
        icon: 'i-heroicons-book-open',
        to: '/examples'
      },
      {
        label: 'Migration',
        icon: 'i-heroicons-arrow-path',
        to: '/migration'
      },
      {
        label: 'External link',
        icon: 'i-heroicons-link',
        to: 'https://google.fr',
        target: '_blank'
      }
    ]
  },
  CommandPalette: {
    modelValue: commandPalette,
    'onUpdate:modelValue': (v) => { commandPalette.value = v },
    groups: [{
      key: 'people',
      label: 'People',
      commands: people
    }]
  },
  Icon: {
    name: 'i-heroicons-bell'
  },
  Input: {
    name: 'input',
    placeholder: 'Enter text'
  },
  FormGroup: {
    name: 'input',
    label: 'Input group',
    slots: {
      default: {
        component: {
          name: 'Input',
          props: {
            name: 'input',
            placeholder: 'Works with every form element'
          }
        }
      }
    }
  },
  Toggle: {
    modelValue: toggle,
    'onUpdate:modelValue': (v) => { toggle.value = v }
  },
  Checkbox: {
    name: 'checkbox'
  },
  Radio: {
    name: 'radio'
  },
  Select: {
    name: 'select',
    options: ['English', 'Spanish', 'French', 'German', 'Chinese']
  },
  SelectCustom: {
    modelValue: selectCustom,
    'onUpdate:modelValue': (v) => { selectCustom.value = v },
    textAttribute: 'label',
    options: people
  },
  Textarea: {
    name: 'textarea'
  },
  Tooltip: {
    text: 'Tooltip text'
  },
  Notification: {
    id: '1',
    title: 'Notification title',
    callback: 'console.log(\'Timer expired\')'
  },
  Modal: {
    modelValue: modal,
    'onUpdate:modelValue': (v) => { modal.value = v },
    component: {
      name: 'Button',
      props: {
        variant: 'secondary',
        label: 'Open modal',
        onClick: () => { modal.value = true }
      }
    },
    slots: {
      default: {
        tag: 'div',
        html: 'Modal content'
      },
      footer: {
        component: {
          name: 'Button',
          props: {
            label: 'Close',
            onClick: () => { modal.value = false }
          }
        }
      }
    }
  },
  Slideover: {
    modelValue: slideover,
    'onUpdate:modelValue': (v) => { slideover.value = v },
    component: {
      name: 'Button',
      props: {
        variant: 'secondary',
        label: 'Open slideover',
        onClick: () => { slideover.value = true }
      }
    },
    slots: {
      default: {
        tag: 'div',
        html: 'Slideover content'
      }
    }
  },
  Popover: {
    slots: {
      panel: {
        tag: 'div',
        class: 'u-bg-gray-100 rounded-lg shadow-lg ring-1 ring-black ring-opacity-5 p-6',
        html: 'Popover content'
      }
    }
  },
  Tabs: {
    links: [{
      label: 'Usage',
      to: '/',
      exact: true
    }, {
      label: 'Examples',
      to: '/examples'
    }, {
      label: 'Migration',
      to: '/migration'
    }, {
      label: 'Tabs',
      to: '/components/Tabs'
    }]
  },
  Pills: {
    links: [{
      label: 'Usage',
      to: '/',
      exact: true
    }, {
      label: 'Examples',
      to: '/examples'
    }, {
      label: 'Migration',
      to: '/migration'
    }, {
      label: 'Pills',
      to: '/components/Pills'
    }]
  }
}

const componentDefaultProps = defaultProps[params.component] || {}
const { props: componentProps } = await component.__asyncLoader()

function lowercaseFirstLetter (string) {
  return string.charAt(0).toLowerCase() + string.slice(1)
}

const refProps = Object.entries(componentProps).map(([key, prop]) => {
  const defaultValue = componentDefaultProps[key]
  const propDefault = (typeof prop.default === 'function' ? prop.default() : prop.default)
  let value = defaultValue !== undefined ? defaultValue : propDefault
  let type = prop.type
  if (Array.isArray(type)) {
    type = type[0].name
  } else {
    type = type.name
  }

  let values
  if (prop.validator) {
    const arrayRegex = prop.validator.toString().match(/\[.*\]/g, '')
    if (arrayRegex) {
      values = JSON.parse(arrayRegex[0].replace(/'/g, '"')).filter(Boolean)
    } else {
      const $uiProp = $ui[lowercaseFirstLetter(params.component)][key]
      if ($uiProp) {
        values = Object.keys($uiProp).filter(Boolean)
      }
    }
  }

  if (value) {
    if (type === 'String' && typeof value === 'string') {
      value = value.replace(/^'(.*)'$/, '$1')
    } else if (type === 'Array') {
      value = JSON.stringify(value)
    }
  }

  return {
    key,
    type,
    value,
    values,
    default: propDefault
  }
})

const eventProps = Object.entries(componentDefaultProps)
  .filter(([key]) => !refProps.find(prop => prop.key === key))
  .filter(([key]) => !['slots'].includes(key))
  .reduce((acc, [key, value]) => {
    acc[key] = value
    return acc
  }, {})

const props = ref(refProps)
const boundProps = computed(() => {
  const bound = {}
  for (const prop of props.value) {
    let value = prop.value
    if (value === null) {
      continue
    }

    try {
      if (prop.type === 'Array') {
        value = JSON.parse(value)
      } else if (prop.type === 'Number') {
        value = Number(value)
      } else if (prop.type === 'Function') {
        // eslint-disable-next-line no-new-func
        value = Function(value)
      }

      bound[prop.key] = value
    } catch (e) {
      continue
    }
  }
  return bound
})

function toKebabCase (str) {
  return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase()
}

const { copy, copied } = useClipboard({ copiedDuring: 2000 })
const onCopy = () => {
  copy(code.value)
}

const code = computed(() => {
  let code = `<U${params.component}`
  for (const prop of props.value) {
    if (prop.value === null) {
      continue
    }
    if (prop.value === prop.default) {
      continue
    }

    const key = toKebabCase(prop.key)
    code += `\n  ${prop.type === 'Boolean' ? ':' : ''}${key === 'model-value' ? 'v-model' : key}="${prop.value}"`
  }
  code += '\n/>'
  return code
})
</script>
