<template>
  <div
    class="w100 col-grow relative-position bg-white overflow-hidden"
    >
    <q-resize-observer @resize="onCardResize"/>
    <div
      id="card-header"
      class="absolute-top overflow-hidden"
      v-if="hasHeader"
      style="z-index: 100;"
      >
      <q-resize-observer @resize="onHeaderResize"/>
      <slot name="card-header"/>
    </div>

    <div
      id="card-under-header"
      class="absolute-top"
      v-if="hasUnderHeader"
      style="z-index: 100;"
      :style="{ top: headerHeight + 'px' }"
      >
      <slot name="card-under-header"/>
    </div>

    <div
      id="card-inner-header"
      v-if="hasInnerHeader"
      style="z-index: 100;"
      >
      <q-resize-observer @resize="onInnerHeaderResize"/>
      <slot name="card-inner-header"/>
    </div>
    
    <pn-shadow-scroll
      ref="shadowScrollRef"
      :height="cardHeight - innerHeaderHeight"
      :topOffset="headerHeight"
      :bottomOffset
      v-bind="$attrs"
      class="overflow-hidden top-border"
      @focusin="onFocusIn"
      @editor-cursor-update="onEditorCursorUpdate"
      @updateScrollPosition="onScroll"
      :class="{ 'has-top-border': isScrolled }"
      >
      <slot/>
    </pn-shadow-scroll>

    <div
      class="absolute-bottom q-px-md q-py-md"
      id="card-actions"
      v-if="hasActions"
      style="z-index: 100;"
      >
      <q-resize-observer @resize="onActionsResize"/>
      <slot name="card-actions"/>
      <div style="height: var(--tg-safe-area-inset-bottom)"/>
    </div>

    <div
      class="absolute column q-px-md q-gutter-y-md"
      :class="hasActions || tabsSlotHeight ? 'q-pb-none' : 'q-pb-md'"
      :style="{ bottom: bottomOffset + 'px', right: '0' }"
      v-if="hasFAB"
      style="z-index: 100;"
      >
      <slot name="card-fab"/>
    </div>
    
  </div>
</template>

<script setup lang="ts">
  import { useSlots, computed, ref, onMounted, getCurrentInstance  } from 'vue'
  const app = getCurrentInstance()
  const isMobile = app?.appContext.config.globalProperties.$isMobile

  const props = withDefaults(defineProps<{
    tabsSlotHeight?: number
  }>(),
    {
      tabsSlotHeight: 0
    }
  )

  const slots = useSlots()
  const hasHeader = computed(() => !!slots['card-header'])
  const hasUnderHeader = computed(() => !!slots['card-under-header'])
  const hasInnerHeader = computed(() => !!slots['card-inner-header'])
  const hasActions = computed(() => !!slots['card-actions'])
  const hasFAB = computed(() => !!slots['card-fab'])

  const cardHeight = ref(0)
  const headerHeight = ref(16)
  const innerHeaderHeight = ref(0)
  const actionsHeight = ref(0)
  
  interface sizeParams {
    height: number,
    width: number
  }

  function onCardResize (size: sizeParams) {
    cardHeight.value = size.height
  }

  function onHeaderResize (size: sizeParams) {
    headerHeight.value = size.height
  }

  function onInnerHeaderResize (size: sizeParams) {
    innerHeaderHeight.value = size.height
  }

  function onActionsResize (size: sizeParams) {
    actionsHeight.value = size.height
  }

  const tgInsetBottom = ref(0)

  const getTgInsetBottom = () => {
    const value = getComputedStyle(document.documentElement)
      .getPropertyValue('--tg-safe-area-inset-bottom')
      .trim()
    
    tgInsetBottom.value = parseFloat(value) || 0
  }

  onMounted(() => getTgInsetBottom())

  const bottomOffset = computed(() => {
    return Math.max(props.tabsSlotHeight, actionsHeight.value, tgInsetBottom.value)
  })

  // smart scroll only for page with editable content
  const shadowScrollRef = ref()

  function onFocusIn(e: FocusEvent) {
    if (!isMobile) return
    const target = e.target as HTMLElement
    
    if (!['INPUT', 'TEXTAREA'].includes(target.tagName)) return
    const viewport = shadowScrollRef.value?.$el?.querySelector('.q-scrollarea__container') as HTMLElement
    if (!viewport) return

    setTimeout(() => {
      const field = target.closest('.q-field') as HTMLElement || target
      
      const fieldRect = field.getBoundingClientRect()
      const viewportRect = viewport.getBoundingClientRect()
      
      const fieldBottomRelative = fieldRect.bottom - viewportRect.top
      const marginBottom = 0
      const availableHeight = viewport.offsetHeight - actionsHeight.value - marginBottom

      if (fieldBottomRelative > availableHeight) {
        const scrollDiff = fieldBottomRelative - availableHeight
        viewport.scrollTo({
          top: viewport.scrollTop + scrollDiff,
          behavior: 'smooth'
        })
      }
    }, 1000) // fix apple slow keyboard
  }

  function onEditorCursorUpdate(e: Event) {
    if (!isMobile) return
    const coords = (e as CustomEvent).detail as { top: number, bottom: number } | null
    if (!coords) return

    const scrollEl = shadowScrollRef.value?.$el
    const viewport = scrollEl?.querySelector('.q-scrollarea__container') as HTMLElement
    if (!viewport) return

    const viewportRect = viewport.getBoundingClientRect()
    const cursorBottomRelativeToViewport = coords.bottom - viewportRect.top
    const visibleThreshold = viewport.offsetHeight - actionsHeight.value

    if (cursorBottomRelativeToViewport > visibleThreshold) {
      const scrollDiff = cursorBottomRelativeToViewport - visibleThreshold
      viewport.scrollBy({ top: scrollDiff, behavior: 'smooth' })
    }
  }

  const isScrolled = ref(false)
  const onScroll = (pos: number) => {
    isScrolled.value = pos > 1
  }
</script>

<style scoped lang="scss">
  .top-border {
    border-top: 1px solid transparent;
    transition: border-color 0.3s ease; 
  }
  
  .has-top-border {
    border-color: $t-section-separator-color;
  }
</style>
