<script setup>
import { computed, nextTick, ref, watch, onMounted, onUnmounted } from 'vue'
import { router } from '@inertiajs/vue3'
import { VueDraggable } from 'vue-draggable-plus'

const MASTER_ID = 'master'

const props = defineProps({
    songId: {
        type: Number,
        default: null,
    },
    arrangements: {
        type: Array,
        default: () => [],
    },
    availableGroups: {
        type: Array,
        default: () => [],
    },
    selectedArrangementId: {
        type: Number,
        default: null,
    },
    serviceSongId: {
        type: Number,
        default: null,
    },
    songsCatalog: {
        type: Array,
        default: () => [],
    },
})

const emit = defineEmits(['close', 'arrangement-selected'])

/* ── Song assignment (unmatched songs) ── */

const isUnmatched = computed(() => !props.songId)

const searchQuery = ref('')
const selectedSongId = ref('')
const dropdownOpen = ref(false)
const assignError = ref('')

function normalize(value) {
    return (value ?? '').toString().toLowerCase().trim()
}

const filteredCatalog = computed(() => {
    const term = normalize(searchQuery.value)
    if (term === '') return props.songsCatalog.slice(0, 100)
    return props.songsCatalog
        .filter((song) => normalize(song.title).includes(term) || normalize(song.ccli_id).includes(term))
        .slice(0, 100)
})

function openSearchDropdown() {
    dropdownOpen.value = true
}

function closeSearchDropdown() {
    setTimeout(() => {
        dropdownOpen.value = false
    }, 200)
}

function selectSong(song) {
    selectedSongId.value = song.id
    searchQuery.value = song.title
    dropdownOpen.value = false
}

async function assignSong() {
    const songId = Number(selectedSongId.value)
    if (!songId) {
        assignError.value = 'Bitte wähle zuerst einen Song aus.'
        return
    }
    assignError.value = ''

    try {
        await window.axios.post(`/api/service-songs/${props.serviceSongId}/assign`, {
            song_id: songId,
        })
        emit('close')
    } catch {
        assignError.value = 'Zuordnung fehlgeschlagen.'
    }
}

/* ── State ── */

// Virtual MASTER arrangement — always first, computed from availableGroups
const masterArrangement = computed(() => ({
    id: MASTER_ID,
    name: 'MASTER',
    is_default: false,
    is_master: true,
    groups: props.availableGroups.map((g) => ({
        ...g,
        slides: g.slides ?? [],
    })),
}))

// All arrangements with MASTER prepended (for select dropdown)
const allArrangements = computed(() => [
    masterArrangement.value,
    ...props.arrangements,
])

const isMasterSelected = computed(() => currentArrangementId.value === MASTER_ID)

// Local copy of arrangements so changes survive switching between arrangements
const localArrangements = ref(JSON.parse(JSON.stringify(props.arrangements)))

watch(
    () => props.arrangements,
    (newArr) => {
        // Merge server updates (e.g. after create/clone/delete) but keep local edits for existing arrangements
        const localById = Object.fromEntries(localArrangements.value.map((a) => [a.id, a]))
        localArrangements.value = newArr.map((a) => localById[a.id] ?? JSON.parse(JSON.stringify(a)))
        // Add any new arrangements not in local
        for (const a of newArr) {
            if (!localById[a.id]) {
                localArrangements.value.push(JSON.parse(JSON.stringify(a)))
            }
        }
    },
    { deep: true },
)

const currentArrangementId = ref(
    props.selectedArrangementId ?? props.arrangements.find((a) => a.is_default)?.id ?? props.arrangements[0]?.id ?? MASTER_ID,
)

const currentArrangement = computed(() => {
    if (currentArrangementId.value === MASTER_ID) return masterArrangement.value
    return localArrangements.value.find((a) => a.id === Number(currentArrangementId.value)) ?? null
})

const arrangementGroups = ref([])
const hoveredIndex = ref(null)
const clickedIndex = ref(null)
let clickedTimeout = null
const rightItems = ref([])

function setRightItemRef(el, index) {
    if (el) rightItems.value[index] = el
}

function scrollToRight(index) {
    const el = rightItems.value[index]
    if (!el) return
    el.scrollIntoView({ behavior: 'smooth', block: 'nearest' })
    clickedIndex.value = index
    if (clickedTimeout) clearTimeout(clickedTimeout)
    clickedTimeout = setTimeout(() => {
        clickedIndex.value = null
    }, 1500)
}

watch(
    currentArrangementId,
    (id) => {
        rightItems.value = []
        clickedIndex.value = null
        if (id === MASTER_ID) {
            arrangementGroups.value = props.availableGroups.map((g, i) => ({ ...g, slides: g.slides ?? [], _uid: `${g.id}-master-${i}-${Date.now()}` }))
            return
        }
        const arr = localArrangements.value.find((a) => a.id === Number(id))
        const arrGroups = arr?.groups ?? (arr?.arrangement_groups
            ? arr.arrangement_groups.map((ag) => props.availableGroups.find((g) => g.id === ag.label_id)).filter(Boolean)
            : [])
        if (arrGroups.length) {
            arrangementGroups.value = arrGroups.map((g, i) => ({ ...g, _uid: `${g.id}-${i}-${Date.now()}` }))
        } else {
            // Fallback: show all available groups in order (Master)
            arrangementGroups.value = props.availableGroups.map((g, i) => ({ ...g, slides: g.slides ?? [], _uid: `${g.id}-master-${i}-${Date.now()}` }))
        }
    },
    { immediate: true },
)

const pendingAutoSelect = ref(false)

watch(
    () => props.arrangements.length,
    (newLen, oldLen) => {
        if (pendingAutoSelect.value && newLen > oldLen) {
            const newest = props.arrangements.reduce((a, b) => (a.id > b.id ? a : b))
            currentArrangementId.value = newest.id
            pendingAutoSelect.value = false
        }
    },
)

/* ── Scroll sync ── */

const leftCol = ref(null)
const rightCol = ref(null)
let syncing = false

function syncScroll(from) {
    if (syncing) return
    syncing = true
    if (from === 'left' && rightCol.value) {
        rightCol.value.scrollTop = leftCol.value.scrollTop
    } else if (from === 'right' && leftCol.value) {
        leftCol.value.scrollTop = rightCol.value.scrollTop
    }
    nextTick(() => {
        syncing = false
    })
}

/* ── Group picker ── */

const groupPickerOpen = ref(null)

function toggleGroupPicker(index) {
    groupPickerOpen.value = groupPickerOpen.value === index ? null : index
}

/* ── Close on outside click for group picker ── */

function onBodyClick(e) {
    if (groupPickerOpen.value !== null && !e.target.closest('[data-group-picker]')) {
        groupPickerOpen.value = null
    }
}

/* ── Keyboard: Escape ── */

function closeOnEscape(e) {
    if (e.key === 'Escape') {
        if (groupPickerOpen.value !== null) {
            groupPickerOpen.value = null
        } else {
            emit('close')
        }
    }
}

onMounted(() => {
    document.addEventListener('keydown', closeOnEscape)
    document.addEventListener('click', onBodyClick)
})

onUnmounted(() => {
    document.removeEventListener('keydown', closeOnEscape)
    document.removeEventListener('click', onBodyClick)
})

/* ── Arrangement CRUD (Inertia router, matching ArrangementConfigurator patterns) ── */

function createArrangement() {
    const name = window.prompt('Name für das neue Arrangement:')
    if (!name?.trim()) return
    pendingAutoSelect.value = true
    router.post(`/songs/${props.songId}/arrangements`, { name: name.trim() }, {
        preserveScroll: true,
        onSuccess: () => {
            router.reload({ preserveScroll: true })
        },
    })
}

function cloneArrangement() {
    if (!currentArrangementId.value) return

    // Cloning from MASTER = creating a new arrangement (store() already uses all groups in master order)
    if (isMasterSelected.value) {
        const name = window.prompt('Name für das geklonte Arrangement:', 'MASTER Kopie')
        if (!name?.trim()) return
        pendingAutoSelect.value = true
        router.post(`/songs/${props.songId}/arrangements`, { name: name.trim() }, {
            preserveScroll: true,
            onSuccess: () => {
                router.reload({ preserveScroll: true })
            },
        })
        return
    }

    const name = window.prompt('Name für das geklonte Arrangement:', `${currentArrangement.value?.name ?? ''} Kopie`)
    if (!name?.trim()) return
    pendingAutoSelect.value = true
    router.post(`/arrangements/${currentArrangementId.value}/clone`, { name: name.trim() }, {
        preserveScroll: true,
        onSuccess: () => {
            router.reload({ preserveScroll: true })
        },
    })
}

function deleteArrangement() {
    if (!currentArrangementId.value || isMasterSelected.value) return
    if (props.arrangements.length <= 1) {
        alert('Das letzte Arrangement kann nicht gelöscht werden.')
        return
    }
    if (!confirm('Arrangement wirklich löschen?')) return
    router.delete(`/arrangements/${currentArrangementId.value}`, {
        preserveScroll: true,
        onSuccess: () => {
            router.reload({ preserveScroll: true })
        },
    })
}

function saveArrangement() {
    if (!currentArrangement.value || isMasterSelected.value) return

    // Update local arrangements copy so changes survive switching
    const localArr = localArrangements.value.find((a) => a.id === currentArrangement.value.id)
    if (localArr) {
        localArr.groups = arrangementGroups.value.map((g, i) => ({
            ...g,
            order: i + 1,
        }))
    }

    router.put(
        `/arrangements/${currentArrangement.value.id}`,
        {
            groups: arrangementGroups.value.map((group, index) => ({
                label_id: group.id,
                order: index + 1,
            })),
        },
        {
            preserveScroll: true,
            preserveState: true,
        },
    )
}

/* ── Group operations ── */

function duplicateGroup(index) {
    if (isMasterSelected.value) return
    const item = arrangementGroups.value[index]
    const newItem = { ...item, _uid: `${item.id}-dup-${Date.now()}` }
    arrangementGroups.value.splice(index + 1, 0, newItem)
    saveArrangement()
}

function addGroupAt(index, group) {
    if (isMasterSelected.value) return
    const newItem = {
        id: group.id,
        name: group.name,
        color: group.color,
        slides: group.slides ?? [],
        _uid: `${group.id}-add-${Date.now()}`,
    }
    arrangementGroups.value.splice(index + 1, 0, newItem)
    groupPickerOpen.value = null
    saveArrangement()
}

function removeGroupAt(index) {
    if (isMasterSelected.value) return
    arrangementGroups.value.splice(index, 1)
    saveArrangement()
}

/* ── Selection emit ── */

watch(currentArrangementId, (id) => {
    emit('arrangement-selected', id === MASTER_ID ? null : Number(id))
})

/* ── Close on backdrop ── */

function closeOnBackdrop(e) {
    if (e.target === e.currentTarget) {
        emit('close')
    }
}
</script>

<template>
    <Teleport to="body">
        <Transition
            enter-active-class="transition duration-200 ease-out"
            enter-from-class="opacity-0"
            enter-to-class="opacity-100"
            leave-active-class="transition duration-150 ease-in"
            leave-from-class="opacity-100"
            leave-to-class="opacity-0"
        >
            <div
                class="fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4"
                @click="closeOnBackdrop"
            >
                <div
                    data-testid="arrangement-dialog"
                    :class="isUnmatched
                        ? 'flex w-full max-w-lg flex-col rounded-xl bg-white shadow-2xl'
                        : 'flex h-[80vh] w-full max-w-5xl flex-col rounded-xl bg-white shadow-2xl'"
                >
                    <!-- Header: Unmatched song assignment -->
                    <div v-if="isUnmatched" class="flex items-center gap-3 border-b border-gray-200 px-6 py-4">
                        <h3 class="text-base font-semibold text-gray-900">Song zuordnen</h3>
                        <button
                            data-testid="arrangement-dialog-close-btn"
                            type="button"
                            class="ml-auto rounded-lg p-2 text-gray-400 hover:bg-gray-100 hover:text-gray-600"
                            @click="emit('close')"
                        >
                            <svg class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
                                <path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
                            </svg>
                        </button>
                    </div>

                    <!-- Header: Arrangement editor -->
                    <div v-else class="flex items-center gap-3 border-b border-gray-200 px-6 py-4">
                        <div class="min-w-48 flex-1">
                            <select
                                v-model="currentArrangementId"
                                data-testid="arrangement-select"
                                class="block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500"
                            >
                                <option
                                    v-for="arr in allArrangements"
                                    :key="arr.id"
                                    :value="arr.id"
                                >
                                    {{ arr.name }}{{ arr.is_default ? ' (Standard)' : '' }}
                                </option>
                            </select>
                        </div>

                        <button
                            data-testid="arrangement-new-btn"
                            type="button"
                            class="rounded-md bg-blue-600 px-3 py-2 text-sm font-semibold text-white shadow hover:bg-blue-700"
                            @click="createArrangement"
                        >
                            Neu
                        </button>

                        <button
                            data-testid="arrangement-clone-btn"
                            type="button"
                            class="rounded-md bg-slate-700 px-3 py-2 text-sm font-semibold text-white shadow hover:bg-slate-800"
                            @click="cloneArrangement"
                        >
                            Duplizieren
                        </button>

                        <button
                            data-testid="arrangement-delete-btn"
                            type="button"
                            class="rounded-md bg-red-600 px-3 py-2 text-sm font-semibold text-white shadow hover:bg-red-700 disabled:cursor-not-allowed disabled:opacity-40"
                            :disabled="isMasterSelected"
                            @click="deleteArrangement"
                        >
                            Löschen
                        </button>

                        <button
                            data-testid="arrangement-dialog-close-btn"
                            type="button"
                            class="ml-auto rounded-lg p-2 text-gray-400 hover:bg-gray-100 hover:text-gray-600"
                            @click="emit('close')"
                        >
                            <svg
                                class="h-5 w-5"
                                fill="none"
                                viewBox="0 0 24 24"
                                stroke="currentColor"
                                stroke-width="2"
                            >
                                <path
                                    stroke-linecap="round"
                                    stroke-linejoin="round"
                                    d="M6 18L18 6M6 6l12 12"
                                />
                            </svg>
                        </button>
                    </div>

                    <!-- Body: Unmatched song search & assign -->
                    <div v-if="isUnmatched" class="flex-1 overflow-y-auto p-6">
                        <div class="mx-auto max-w-lg space-y-4">
                            <p class="text-sm text-gray-600">
                                Dieser CTS-Song ist noch nicht in der Song-DB verknüpft. Suche den passenden Song und ordne ihn zu.
                            </p>

                            <div class="relative">
                                <label class="mb-1 block text-xs font-semibold uppercase tracking-wide text-gray-600">
                                    Song suchen und auswählen
                                </label>
                                <input
                                    v-model="searchQuery"
                                    type="text"
                                    placeholder="Titel oder CCLI eingeben…"
                                    class="block w-full rounded-md border-gray-300 text-sm shadow-sm focus:border-emerald-500 focus:ring-emerald-500"
                                    data-testid="song-search-input"
                                    @focus="openSearchDropdown"
                                    @input="openSearchDropdown"
                                    @blur="closeSearchDropdown"
                                />
                                <!-- Selected indicator -->
                                <div v-if="selectedSongId" class="mt-1 flex items-center gap-2">
                                    <span class="text-xs font-medium text-emerald-700">
                                        Ausgewählt: {{ songsCatalog.find((s) => s.id === Number(selectedSongId))?.title || '' }}
                                    </span>
                                    <button
                                        type="button"
                                        class="text-xs text-gray-400 hover:text-red-500"
                                        @click="selectedSongId = ''; searchQuery = ''"
                                    >
                                        &#10005;
                                    </button>
                                </div>
                                <!-- Dropdown -->
                                <div
                                    v-if="dropdownOpen && filteredCatalog.length > 0"
                                    class="absolute z-30 mt-1 max-h-64 w-full overflow-auto rounded-md border border-gray-200 bg-white shadow-lg"
                                >
                                    <button
                                        v-for="song in filteredCatalog"
                                        :key="song.id"
                                        type="button"
                                        class="flex w-full items-center gap-2 px-3 py-2 text-left text-sm hover:bg-emerald-50"
                                        @mousedown.prevent="selectSong(song)"
                                    >
                                        <span class="font-medium text-gray-900">{{ song.title }}</span>
                                        <span class="ml-auto text-xs text-gray-400">CCLI: {{ song.ccli_id || '–' }}</span>
                                    </button>
                                </div>
                            </div>

                            <p v-if="assignError" class="text-sm text-red-600">{{ assignError }}</p>

                            <button
                                type="button"
                                class="inline-flex items-center justify-center rounded-md bg-emerald-600 px-5 py-2 text-sm font-semibold text-white shadow transition hover:bg-emerald-700"
                                data-testid="song-assign-button"
                                @click="assignSong"
                            >
                                Zuordnen
                            </button>
                        </div>
                    </div>

                    <!-- Body: Two-column arrangement editor -->
                    <div v-else class="flex flex-1 overflow-hidden">
                        <!-- Left: Pill list with DnD -->
                        <div
                            ref="leftCol"
                            data-testid="arrangement-pill-list"
                            class="flex w-1/2 flex-col gap-2 overflow-y-auto border-r border-gray-200 p-4"
                            @scroll="syncScroll('left')"
                        >
                            <h4 class="text-xs font-semibold uppercase tracking-wide text-gray-500">
                                Gruppenfolge
                                <span v-if="isMasterSelected" class="ml-1 text-[10px] font-normal normal-case text-gray-400">(nicht editierbar)</span>
                            </h4>

                            <VueDraggable
                                v-model="arrangementGroups"
                                :disabled="isMasterSelected"
                                ghost-class="drag-ghost"
                                chosen-class="drag-chosen"
                                drag-class="drag-active"
                                class="flex flex-col gap-2"
                                :class="{ 'opacity-60': isMasterSelected }"
                                @end="saveArrangement"
                            >
                                <div
                                    v-for="(element, index) in arrangementGroups"
                                    :key="element._uid"
                                    data-testid="arrangement-pill"
                                    class="flex items-center gap-2 rounded-lg border-2 px-3 py-2 transition-shadow"
                                    :class="[
                                        { 'ring-2 ring-indigo-400 ring-offset-1': hoveredIndex === index || clickedIndex === index },
                                        isMasterSelected ? 'cursor-default' : 'cursor-grab',
                                    ]"
                                    :style="{
                                        borderColor: element.color ?? '#6b7280',
                                        backgroundColor: (element.color ?? '#6b7280') + '20',
                                    }"
                                    @click="scrollToRight(index)"
                                >
                                    <!-- Group name -->
                                    <span class="flex-1 text-sm font-medium">
                                        {{ element.name }}
                                    </span>

                                    <template v-if="!isMasterSelected">
                                        <!-- Duplicate button (2×) -->
                                        <button
                                            data-testid="arrangement-duplicate-btn"
                                            type="button"
                                            class="rounded bg-gray-100 px-2 py-0.5 text-xs hover:bg-gray-200"
                                            @click="duplicateGroup(index)"
                                        >
                                            2×
                                        </button>

                                        <!-- Add group button (+) -->
                                        <div
                                            class="relative"
                                            data-group-picker
                                        >
                                            <button
                                                data-testid="arrangement-add-group-btn"
                                                type="button"
                                                class="rounded bg-blue-100 px-2 py-0.5 text-xs text-blue-700 hover:bg-blue-200"
                                                @click.stop="toggleGroupPicker(index)"
                                            >
                                                +
                                            </button>

                                            <!-- Quick select dropdown -->
                                            <div
                                                v-if="groupPickerOpen === index"
                                                class="absolute right-0 top-8 z-10 min-w-36 rounded-lg border border-gray-200 bg-white shadow-lg"
                                            >
                                                <button
                                                    v-for="g in availableGroups"
                                                    :key="g.id"
                                                    type="button"
                                                    class="block w-full px-3 py-1.5 text-left text-sm hover:bg-gray-50"
                                                    @click="addGroupAt(index, g)"
                                                >
                                                    <span
                                                        class="mr-1.5 inline-block h-2.5 w-2.5 rounded-full"
                                                        :style="{ backgroundColor: g.color }"
                                                    />
                                                    {{ g.name }}
                                                </button>
                                            </div>
                                        </div>

                                        <!-- Remove button -->
                                        <button
                                            data-testid="arrangement-remove-btn"
                                            type="button"
                                            class="rounded px-1.5 py-0.5 text-xs text-red-400 hover:bg-red-50 hover:text-red-600"
                                            @click="removeGroupAt(index)"
                                        >
                                            ×
                                        </button>
                                    </template>
                                </div>
                            </VueDraggable>

                            <!-- Empty state -->
                            <div
                                v-if="arrangementGroups.length === 0"
                                class="flex flex-1 items-center justify-center rounded-lg border-2 border-dashed border-gray-300 p-8 text-center text-sm text-gray-400"
                            >
                                Noch keine Gruppen zugeordnet.
                            </div>
                        </div>

                        <!-- Right: Lyric preview (scroll-synced) -->
                        <div
                            ref="rightCol"
                            data-testid="arrangement-lyric-preview"
                            class="flex w-1/2 flex-col gap-2 overflow-y-auto bg-gray-50 p-4"
                            @scroll="syncScroll('right')"
                        >
                            <h4 class="text-xs font-semibold uppercase tracking-wide text-gray-500">
                                Textvorschau
                            </h4>

                            <div
                                v-for="(element, index) in arrangementGroups"
                                :key="element._uid"
                                :ref="(el) => setRightItemRef(el, index)"
                                class="rounded-r-lg border-l-4 bg-white p-3 shadow-sm transition-shadow"
                                :class="{ 'ring-2 ring-indigo-400 ring-offset-1': hoveredIndex === index || clickedIndex === index }"
                                :style="{ borderColor: element.color ?? '#6b7280' }"
                                @mouseenter="hoveredIndex = index"
                                @mouseleave="hoveredIndex = null"
                            >
                                <!-- Group name pill -->
                                <span
                                    class="mb-2 inline-block rounded-full px-2 py-0.5 text-xs font-semibold text-white"
                                    :style="{ backgroundColor: element.color ?? '#6b7280' }"
                                >
                                    {{ element.name }}
                                </span>

                                <!-- Slides -->
                                <template v-if="element.slides?.length > 0">
                                    <div
                                        v-for="(slide, si) in element.slides"
                                        :key="slide.id ?? si"
                                    >
                                        <div
                                            v-if="si > 0"
                                            class="my-1.5 border-t border-gray-200"
                                        />
                                        <p class="whitespace-pre-wrap text-sm">
                                            {{ slide.text_content }}
                                        </p>
                                        <p
                                            v-if="slide.text_content_translated"
                                            class="mt-0.5 whitespace-pre-wrap text-xs italic text-gray-400"
                                        >
                                            {{ slide.text_content_translated }}
                                        </p>
                                    </div>
                                </template>

                                <!-- No slides -->
                                <p
                                    v-else
                                    class="text-xs italic text-gray-300"
                                >
                                    Kein Text vorhanden
                                </p>
                            </div>

                            <!-- Empty state -->
                            <div
                                v-if="arrangementGroups.length === 0"
                                class="flex flex-1 items-center justify-center text-sm text-gray-400"
                            >
                                Wähle ein Arrangement aus, um die Vorschau zu sehen.
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </Transition>
    </Teleport>
</template>

<style scoped>
:deep(.drag-ghost) {
    opacity: 0.4;
    box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.8), 0 0 0 4px rgba(99, 102, 241, 0.6);
    border-radius: 0.5rem;
}

:deep(.drag-chosen) {
    opacity: 0.7;
}

:deep(.drag-active) {
    opacity: 1 !important;
    transform: scale(1.02);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3), 0 0 0 2px rgba(255, 255, 255, 0.8);
    border-radius: 0.5rem;
    z-index: 50;
}
</style>
