<template>
  <Teleport to="body">
    <div v-if="isModalOpenRef" class="fixed border-solid border-2 border-gray-500 z-50 flex flex-col backdrop-blur-sm shadow-lg" :style="modalStyle">
      <div @mousedown="startDrag" class="cursor-move p-2.5 flex justify-between items-center border-solid border-0 border-b border-gray-500 relative">
        <div class="rounded-t-md absolute w-full h-full top-0 left-0 bg-[url('/assets/ui-texture.png')] bg-no-repeat bg-center bg-cover opacity-90"></div>
        <div class="relative z-10">
          <slot name="modalHeader" />
        </div>
        <div class="flex gap-2.5">
          <button @click="toggleFullScreen" class="w-5 h-5 m-0 p-0 relative hover:scale-110 transition-transform duration-300 ease-in-out" v-if="canFullScreen">
            <img :alt="isFullScreen ? 'exit full-screen' : 'full-screen'" draggable="false" :src="isFullScreen ? '/assets/icons/minimize.svg' : '/assets/icons/increase-size-option.svg'" class="w-3.5 h-3.5 invert" />
          </button>
          <button @click="close" v-if="closable" class="w-3.5 h-3.5 m-0 p-0 relative hover:rotate-180 transition-transform duration-300 ease-in-out">
            <img alt="close" draggable="false" src="/assets/icons/close-button-white.svg" class="w-full h-full" />
          </button>
        </div>
      </div>
      <div class="overflow-hidden grow relative">
        <div class="rounded-b-md absolute w-full h-full top-0 left-0 bg-[url('/assets/ui-texture.png')] bg-no-repeat bg-cover bg-center opacity-90"></div>
        <div class="relative z-10 h-full">
          <slot name="modalBody" />
        </div>
        <img v-if="isResizable && !isFullScreen" src="/assets/icons/resize-icon.svg" alt="resize" class="absolute z-10 bottom-0 right-0 w-5 h-5 cursor-nwse-resize" @mousedown="startResize" />
      </div>
    </div>
  </Teleport>
</template>

<script setup lang="ts">
import { defineEmits, onMounted, onUnmounted, ref, watch, computed } from 'vue'

const props = defineProps({
  isModalOpen: {
    type: Boolean,
    default: false
  },
  closable: {
    type: Boolean,
    default: true
  },
  isResizable: {
    type: Boolean,
    default: true
  },
  canFullScreen: {
    type: Boolean,
    default: false
  },
  modalPositionX: {
    type: Number,
    default: 0
  },
  modalPositionY: {
    type: Number,
    default: 0
  },
  modalWidth: {
    type: Number,
    default: 500
  },
  modalHeight: {
    type: Number,
    default: 280
  }
})

const isModalOpenRef = ref(props.isModalOpen)
const emit = defineEmits(['modal:close', 'character:create'])

const width = ref(props.modalWidth)
const height = ref(props.modalHeight)
const x = ref(0)
const y = ref(0)

const minWidth = ref(200)
const minHeight = ref(100)
const isResizing = ref(false)
const isDragging = ref(false)
const isFullScreen = ref(false)

let startX = 0
let startY = 0
let initialX = 0
let initialY = 0
let startWidth = 0
let startHeight = 0
let preFullScreenState = { x: 0, y: 0, width: 0, height: 0 }

const modalStyle = computed(() => ({
  borderRadius: isFullScreen.value ? '0' : '6px',
  top: isFullScreen.value ? '0' : `${y.value}px`,
  left: isFullScreen.value ? '0' : `${x.value}px`,
  width: isFullScreen.value ? '100vw' : `${width.value}px`,
  height: isFullScreen.value ? '100vh' : `${height.value}px`,
  maxWidth: '100vw',
  maxHeight: '100vh'
}))

function close() {
  emit('modal:close')
}

function startResize(event: MouseEvent) {
  if (isFullScreen.value) return
  isResizing.value = true
  startWidth = width.value - event.clientX
  startHeight = height.value - event.clientY
  event.preventDefault()
}

function resizeModal(event: MouseEvent) {
  if (!isResizing.value || isFullScreen.value) return
  const newWidth = Math.min(startWidth + event.clientX, window.innerWidth)
  const newHeight = Math.min(startHeight + event.clientY, window.innerHeight)
  width.value = Math.max(newWidth, minWidth.value)
  height.value = Math.max(newHeight, minHeight.value)
  adjustPosition()
}

function stopResize() {
  isResizing.value = false
}

function startDrag(event: MouseEvent) {
  if (isFullScreen.value) return
  isDragging.value = true
  startX = event.clientX
  startY = event.clientY
  initialX = x.value
  initialY = y.value
  event.preventDefault()
}

function drag(event: MouseEvent) {
  if (!isDragging.value || isFullScreen.value) return
  const dx = event.clientX - startX
  const dy = event.clientY - startY
  x.value = initialX + dx
  y.value = initialY + dy
  adjustPosition()
}

function stopDrag() {
  isDragging.value = false
}

function adjustPosition() {
  if (isFullScreen.value) return
  x.value = Math.max(0, Math.min(x.value, window.innerWidth - width.value))
  y.value = Math.max(0, Math.min(y.value, window.innerHeight - height.value))
}

function handleResize() {
  if (isFullScreen.value) return
  width.value = Math.min(width.value, window.innerWidth)
  height.value = Math.min(height.value, window.innerHeight)
  adjustPosition()
}

function initializePosition() {
  width.value = Math.min(props.modalWidth, window.innerWidth)
  height.value = Math.min(props.modalHeight, window.innerHeight)
  if (props.modalPositionX !== 0 && props.modalPositionY !== 0) {
    console.log(props.modalPositionX)
    console.log(props.modalPositionY)
    x.value = props.modalPositionX
    y.value = props.modalPositionY
  } else {
    x.value = (window.innerWidth - width.value) / 2
    y.value = (window.innerHeight - height.value) / 2
  }
}

function toggleFullScreen() {
  if (isFullScreen.value) {
    // Exit full-screen
    x.value = preFullScreenState.x
    y.value = preFullScreenState.y
    width.value = preFullScreenState.width
    height.value = preFullScreenState.height
    isFullScreen.value = false
  } else {
    // Enter full-screen
    preFullScreenState = { x: x.value, y: y.value, width: width.value, height: height.value }
    isFullScreen.value = true
  }
}

watch(
  () => props.isModalOpen,
  (value) => {
    isModalOpenRef.value = value
    if (value) {
      initializePosition()
    }
  }
)

watch(
  () => props.modalWidth,
  (value) => {
    width.value = Math.min(value, window.innerWidth)
  }
)

watch(
  () => props.modalHeight,
  (value) => {
    height.value = Math.min(value, window.innerHeight)
  }
)

watch(
  () => props.modalPositionX,
  (value) => {
    x.value = value
  }
)

watch(
  () => props.modalPositionY,
  (value) => {
    y.value = value
  }
)

onMounted(() => {
  window.addEventListener('mousemove', drag)
  window.addEventListener('mouseup', stopDrag)
  window.addEventListener('mousemove', resizeModal)
  window.addEventListener('mouseup', stopResize)
  if (props.modalPositionX !== 0 && props.modalPositionY !== 0) {
    window.addEventListener('resize', handleResize)
  }
  initializePosition()
})

onUnmounted(() => {
  window.removeEventListener('mousemove', drag)
  window.removeEventListener('mouseup', stopDrag)
  window.removeEventListener('mousemove', resizeModal)
  window.removeEventListener('mouseup', stopResize)
  if (props.modalPositionX !== 0 && props.modalPositionY !== 0) {
    window.removeEventListener('resize', handleResize)
  }
})
</script>
