<template>
    <div
        ref="blockEl"
        class="absolute z-10 cursor-pointer rounded-md text-xs shadow-sm select-none"
        :style="blockStyle"
        :class="{ 'opacity-40': isDragSource }"
        @contextmenu.prevent="emit('contextmenu', $event, entry)"
        @mousedown="onMouseDown"
        @click.stop
    >
        <!-- Resize handle top (outside block) -->
        <div
            class="absolute left-0 right-0 h-3 cursor-n-resize group"
            style="bottom: 100%"
            @mousedown.stop.prevent="onResizeTopStart"
        >
            <div class="absolute bottom-0 left-1/2 -translate-x-1/2 h-[3px] w-8 rounded-full bg-black/0 group-hover:bg-black/20 transition" />
        </div>

        <div class="flex flex-col h-full overflow-hidden px-1.5 py-1">
            <!-- Top: title + project -->
            <div class="min-w-0">
                <div v-if="sizeLevel >= 1" class="font-bold truncate leading-tight" style="color: #0A2168">{{ entry.title || $t('common.untitled') }}</div>
                <div v-if="sizeLevel >= 2 && entry.project" class="truncate text-[10px] font-semibold opacity-80 leading-tight">{{ entry.project.name }}</div>
            </div>

            <!-- Spacer -->
            <div class="flex-1" />

            <!-- Bottom: tags left, duration right -->
            <div v-if="sizeLevel >= 3" class="flex items-end justify-between gap-1 min-w-0">
                <div v-if="showTags && entry.tags.length" class="flex flex-wrap items-center gap-0.5 overflow-hidden min-w-0">
                    <span
                        v-for="tag in visibleTags"
                        :key="tag.id"
                        class="inline-flex items-center rounded-full px-1.5 py-0.5 text-[9px] font-bold text-white truncate max-w-[5rem]"
                        :style="{ backgroundColor: tag.color }"
                    >
                        {{ tag.label }}
                    </span>
                    <span
                        v-if="hiddenTagCount > 0"
                        class="inline-flex items-center rounded-full bg-black/20 px-1 py-0.5 text-[9px] font-bold text-white"
                    >
                        +{{ hiddenTagCount }}
                    </span>
                </div>
                <span class="shrink-0 text-[10px] tabular-nums font-bold" style="color: #0A2168">{{ duration }}</span>
            </div>
            <div v-else-if="sizeLevel === 2" class="flex items-end justify-end">
                <span class="shrink-0 text-[10px] tabular-nums font-bold" style="color: #0A2168">{{ duration }}</span>
            </div>
        </div>

        <!-- Resize handle bottom (outside block) -->
        <div
            class="absolute left-0 right-0 h-3 cursor-s-resize group"
            style="top: 100%"
            @mousedown.stop.prevent="onResizeBottomStart"
        >
            <div class="absolute top-0 left-1/2 -translate-x-1/2 h-[3px] w-8 rounded-full bg-black/0 group-hover:bg-black/20 transition" />
        </div>
    </div>
</template>

<script setup lang="ts">
import type { TimeEntry } from '~/modules/time-tracking/services/dto/time-entry'

const props = defineProps<{
    entry: TimeEntry
    hourHeight: number
    dayStartHour: number
    isDragSource?: boolean
    columnIndex?: number
    totalColumns?: number
}>()

const emit = defineEmits<{
    (e: 'click', entry: TimeEntry): void
    (e: 'contextmenu', event: MouseEvent, entry: TimeEntry): void
    (e: 'resize', entry: TimeEntry, newStartedAt: string, newStoppedAt: string): void
    (e: 'moveStart', payload: { entry: TimeEntry; offsetY: number }): void
}>()

const blockEl = ref<HTMLElement | null>(null)

const startDate = computed(() => new Date(props.entry.startedAt))
const endDate = computed(() => props.entry.stoppedAt ? new Date(props.entry.stoppedAt) : new Date())

const resizeTopDeltaMinutes = ref(0)
const resizeBottomDeltaMinutes = ref(0)

const duration = computed(() => {
    const mins = Math.floor((endDate.value.getTime() + resizeBottomDeltaMinutes.value * 60000
        - startDate.value.getTime() - resizeTopDeltaMinutes.value * 60000) / 60000)
    const h = Math.floor(mins / 60)
    const m = mins % 60
    return m > 0 ? `${h}h${String(m).padStart(2, '0')}` : `${h}h`
})

const heightPx = computed(() => {
    const startMinutes = startDate.value.getHours() * 60 + startDate.value.getMinutes() + resizeTopDeltaMinutes.value
    const endMinutes = endDate.value.getHours() * 60 + endDate.value.getMinutes() + resizeBottomDeltaMinutes.value
    return Math.max(((endMinutes - startMinutes) / 60) * props.hourHeight, 20)
})

// Responsive content levels based on block height
// 3 = full (title + project + types + duration)
// 2 = medium (title + duration)
// 1 = small (title only)
// 0 = tiny (colored bar only)
const sizeLevel = computed(() => {
    const h = heightPx.value
    if (h >= 50) return 3
    if (h >= 35) return 2
    if (h >= 20) return 1
    return 0
})

const showTags = computed(() => (props.totalColumns ?? 1) <= 2)

const maxVisibleTags = computed(() => {
    const total = props.totalColumns ?? 1
    if (total >= 2) return 1
    return 2
})

const visibleTags = computed(() => props.entry.tags.slice(0, maxVisibleTags.value))
const hiddenTagCount = computed(() => Math.max(0, props.entry.tags.length - maxVisibleTags.value))

const hasProject = computed(() => !!props.entry.project)

const blockStyle = computed(() => {
    const startMinutes = startDate.value.getHours() * 60 + startDate.value.getMinutes() + resizeTopDeltaMinutes.value
    const topPx = ((startMinutes - props.dayStartHour * 60) / 60) * props.hourHeight

    const col = props.columnIndex ?? 0
    const total = props.totalColumns ?? 1
    const gapPx = 2
    const leftPercent = (col / total) * 100
    const widthPercent = (1 / total) * 100

    const base: Record<string, string> = {
        top: `${topPx}px`,
        height: `${heightPx.value}px`,
        left: `calc(${leftPercent}% + ${gapPx}px)`,
        width: `calc(${widthPercent}% - ${gapPx * 2}px)`,
    }

    if (hasProject.value) {
        const hex = props.entry.project!.color.replace('#', '')
        const r = parseInt(hex.substring(0, 2), 16)
        const g = parseInt(hex.substring(2, 4), 16)
        const b = parseInt(hex.substring(4, 6), 16)
        base.backgroundColor = `rgb(${Math.round(r + (255 - r) * 0.6)}, ${Math.round(g + (255 - g) * 0.6)}, ${Math.round(b + (255 - b) * 0.6)})`
        base.color = `rgb(${r}, ${g}, ${b})`
    } else {
        base.backgroundColor = '#e5e7eb'
        base.backgroundImage = 'repeating-conic-gradient(#d1d5db 0% 25%, #f3f4f6 0% 50%)'
        base.backgroundSize = '12px 12px'
        base.color = '#6b7280'
    }

    return base
})

// --- Click / Drag detection ---
let mouseDownPos = { x: 0, y: 0 }
let mouseDownHandled = false

function onMouseDown(event: MouseEvent) {
    if (event.button !== 0) return
    if ((event.target as HTMLElement).closest('.cursor-s-resize, .cursor-n-resize')) return

    mouseDownPos = { x: event.clientX, y: event.clientY }
    mouseDownHandled = false

    document.addEventListener('mousemove', onMouseMoveDetect)
    document.addEventListener('mouseup', onMouseUpDetect)
}

function onMouseMoveDetect(event: MouseEvent) {
    const dx = event.clientX - mouseDownPos.x
    const dy = event.clientY - mouseDownPos.y
    if (Math.abs(dx) + Math.abs(dy) > 5 && !mouseDownHandled) {
        mouseDownHandled = true
        document.removeEventListener('mousemove', onMouseMoveDetect)
        document.removeEventListener('mouseup', onMouseUpDetect)

        const rect = blockEl.value!.getBoundingClientRect()
        emit('moveStart', {
            entry: props.entry,
            offsetY: mouseDownPos.y - rect.top,
        })
    }
}

function onMouseUpDetect() {
    document.removeEventListener('mousemove', onMouseMoveDetect)
    document.removeEventListener('mouseup', onMouseUpDetect)
    if (!mouseDownHandled) {
        emit('click', props.entry)
    }
}

// --- Resize bottom (change stoppedAt) ---
function onResizeBottomStart(event: MouseEvent) {
    const startY = event.clientY
    resizeBottomDeltaMinutes.value = 0

    document.body.style.userSelect = 'none'
    document.body.style.cursor = 's-resize'

    function onMouseMove(e: MouseEvent) {
        const delta = e.clientY - startY
        resizeBottomDeltaMinutes.value = Math.round((delta / props.hourHeight) * 60 / 15) * 15
    }

    function onMouseUp() {
        document.removeEventListener('mousemove', onMouseMove)
        document.removeEventListener('mouseup', onMouseUp)
        document.body.style.userSelect = ''
        document.body.style.cursor = ''

        const finalDelta = resizeBottomDeltaMinutes.value
        resizeBottomDeltaMinutes.value = 0

        if (finalDelta !== 0) {
            const newEnd = new Date(endDate.value.getTime() + finalDelta * 60000)
            emit('resize', props.entry, props.entry.startedAt, newEnd.toISOString())
        }
    }

    document.addEventListener('mousemove', onMouseMove)
    document.addEventListener('mouseup', onMouseUp)
}

// --- Resize top (change startedAt) ---
function onResizeTopStart(event: MouseEvent) {
    const startY = event.clientY
    resizeTopDeltaMinutes.value = 0

    document.body.style.userSelect = 'none'
    document.body.style.cursor = 'n-resize'

    function onMouseMove(e: MouseEvent) {
        const delta = e.clientY - startY
        resizeTopDeltaMinutes.value = Math.round((delta / props.hourHeight) * 60 / 15) * 15
    }

    function onMouseUp() {
        document.removeEventListener('mousemove', onMouseMove)
        document.removeEventListener('mouseup', onMouseUp)
        document.body.style.userSelect = ''
        document.body.style.cursor = ''

        const finalDelta = resizeTopDeltaMinutes.value
        resizeTopDeltaMinutes.value = 0

        if (finalDelta !== 0) {
            const newStart = new Date(startDate.value.getTime() + finalDelta * 60000)
            emit('resize', props.entry, newStart.toISOString(), props.entry.stoppedAt ?? endDate.value.toISOString())
        }
    }

    document.addEventListener('mousemove', onMouseMove)
    document.addEventListener('mouseup', onMouseUp)
}
</script>
