<script setup lang="ts">
import { PropType, computed, onMounted, ref, onBeforeUnmount } from 'vue'
import { CCCard } from '../../index'
import { ColorTypes } from '../../types'

const props = defineProps({
  /**
   * カラー
   * @example 'primary' | 'secondary' | 'positive' | 'negative' | 'warning'
   */
  color: {
    type: String as PropType<ColorTypes>,
    default: 'secondary',
  },
  /**
   * ボタンのサイズ(afc用)
   */
  miniSize: { type: Boolean, default: false },
  /**
   * アップロード済みの写真かどうか
   * @example uploaded
   */
  uploaded: { type: Boolean, default: true },
  /**
   * ボタンの透明度
   * @example opacity
   */
  opacity: { type: Boolean, default: false },
  /**
   *
   */
  modelValue: { type: Boolean },

  /**
   * メニューの項目を選択して表示
   * @example showCustomMenu
   */
  showCustomMenu: {
    type: Object as PropType<{
      download: boolean
      delete: boolean
      shareUrl: boolean
      edit: boolean
      close: boolean
    }>,
    default: {
      download: true,
      delete: true,
      shareUrl: true,
      edit: true,
      close: true,
    },
  },
})

const emit = defineEmits<{
  (e: 'update:modelValue', value: boolean): void
  (e: 'onClick', action: 'download' | 'delete' | 'shareUrl' | 'edit'): void
  (e: 'fileChange', file: File): void
}>()

onMounted(() => {
  const menuButton = document.getElementById('menuButton')
  if (menuButton) {
    const rect = menuButton.getBoundingClientRect()
    teleportPosition.value = {
      top: rect.top + window.scrollY,
      left: rect.left + window.scrollX,
    }
  }
})

/** メニューの表示非表示フラグ */
const isShowCard = computed<boolean>({
  get() {
    return props.modelValue
  },
  set(value) {
    emit('update:modelValue', value)
  },
})

/** メニューの表示非表示を切り替える */
const toggleCard = () => {
  isShowCard.value = !isShowCard.value
  updateMenuPosition() // メニューが表示される度に位置を更新
}

const menuButtonRef = ref<HTMLElement | null>(null)
const menuCardRef = ref<HTMLElement | null>(null)
const handleClickOutside = (e: MouseEvent) => {
  if (!menuButtonRef.value || !menuCardRef.value) return

  if (
    !menuButtonRef.value.contains(e.target as Node) &&
    !menuCardRef.value.contains(e.target as Node) &&
    isShowCard.value
  ) {
    isShowCard.value = false
  }
}

onMounted(() => {
  document.addEventListener('click', handleClickOutside)
})

onBeforeUnmount(() => {
  document.removeEventListener('click', handleClickOutside)
})

/** 渡ってきたカラーに応じて色を変える */
const changeColor = computed(() => {
  if (props.color === 'primary') return 'var(--c-primary)'
  if (props.color === 'secondary') return 'var(--c-secondary)'
  if (props.color === 'positive') return 'var(--c-positive)'
  if (props.color === 'negative') return 'var(--c-negative)'
  if (props.color === 'warning') return 'var(--c-warning)'
})
const teleportPosition = ref({ top: 0, left: 0 })

/**
 * メニューカードの位置を更新する
 */
// const updateMenuPosition = () => {
//   const menuButton = menuButtonRef.value
//   if (menuButton) {
//     const rect = menuButton.getBoundingClientRect()

//     const cardWidth = 130 // メニューカードの幅
//     const cardHeight = 200 // メニューカードの高さ
//     const windowWidth = window.innerWidth
//     const windowHeight = window.innerHeight
//     const miniStandardOpHight = props.miniSize ? 30 : 50
//     const miniDownOpHight = props.miniSize ? 160 : 80

//     // メニューカードが画面右端にはみ出す場合または画面左端にはみ出す場合
//     if (rect.left + cardWidth > windowWidth || rect.right + cardWidth > windowWidth) {
//       teleportPosition.value = {
//         top: rect.top - 120,
//         left: rect.left - cardWidth,
//       }
//     }
//     // メニューカードが画面下端にはみ出す場合
//     else if (rect.bottom + cardHeight > windowHeight) {
//       teleportPosition.value = {
//         top: rect.top - cardHeight + miniDownOpHight,
//         left: rect.left - 150,
//       }
//     }
//     // メニューカードが画面内に収まる場合
//     else {
//       teleportPosition.value = {
//         top: rect.top + miniStandardOpHight,
//         left: rect.left,
//       }
//     }
//   }
// }

const updateMenuPosition = () => {
  const menuButton = menuButtonRef.value
  if (menuButton) {
    const rect = menuButton.getBoundingClientRect()

    const cardWidth = 130 // メニューカードの幅
    const cardHeight = 200 // メニューカードの高さ
    const windowWidth = window.innerWidth
    const windowHeight = window.innerHeight
    const miniStandardOpHeight = props.miniSize ? 30 : 50
    const miniDownOpHeight = props.miniSize ? 160 : 80

    // スクロール位置を考慮してtopとleftの基準位置を計算
    const topPosition = rect.top + window.scrollY
    const leftPosition = rect.left + window.scrollX

    // メニューカードが画面右端または左端にはみ出す場合
    if (leftPosition + cardWidth > windowWidth) {
      teleportPosition.value = {
        top: topPosition - 120,
        left: leftPosition - cardWidth,
      }
    }
    // メニューカードが画面下端にはみ出す場合
    else if (rect.bottom + cardHeight > windowHeight) {
      teleportPosition.value = {
        top: topPosition - cardHeight + miniDownOpHeight,
        left: leftPosition - 150,
      }
    }
    // メニューカードが画面内に収まる場合
    else {
      teleportPosition.value = {
        top: topPosition + miniStandardOpHeight,
        left: leftPosition,
      }
    }
  }
}

// 画面サイズが変更された時にメニューの位置を更新する
window.addEventListener('resize', updateMenuPosition)

onMounted(() => {
  updateMenuPosition()
})

onBeforeUnmount(() => {
  window.removeEventListener('resize', updateMenuPosition)
})
</script>

<template>
  <div
    ref="menuButtonRef"
    :class="['_circle', { _opacity: opacity, _circle_mini: miniSize }]"
    @click="toggleCard()"
  >
    <div :class="['_line', { _line_mini: miniSize }]"></div>
    <div :class="['_line', { _line_mini: miniSize }]"></div>
    <div :class="['_line', { _line_mini: miniSize }]"></div>
  </div>
  <Teleport to="body" ref="menuCardRef">
    <transition name="fade">
      <CCCard
        class="_card"
        v-show="isShowCard"
        :style="{ top: teleportPosition.top + 'px', left: teleportPosition.left + 'px' }"
      >
        <div v-if="uploaded">
          <div
            v-if="showCustomMenu.download"
            class="_button"
            @click="() => emit('onClick', 'download')"
          >
            ダウンロード
          </div>
          <div v-if="showCustomMenu.edit" class="_button" @click="() => emit('onClick', 'edit')">
            編集
          </div>
          <div
            v-if="showCustomMenu.delete"
            class="_button"
            @click="() => emit('onClick', 'delete')"
          >
            削除
          </div>
          <div
            v-if="showCustomMenu.shareUrl"
            class="_button"
            @click="() => emit('onClick', 'shareUrl')"
          >
            共有用URL
          </div>
        </div>
        <div v-else>
          <div v-if="showCustomMenu.edit" class="_button" @click="() => emit('onClick', 'edit')">
            編集
          </div>
          <div
            v-if="showCustomMenu.delete"
            class="_button"
            @click="() => emit('onClick', 'delete')"
          >
            削除
          </div>
        </div>
        <div class="_button" @click="toggleCard()">閉じる</div>
      </CCCard>
    </transition>
  </Teleport>
</template>

<style lang="sass" scoped>
._circle
  user-select: none
  width: 40px
  height: 40px
  background: rgba(255, 255, 255)
  border-radius: 50%
  position: relative
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1)
  cursor: pointer
._circle_mini
  width: 20px
  height: 20px

._opacity
  background: rgba(255, 255, 255, 0.5)
._line
  position: absolute
  left: 50%
  top: 50%
  transform: translate(-50%, -50%)
  width: 20px
  height: 2px
  background: v-bind(changeColor)
._line_mini
  width: 10px
  height: 10px
  height: 0.1px
._line:nth-child(2)
  top: 65%
._line:nth-child(3)
  top: 35%
._card
  // サイズの変更をする際は座標も変更してください
  width: 130px
  margin-top: 10px
  margin: 0 auto
  z-index: 9999999
  position: absolute
  user-select: none

.fade-enter-active, .fade-leave-active
  transition: opacity 0.2s
.fade-enter, .fade-enter-from, .fade-leave-to
  opacity: 0
.fade-enter-to, .fade-leave
  opacity: 1
._button
  font-size: 16px
  color: #707070
  padding: 10px 15px
  cursor: pointer
  transition: 0.3s
._button:hover
  background: v-bind(changeColor)
  color: #ffffff
</style>
