/**
 * Week-Canvas – Alpine.data-Komponente
 * Drag & Drop + Resize für Week / Day / Month-Ansicht
 * 15-Minuten-Snapping in der Zeitachse
 */

const CELL_PX = 48;          // px pro Stunde  (muss mit $cellPx im Blade übereinstimmen)
const SLOT_PX = CELL_PX / 4; // 12 px = 15 Minuten

document.addEventListener('alpine:init', () => {
    Alpine.data('weekCanvas', () => ({

        // ── Focus (Einzelklick → Vordergrund) ────────────────────────
        focusedEventId: null,

        // ── Timed-Event DnD (Week / Day) ─────────────────────────────
        draggingId:   null,
        dragOffsetY:  0,
        dragGrabDate: null,   // Datum der Kopie, die der User gegriffen hat

        // ── All-Day-Event DnD (Week) ──────────────────────────────────
        draggingAllDayId:        null,
        draggingAllDayStartCol:  0,
        draggingAllDayStartDate: null,
        draggingAllDayGrabDate:  null,   // konkretes Grab-Datum aus data-date
        allDayGrabColOffset:     0,
        allDayDropCol:           null,

        // ── Month-View DnD ────────────────────────────────────────────
        monthDraggingId:        null,
        monthDraggingIsAllDay:  false,
        monthDraggingHour:      0,
        monthDraggingMinute:    0,
        monthDraggingStartDate: null,

        // ── Drag-Zeitvorschau (intern) ────────────────────────────────
        hourStart:      0,
        _dragTimeEl:    null,
        _dragOrigTime:  '',
        _dragDurSlots:  0,

        // ── Init ──────────────────────────────────────────────────────

        init() {
            this.hourStart = parseInt(this.$el.dataset.hourStart) || 0;
            this.$nextTick(() => {
                const g = this.$refs.scrollarea;
                if (g) g.scrollTop = 8 * CELL_PX; // zu 08:00 scrollen
            });
        },

        _timeStr(h, m) {
            return String(h).padStart(2, '0') + ':' + String(m).padStart(2, '0');
        },

        // ═══════════════════════════════════════════════════════════════
        // CREATE ON DOUBLE-CLICK  (Week + Day timeline)
        // ═══════════════════════════════════════════════════════════════

        onCreateAt(e, date) {
            const rect   = e.currentTarget.getBoundingClientRect();
            const relY   = Math.max(0, e.clientY - rect.top);
            const slot   = Math.floor(relY / SLOT_PX);
            const hour   = Math.min(Math.floor(slot / 4), 23);
            const minute = (slot % 4) * 15;
            this.$wire.createEventAt(date, hour, minute);
        },

        // ═══════════════════════════════════════════════════════════════
        // TIMED-EVENT Drag & Drop  (Week + Day)
        // ═══════════════════════════════════════════════════════════════

        onDragStart(e, id) {
            this.draggingId     = id;
            this.focusedEventId = null;
            const rect = e.currentTarget.getBoundingClientRect();
            this.dragOffsetY  = e.clientY - rect.top;
            // Datum der gegriffenen Kopie (data-grab-date gesetzt im Blade)
            this.dragGrabDate = e.currentTarget.dataset.grabDate || null;
            e.dataTransfer.effectAllowed = 'move';

            // Klon erstellen der der Maus folgt (statt statischem Browser-Ghost)
            const clone = e.currentTarget.cloneNode(true);
            // Alpine-Attribute entfernen (Klon lebt außerhalb des x-data Scopes)
            clone.querySelectorAll('[x-bind\\:class],[x-bind\\:style],[x-on\\:click],[x-on\\:dblclick],[x-on\\:dragstart],[x-on\\:dragend],[x-on\\:mousedown]').forEach(el => {
                [...el.attributes].forEach(a => { if (a.name.startsWith('x-') || a.name.startsWith(':') || a.name.startsWith('@')) el.removeAttribute(a.name); });
            });
            [...clone.attributes].forEach(a => { if (a.name.startsWith('x-') || a.name.startsWith(':') || a.name.startsWith('@')) clone.removeAttribute(a.name); });
            clone.removeAttribute('wire:key');
            clone.removeAttribute('draggable');
            clone.style.position   = 'fixed';
            clone.style.width      = rect.width + 'px';
            clone.style.height     = rect.height + 'px';
            clone.style.left       = rect.left + 'px';
            clone.style.top        = rect.top + 'px';
            clone.style.zIndex     = '9999';
            clone.style.pointerEvents = 'none';
            clone.style.opacity    = '0.92';
            clone.style.boxShadow  = '0 4px 16px rgba(0,0,0,0.18)';
            clone.style.transition = 'none';
            clone.id = 'drag-clone';
            document.body.appendChild(clone);

            this._dragClone    = clone;
            this._dragCloneTimeEl = clone.querySelector('[data-time-display]');
            this._dragDurSlots = Math.round(e.currentTarget.offsetHeight / SLOT_PX);
            this._dragOffsetX  = e.clientX - rect.left;

            // Nativen Ghost verstecken
            const ghost = document.createElement('div');
            ghost.style.cssText = 'position:fixed;top:-999px;left:-999px;width:1px;height:1px;opacity:0;';
            document.body.appendChild(ghost);
            e.dataTransfer.setDragImage(ghost, 0, 0);
            requestAnimationFrame(() => document.body.removeChild(ghost));

            setTimeout(() => e.target.style.opacity = '0.15', 0);
        },

        onDragEnd(e) {
            e.target.style.opacity = '1';
            if (this._dragClone) { this._dragClone.remove(); this._dragClone = null; }
            this._dragCloneTimeEl = null;
            this.draggingId    = null;
            this.dragOffsetY   = 0;
            this.dragGrabDate  = null;
            this._dragDurSlots = 0;
        },

        onDragOver(e) {
            e.preventDefault();
            e.currentTarget.style.background = 'rgba(99,102,241,0.07)';

            // Klon der Maus folgen lassen + Zeit live aktualisieren
            if (this._dragClone && e.clientY > 0) {
                this._dragClone.style.left = (e.clientX - this._dragOffsetX) + 'px';
                this._dragClone.style.top  = (e.clientY - this.dragOffsetY) + 'px';

                const rect   = e.currentTarget.getBoundingClientRect();
                const relY   = Math.max(0, e.clientY - rect.top - this.dragOffsetY);
                const slot   = Math.round(relY / SLOT_PX);
                const hour   = Math.min(Math.floor(slot / 4) + this.hourStart, 23);
                const minute = (slot % 4) * 15;
                const endSlot = slot + this._dragDurSlots;
                const endH    = Math.min(Math.floor(endSlot / 4) + this.hourStart, 24);
                const endM    = (endSlot % 4) * 15;

                if (this._dragCloneTimeEl) {
                    this._dragCloneTimeEl.textContent = this._timeStr(hour, minute) + ' – ' + this._timeStr(endH, endM);
                }
            }
        },

        onDragLeave(e) {
            if (e.relatedTarget && e.currentTarget.contains(e.relatedTarget)) return;
            e.currentTarget.style.background = '';
        },

        onDrop(e, date) {
            e.preventDefault();
            e.currentTarget.style.background = '';
            if (!this.draggingId) return;

            const rect   = e.currentTarget.getBoundingClientRect();
            const relY   = Math.max(0, e.clientY - rect.top - this.dragOffsetY);
            const slot   = Math.round(relY / SLOT_PX);
            const hour   = Math.min(Math.floor(slot / 4), 23);
            const minute = (slot % 4) * 15;

            // dragGrabDate: Datum der gegriffenen Kopie → PHP berechnet dayDelta relativ
            this.$wire.moveEvent(this.draggingId, date, hour, minute, this.dragGrabDate);
            this.draggingId   = null;
            this.dragOffsetY  = 0;
            this.dragGrabDate = null;
        },

        // ═══════════════════════════════════════════════════════════════
        // RESIZE  (Week + Day)
        // ═══════════════════════════════════════════════════════════════

        onResizeStart(e, id) {
            e.preventDefault();

            const wire      = this.$wire;
            const startY    = e.clientY;
            const eventEl   = e.currentTarget.parentElement;
            const startH    = eventEl.offsetHeight;
            const topPx     = eventEl.offsetTop;
            const hourStart = this.hourStart;
            const timeEl    = eventEl.querySelector('[data-time-display]');
            const origTime  = timeEl ? timeEl.textContent : '';

            const startSlot = Math.round(topPx / SLOT_PX);
            const sH = Math.min(Math.floor(startSlot / 4) + hourStart, 23);
            const sM = (startSlot % 4) * 15;

            eventEl.style.transition       = 'none';
            document.body.style.userSelect = 'none';
            document.body.style.cursor     = 'ns-resize';

            const onMove = (mv) => {
                const snapped   = Math.round((mv.clientY - startY) / SLOT_PX) * SLOT_PX;
                const newHeight = Math.max(SLOT_PX, startH + snapped);
                eventEl.style.height = newHeight + 'px';

                if (timeEl) {
                    const endSlot = Math.round((topPx + newHeight) / SLOT_PX);
                    const endH    = Math.min(Math.floor(endSlot / 4) + hourStart, 24);
                    const endM    = (endSlot % 4) * 15;
                    timeEl.textContent = this._timeStr(sH, sM) + ' – ' + this._timeStr(endH, endM);
                }
            };

            const onUp = (up) => {
                document.body.style.cursor     = '';
                document.body.style.userSelect = '';
                eventEl.style.transition       = '';

                const delta = Math.round((up.clientY - startY) / SLOT_PX) * 0.25;

                if (Math.abs(delta) >= 0.25) {
                    wire.resizeEvent(id, delta);
                } else {
                    eventEl.style.height = startH + 'px';
                    if (timeEl) timeEl.textContent = origTime;
                }

                window.removeEventListener('mousemove', onMove);
                window.removeEventListener('mouseup',   onUp);
            };

            window.addEventListener('mousemove', onMove);
            window.addEventListener('mouseup',   onUp);
        },

        // ═══════════════════════════════════════════════════════════════
        // ALL-DAY DnD  (Week – X-Achse)
        // ═══════════════════════════════════════════════════════════════

        onAllDayDragStart(e, id, startCol, startDate) {
            this.draggingAllDayId        = id;
            this.draggingAllDayStartCol  = startCol;
            this.draggingAllDayStartDate = startDate;

            const strip = this.$refs.allDayStrip;
            if (strip) {
                const stripRect = strip.getBoundingClientRect();
                const grabCol   = Math.min(6, Math.max(0, Math.floor((e.clientX - stripRect.left) / stripRect.width * 7)));
                // Grab-Datum aus data-date des Spalten-Divs lesen (exakte Datumsreferenz)
                const colEl     = strip.querySelector(`[data-col="${grabCol}"]`);
                this.draggingAllDayGrabDate  = colEl ? colEl.dataset.date : startDate;
                // Offset für visuelle Preview (Spalten-basiert)
                this.allDayGrabColOffset = Math.max(0, grabCol - startCol);
            } else {
                this.draggingAllDayGrabDate  = startDate;
                this.allDayGrabColOffset = 0;
            }

            e.dataTransfer.effectAllowed = 'move';
            const ghost = document.createElement('div');
            ghost.style.cssText = 'position:fixed;top:-999px;left:-999px;width:1px;height:1px;opacity:0;';
            document.body.appendChild(ghost);
            e.dataTransfer.setDragImage(ghost, 0, 0);
            requestAnimationFrame(() => document.body.removeChild(ghost));

            setTimeout(() => e.target.style.opacity = '0.45', 0);
        },

        onAllDayDragEnd(e) {
            e.target.style.opacity   = '1';
            this.draggingAllDayId    = null;
            this.allDayDropCol       = null;
            this.allDayGrabColOffset = 0;
        },

        onAllDayDragOver(e) {
            e.preventDefault();
            if (!this.draggingAllDayId) return;

            const strip = this.$refs.allDayStrip;
            if (!strip) return;

            const rect        = strip.getBoundingClientRect();
            const rawCol      = Math.floor((e.clientX - rect.left) / rect.width * 7);
            const targetStart = Math.max(0, Math.min(6, rawCol - this.allDayGrabColOffset));
            this.allDayDropCol = targetStart;

            e.dataTransfer.dropEffect = 'move';
        },

        onAllDayDragLeave(e) {
            if (e.relatedTarget && e.currentTarget.contains(e.relatedTarget)) return;
            this.allDayDropCol = null;
        },

        onAllDayDrop(e) {
            e.preventDefault();
            if (!this.draggingAllDayId) return;

            const strip = this.$refs.allDayStrip;
            if (!strip) return;

            const rect   = strip.getBoundingClientRect();
            const rawCol = Math.min(6, Math.max(0, Math.floor((e.clientX - rect.left) / rect.width * 7)));

            // Datum des Ziel-Spalte aus data-date lesen → exakte Berechnung, keine Spalten-Clipping-Fehler
            const colEl   = strip.querySelector(`[data-col="${rawCol}"]`);
            const dropDate = colEl ? colEl.dataset.date : null;

            if (dropDate && this.draggingAllDayGrabDate) {
                const dayDelta = Math.round(
                    (new Date(dropDate + 'T00:00:00') - new Date(this.draggingAllDayGrabDate + 'T00:00:00'))
                    / 86400000
                );
                if (dayDelta !== 0) {
                    this.$wire.moveAllDayEvent(this.draggingAllDayId, dayDelta);
                }
            }

            this.draggingAllDayId       = null;
            this.draggingAllDayGrabDate = null;
            this.allDayDropCol          = null;
            this.allDayGrabColOffset    = 0;
        },

        // ═══════════════════════════════════════════════════════════════
        // MONTH-VIEW DnD  (timed + all-day Events)
        // ═══════════════════════════════════════════════════════════════

        onMonthEventDragStart(e, id, hour, minute, isAllDay, startDate) {
            this.monthDraggingId        = id;
            this.monthDraggingIsAllDay  = isAllDay;
            this.monthDraggingHour      = hour;
            this.monthDraggingMinute    = minute;
            this.monthDraggingStartDate = startDate;
            this.focusedEventId         = null;
            e.dataTransfer.effectAllowed = 'move';
            setTimeout(() => e.target.style.opacity = '0.4', 0);
        },

        onMonthEventDragEnd(e) {
            e.target.style.opacity  = '1';
            this.monthDraggingId    = null;
        },

        onMonthDayDragOver(e) {
            if (!this.monthDraggingId) return;
            e.preventDefault();
            e.currentTarget.style.background = 'rgba(99,102,241,0.07)';
            e.dataTransfer.dropEffect = 'move';
        },

        onMonthDayDragLeave(e) {
            if (e.relatedTarget && e.currentTarget.contains(e.relatedTarget)) return;
            e.currentTarget.style.background = '';
        },

        onMonthDayDrop(e, date) {
            e.preventDefault();
            e.currentTarget.style.background = '';
            if (!this.monthDraggingId) return;

            if (this.monthDraggingIsAllDay) {
                // Tagesgenaues Verschieben via dayDelta
                const start = new Date(this.monthDraggingStartDate + 'T00:00:00');
                const drop  = new Date(date + 'T00:00:00');
                const delta = Math.round((drop - start) / 86400000);
                if (delta !== 0) {
                    this.$wire.moveAllDayEvent(this.monthDraggingId, delta);
                }
            } else {
                // grabDate = monthDraggingStartDate ($dayStr der gegriffenen Kopie)
                // → PHP berechnet dayDelta relativ und verschiebt Start+End
                this.$wire.moveEvent(
                    this.monthDraggingId,
                    date,
                    this.monthDraggingHour,
                    this.monthDraggingMinute,
                    this.monthDraggingStartDate
                );
            }

            this.monthDraggingId = null;
        },
    }));
});
