<script setup>
import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout.vue'
import { Head, router, usePage } from '@inertiajs/vue3'

const $page = usePage()
import { ref, computed } from 'vue'
import InformationBlock from '@/Components/Blocks/InformationBlock.vue'
import AgendaItemRow from '@/Components/AgendaItemRow.vue'
import SongAgendaItem from '@/Components/SongAgendaItem.vue'
import ArrangementDialog from '@/Components/ArrangementDialog.vue'
import MacroIcon from '@/Components/MacroIcon.vue'
import ServicePartMacroPanel from '@/Components/ServicePartMacroPanel.vue'
import ServiceImagePanel from '@/Components/ServiceImagePanel.vue'

const props = defineProps({
    service: {
        type: Object,
        required: true,
    },
    serviceSongs: {
        type: Array,
        default: () => [],
    },
    informationSlides: {
        type: Array,
        default: () => [],
    },
    songsCatalog: {
        type: Array,
        default: () => [],
    },
    prevService: {
        type: Object,
        default: null,
    },
    nextService: {
        type: Object,
        default: null,
    },
    agendaItems: {
        type: Array,
        default: () => [],
    },
    agendaSettings: {
        type: Object,
        default: () => ({}),
    },
    macros_per_part: {
        type: Object,
        default: () => ({}),
    },
})

const openMacroPanel = ref(null)

const macroPartLabels = {
    information: 'Informationen',
    moderation: 'Moderation',
    sermon: 'Predigt',
    song: 'Lieder',
    agenda_item: 'Ablaufpunkte',
}

function toggleMacroPanel(partType) {
    openMacroPanel.value = openMacroPanel.value === partType ? null : partType
}

function macroPartData(partType) {
    return props.macros_per_part?.[partType] ?? { count: 0, is_overridden: false, has_warning: false, assignments: [] }
}

const formattedDate = computed(() => {
    if (!props.service.date) return ''
    return new Date(props.service.date).toLocaleDateString('de-DE', {
        weekday: 'long',
        day: '2-digit',
        month: 'long',
        year: 'numeric',
    })
})

function formatShortDate(dateStr) {
    if (!dateStr) return ''
    return new Date(dateStr).toLocaleDateString('de-DE', {
        day: '2-digit',
        month: '2-digit',
        year: 'numeric',
    })
}

function goBack() {
    router.get(route('services.index'))
}

const informationBlockRef = ref(null)

function refreshPage() {
    router.reload({ preserveScroll: true })
}

function updateNameOverride(field, value) {
    router.patch(route('services.name-overrides.update', { service: props.service.id }), {
        [field]: value || null,
    }, { preserveScroll: true })
}

function scrollToInfoBlock() {
    informationBlockRef.value?.scrollIntoView({ behavior: 'smooth', block: 'start' })
}

/* ── Agenda helpers ──────────────────────────────────────── */

const arrangementDialogItem = ref(null)

function openArrangementDialog(item) {
    const serviceSong = item.service_song ?? item.serviceSong ?? null
    const songId = serviceSong?.song_id ?? null

    // Unmatched -> open immediately (assignment flow).
    if (!serviceSong || songId == null) {
        arrangementDialogItem.value = item
        return
    }

    const leaderName = (props.service.worship_leader_name ?? '').trim()
    const arrangements = getArrangements(item)
    const defaultArr = arrangements.find((a) => a.is_default) ?? arrangements[0] ?? null
    const defaultArrId = defaultArr?.id ?? null
    const currentArrId = serviceSong.song_arrangement_id ?? null
    const isUnchanged = currentArrId === null || currentArrId === defaultArrId

    // No leader name OR already has a non-default arrangement -> just open.
    if (!leaderName || !isUnchanged || !defaultArrId) {
        arrangementDialogItem.value = item
        return
    }

    const serviceSongId = serviceSong.id

    // If a leader-named arrangement already exists -> point service-song to it, then open.
    const existing = arrangements.find(
        (a) => (a.name ?? '').trim().toLowerCase() === leaderName.toLowerCase(),
    )
    if (existing) {
        window.axios
            .patch(`/api/service-songs/${serviceSongId}`, { song_arrangement_id: existing.id })
            .catch(() => {})
            .finally(() => {
                router.reload({
                    preserveScroll: true,
                    onSuccess: () => {
                        arrangementDialogItem.value = findAgendaItem(item.id) ?? item
                    },
                })
            })
        return
    }

    // Otherwise clone the default arrangement, reload, point service-song to it, THEN open.
    router.post(
        `/arrangements/${defaultArrId}/clone`,
        { name: leaderName },
        {
            preserveScroll: true,
            onSuccess: () => {
                router.reload({
                    preserveScroll: true,
                    onSuccess: () => {
                        const freshItem = findAgendaItem(item.id) ?? item
                        const freshArrs = getArrangements(freshItem)
                        const created = freshArrs.find(
                            (a) => (a.name ?? '').trim().toLowerCase() === leaderName.toLowerCase(),
                        )
                        if (created) {
                            window.axios
                                .patch(`/api/service-songs/${serviceSongId}`, { song_arrangement_id: created.id })
                                .catch(() => {})
                                .finally(() => {
                                    router.reload({
                                        preserveScroll: true,
                                        onSuccess: () => {
                                            arrangementDialogItem.value = findAgendaItem(item.id) ?? item
                                        },
                                    })
                                })
                        } else {
                            arrangementDialogItem.value = freshItem
                        }
                    },
                })
            },
        },
    )
}

function findAgendaItem(id) {
    return props.agendaItems.find((it) => it.id === id) ?? null
}

function getArrangements(item) {
    const song = item.service_song?.song ?? item.serviceSong?.song
    if (!song?.arrangements) return []

    return song.arrangements.map((arr) => ({
        id: arr.id,
        name: arr.name,
        is_default: arr.is_default,
        groups: (arr.arrangement_groups ?? []).map((ag) => {
            const group = song.groups?.find((g) => g.id === ag.label_id) ?? ag.group ?? {}
            return {
                id: ag.label_id ?? group.id,
                name: group.name ?? 'Unbekannt',
                color: group.color ?? '#6b7280',
                order: ag.order,
                slides: group.slides ?? [],
            }
        }),
    }))
}

function getAvailableGroups(item) {
    const song = item.service_song?.song ?? item.serviceSong?.song
    if (!song?.groups) return []

    return song.groups.map((group) => ({
        id: group.id,
        name: group.name,
        color: group.color,
        slides: group.slides ?? [],
    }))
}

function getSelectedArrangementId(item) {
    return item.service_song?.song_arrangement_id ?? item.serviceSong?.song_arrangement_id ?? null
}

function isHeaderType(item) {
    return item.type?.toLowerCase() === 'header'
}

function onArrangementDialogClosed() {
    arrangementDialogItem.value = null
    router.reload({ preserveScroll: true })
}

/* ── Finalize / Reopen / Download ───────────────────────── */
const toastMessage = ref('')
const toastType = ref('info')
const confirmDialog = ref(false)
const confirmWarnings = ref([])
const finalizing = ref(false)
const downloadAfterFinalize = ref(false)

const isFinalized = computed(() => !!props.service.finalized_at)

function formatDateTime(dateStr) {
    if (!dateStr) return ''
    const d = new Date(dateStr)
    return d.toLocaleDateString('de-DE', {
        day: '2-digit',
        month: '2-digit',
        year: 'numeric',
        hour: '2-digit',
        minute: '2-digit',
    })
}

function showToast(message, type = 'info') {
    toastMessage.value = message
    toastType.value = type
    setTimeout(() => {
        toastMessage.value = ''
    }, 3500)
}

function toastClasses() {
    if (toastType.value === 'success') return 'border-emerald-300 bg-emerald-50 text-emerald-700'
    if (toastType.value === 'warning') return 'border-orange-300 bg-orange-50 text-orange-700'
    return 'border-blue-300 bg-blue-50 text-blue-700'
}

async function finalizeService(andDownload = false) {
    if (andDownload) downloadAfterFinalize.value = true
    finalizing.value = true
    try {
        const response = await fetch(route('services.finalize', props.service.id), {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'Accept': 'application/json',
                'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]')?.content ?? '',
            },
            body: JSON.stringify({ confirmed: false }),
        })
        const data = await response.json()

        if (data.needs_confirmation) {
            confirmWarnings.value = data.warnings
            confirmDialog.value = true
            return
        }

        props.service.finalized_at = new Date().toISOString()
        showToast(data.success, 'success')

        if (downloadAfterFinalize.value) {
            downloadAfterFinalize.value = false
            await downloadService()
        }
    } finally {
        finalizing.value = false
    }
}

async function confirmFinalize() {
    finalizing.value = true
    confirmDialog.value = false
    try {
        const response = await fetch(route('services.finalize', props.service.id), {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'Accept': 'application/json',
                'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]')?.content ?? '',
            },
            body: JSON.stringify({ confirmed: true }),
        })
        const data = await response.json()

        props.service.finalized_at = new Date().toISOString()
        showToast(data.success, 'success')

        if (downloadAfterFinalize.value) {
            downloadAfterFinalize.value = false
            await downloadService()
        }
    } finally {
        finalizing.value = false
        confirmWarnings.value = []
    }
}

function cancelFinalize() {
    confirmDialog.value = false
    confirmWarnings.value = []
    downloadAfterFinalize.value = false
}

async function reopenService() {
    try {
        const response = await fetch(route('services.reopen', props.service.id), {
            method: 'POST',
            headers: {
                'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]')?.content ?? '',
            },
        })
        if (response.ok) {
            props.service.finalized_at = null
            showToast('Service wurde wieder geöffnet.', 'success')
        } else {
            showToast('Fehler beim Öffnen.', 'warning')
        }
    } catch {
        showToast('Fehler beim Öffnen.', 'warning')
    }
}

async function downloadService() {
    try {
        const response = await fetch(route('services.download', props.service.id), {
            headers: {
                'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]')?.content ?? '',
            },
        })

        if (!response.ok) {
            const data = await response.json().catch(() => ({}))
            showToast(data.message || 'Fehler beim Herunterladen.', 'warning')
            return
        }

        const disposition = response.headers.get('content-disposition')
        const filenameMatch = disposition?.match(/filename="?([^"]+)"?/)
        const filename = filenameMatch?.[1] || 'playlist.proplaylist'

        const blob = await response.blob()
        const url = URL.createObjectURL(blob)
        const a = document.createElement('a')
        a.href = url
        a.download = filename
        a.click()
        URL.revokeObjectURL(url)

        showToast('Playlist wurde heruntergeladen.', 'success')
    } catch {
        showToast('Fehler beim Herunterladen.', 'warning')
    }
}

async function downloadPreview() {
    try {
        const response = await fetch(route('services.download-preview', props.service.id), {
            headers: {
                'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]')?.content ?? '',
            },
        })

        if (!response.ok) {
            const data = await response.json().catch(() => ({}))
            showToast(data.message || 'Fehler beim Herunterladen der Vorschau.', 'warning')
            return
        }

        const disposition = response.headers.get('content-disposition')
        const filenameMatch = disposition?.match(/filename="?([^"]+)"?/)
        const filename = filenameMatch?.[1] || 'vorschau.proplaylist'

        const blob = await response.blob()
        const url = URL.createObjectURL(blob)
        const a = document.createElement('a')
        a.href = url
        a.download = filename
        a.click()
        URL.revokeObjectURL(url)

        showToast('Vorschau wurde heruntergeladen.', 'success')
    } catch {
        showToast('Fehler beim Herunterladen der Vorschau.', 'warning')
    }
}
</script>

<template>
    <Head :title="`${service.title} bearbeiten`" />

    <AuthenticatedLayout>
        <template #header>
            <div class="flex items-center gap-3">
                <!-- Back button -->
                <button
                    data-testid="service-edit-back-icon-button"
                    type="button"
                    class="group flex h-8 w-8 shrink-0 items-center justify-center rounded-lg border border-gray-200 bg-white text-gray-400 shadow-sm transition-all hover:border-amber-300 hover:bg-amber-50 hover:text-amber-600"
                    @click="goBack"
                    title="Zurueck zur Uebersicht"
                >
                    <svg class="h-4 w-4 transition-transform group-hover:-translate-x-0.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
                        <path stroke-linecap="round" stroke-linejoin="round" d="M10.5 19.5L3 12m0 0l7.5-7.5M3 12h18" />
                    </svg>
                </button>

                <div class="flex items-center gap-2">
                    <button
                        v-if="prevService"
                        type="button"
                        class="group flex items-center gap-1.5 rounded-lg border border-gray-200 bg-white px-3 py-1.5 text-xs text-gray-600 shadow-sm transition hover:border-amber-300 hover:bg-amber-50"
                        @click="router.get(route('services.edit', prevService.id))"
                        :title="prevService.title"
                    >
                        <svg class="h-3.5 w-3.5 text-gray-400 transition group-hover:text-amber-500 group-hover:-translate-x-0.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
                            <path stroke-linecap="round" stroke-linejoin="round" d="M15.75 19.5L8.25 12l7.5-7.5" />
                        </svg>
                        <div class="text-left">
                            <span class="block max-w-32 truncate leading-tight">{{ prevService.title }}</span>
                            <span class="block text-[10px] text-gray-400 leading-tight">{{ formatShortDate(prevService.date) }}</span>
                        </div>
                    </button>
                </div>

                <!-- Service title -->
                <div class="min-w-0 flex-1">
                    <h2 class="truncate text-xl font-semibold leading-tight text-gray-900">
                        {{ service.title }}
                    </h2>
                    <p class="mt-0.5 text-sm text-gray-500">
                        {{ formattedDate }}
                        <template v-if="service.preacher_name">
                            <span class="mx-1.5 text-gray-300">&middot;</span>
                            <span>{{ service.preacher_name }}</span>
                        </template>
                    </p>
                </div>

                <div class="flex items-center gap-2">
                    <button
                        v-if="nextService"
                        type="button"
                        class="group flex items-center gap-1.5 rounded-lg border border-gray-200 bg-white px-3 py-1.5 text-xs text-gray-600 shadow-sm transition hover:border-amber-300 hover:bg-amber-50"
                        @click="router.get(route('services.edit', nextService.id))"
                        :title="nextService.title"
                    >
                        <div class="text-right">
                            <span class="block max-w-32 truncate leading-tight">{{ nextService.title }}</span>
                            <span class="block text-[10px] text-gray-400 leading-tight">{{ formatShortDate(nextService.date) }}</span>
                        </div>
                        <svg class="h-3.5 w-3.5 text-gray-400 transition group-hover:text-amber-500 group-hover:translate-x-0.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
                            <path stroke-linecap="round" stroke-linejoin="round" d="M8.25 4.5l7.5 7.5-7.5 7.5" />
                        </svg>
                    </button>
                </div>
            </div>
        </template>

        <!-- Keyvisual & Hintergrundbild -->
        <div class="py-4">
            <div class="mx-auto max-w-4xl px-4 sm:px-6 lg:px-8">
                <div class="grid grid-cols-1 gap-4 sm:grid-cols-2">
                    <ServiceImagePanel
                        label="Keyvisual"
                        :current-url="service.key_visual_url"
                        upload-route="services.key-visual.store"
                        :service-id="service.id"
                        :source-name="service.key_visual_is_own ? 'Eigenes Bild' : (service.key_visual_filename ? 'Standard' : null)"
                        testid="keyvisual-panel"
                    />
                    <ServiceImagePanel
                        label="Hintergrundbild"
                        :current-url="service.background_url"
                        upload-route="services.background.store"
                        :service-id="service.id"
                        :source-name="service.background_is_own ? 'Eigenes Bild' : (service.background_filename ? 'Standard' : null)"
                        testid="background-panel"
                    />
                </div>
            </div>
        </div>

        <!-- Name-Überschreibungen (Moderation & Predigt) -->
        <div class="pb-4">
            <div class="mx-auto max-w-4xl px-4 sm:px-6 lg:px-8">
                <div class="grid grid-cols-1 gap-4 sm:grid-cols-2">
                    <div class="rounded-lg border border-gray-200 bg-white p-4 shadow-sm">
                        <label class="mb-1 block text-sm font-semibold text-gray-700" for="moderator_name">
                            Moderation — Name (Überschreiben)
                        </label>
                        <input
                            id="moderator_name"
                            type="text"
                            :value="service.moderator_name ?? ''"
                            class="w-full rounded border border-gray-300 px-3 py-1.5 text-sm focus:border-blue-500 focus:outline-none"
                            placeholder="Aus dem Ablauf ermittelt"
                            data-testid="moderator-name-override"
                            @change="updateNameOverride('moderator_name', $event.target.value)"
                        />
                    </div>
                    <div class="rounded-lg border border-gray-200 bg-white p-4 shadow-sm">
                        <label class="mb-1 block text-sm font-semibold text-gray-700" for="preacher_name_override">
                            Predigt — Name (Überschreiben)
                        </label>
                        <input
                            id="preacher_name_override"
                            type="text"
                            :value="service.preacher_name_override ?? ''"
                            class="w-full rounded border border-gray-300 px-3 py-1.5 text-sm focus:border-blue-500 focus:outline-none"
                            placeholder="Aus ChurchTools übernommen"
                            data-testid="preacher-name-override"
                            @change="updateNameOverride('preacher_name_override', $event.target.value)"
                        />
                    </div>
                </div>
            </div>
        </div>

        <!-- Ablauf (Agenda) -->
        <div class="py-6">
            <div class="mx-auto max-w-4xl px-4 sm:px-6 lg:px-8">
                <div class="mb-4 flex items-center justify-between gap-3">
                    <h3 class="text-base font-semibold text-gray-900">Ablauf</h3>
                    <div class="flex items-center gap-1.5">
                        <template v-for="partType in ['agenda_item', 'moderation', 'sermon', 'song']" :key="partType">
                            <div class="relative">
                                <MacroIcon
                                    :count="macroPartData(partType).count"
                                    :has-warning="macroPartData(partType).has_warning"
                                    :data-testid="'macro-icon-' + partType"
                                    @click="toggleMacroPanel(partType)"
                                />
                                <ServicePartMacroPanel
                                    v-if="openMacroPanel === partType"
                                    :service-id="service.id"
                                    :part-type="partType"
                                    :part-label="macroPartLabels[partType]"
                                    :is-overridden="macroPartData(partType).is_overridden"
                                    :assignments="macroPartData(partType).assignments"
                                    :has-warning="macroPartData(partType).has_warning"
                                    @close="openMacroPanel = null"
                                />
                            </div>
                        </template>
                    </div>
                </div>

                <!-- Empty state -->
                <div v-if="!agendaItems || agendaItems.length === 0"
                     class="rounded-lg border border-dashed border-gray-300 p-8 text-center text-sm text-gray-500">
                    Keine Ablauf-Elemente vorhanden. Bitte synchronisiere die Daten zuerst.
                </div>

                <!-- Song-state legend -->
                <div
                    v-if="agendaItems && agendaItems.length > 0"
                    class="mb-2 flex flex-wrap items-center gap-x-4 gap-y-1 text-xs text-gray-500"
                    data-testid="song-state-legend"
                >
                    <span class="inline-flex items-center gap-1.5">
                        <span class="inline-flex h-2.5 w-2.5 rounded-full bg-red-400"></span>
                        Nicht zugeordnet
                    </span>
                    <span class="inline-flex items-center gap-1.5">
                        <span class="inline-flex h-2.5 w-2.5 rounded-full bg-amber-400"></span>
                        Zu bestätigen
                    </span>
                    <span class="inline-flex items-center gap-1.5">
                        <span class="inline-flex h-2.5 w-2.5 rounded-full bg-emerald-500"></span>
                        Bestätigt
                    </span>
                </div>

                <!-- Agenda table -->
                <table v-if="agendaItems && agendaItems.length > 0" class="w-full text-sm" data-testid="agenda-section">
                    <thead>
                        <tr class="border-b border-gray-200 text-left text-xs font-semibold uppercase tracking-wider text-gray-400">
                            <th class="py-2 pr-3 w-12">Nr</th>
                            <th class="py-2 pr-3 w-20">Zeit</th>
                            <th class="py-2 pr-3 w-20">Dauer</th>
                            <th class="py-2 pr-3">Titel</th>
                            <th class="py-2 pr-3 w-40">Verantwortlich</th>
                            <th class="py-2 w-24"></th>
                        </tr>
                    </thead>
                    <tbody>
                        <template v-for="item in agendaItems" :key="item.id">
                            <!-- Title/header items -->
                            <tr v-if="isHeaderType(item)"
                                class="bg-gray-600"
                                data-testid="agenda-header-item">
                                <td colspan="6" class="px-3 py-1.5">
                                    <h4 class="text-xs font-semibold uppercase tracking-wider text-white">
                                        {{ item.title }}
                                    </h4>
                                </td>
                            </tr>

                            <!-- Song items -->
                            <SongAgendaItem
                                v-else-if="item.service_song_id !== null || item.type === 'Song'"
                                :agenda-item="item"
                                :songs-catalog="songsCatalog"
                                :service-id="service.id"
                                @arrangement-selected="openArrangementDialog(item)"
                                @slides-updated="refreshPage"
                            />

                            <!-- Generic agenda items -->
                            <AgendaItemRow
                                v-else
                                :agenda-item="item"
                                :service-id="service.id"
                                :service-date="service.date"
                                @slides-updated="refreshPage"
                                @scroll-to-info="scrollToInfoBlock"
                            />
                        </template>
                    </tbody>
                </table>
            </div>
        </div>

        <!-- Information Block (below agenda, scrolled to from announcement row) -->
        <div ref="informationBlockRef" class="py-6">
            <div class="mx-auto max-w-4xl px-4 pb-24 sm:px-6 lg:px-8">
                <div class="overflow-hidden rounded-xl border border-gray-200/80 bg-white p-5 shadow-sm">
                    <div class="mb-3 flex items-center gap-3">
                        <div class="flex h-10 w-10 shrink-0 items-center justify-center rounded-xl bg-gradient-to-br from-sky-400 to-blue-500 shadow-sm">
                            <svg class="h-5 w-5 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
                                <path stroke-linecap="round" stroke-linejoin="round" d="M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z" />
                            </svg>
                        </div>
                        <div class="flex-1">
                            <h3 class="text-[15px] font-semibold text-gray-900">Information</h3>
                            <p class="text-xs text-gray-500">Info-Folien für alle kommenden Services</p>
                        </div>
                        <div class="relative">
                            <MacroIcon
                                :count="macroPartData('information').count"
                                :has-warning="macroPartData('information').has_warning"
                                :data-testid="'macro-icon-information'"
                                @click="toggleMacroPanel('information')"
                            />
                            <ServicePartMacroPanel
                                v-if="openMacroPanel === 'information'"
                                :service-id="service.id"
                                :part-type="'information'"
                                :part-label="macroPartLabels.information"
                                :is-overridden="macroPartData('information').is_overridden"
                                :assignments="macroPartData('information').assignments"
                                :has-warning="macroPartData('information').has_warning"
                                @close="openMacroPanel = null"
                            />
                        </div>
                    </div>
                    <InformationBlock
                        :service-id="service.id"
                        :service-date="service.date"
                        :slides="informationSlides"
                        @slides-updated="refreshPage"
                    />
                </div>
            </div>
        </div>

        <!-- Arrangement Dialog -->
        <ArrangementDialog
            v-if="arrangementDialogItem"
            :song-id="arrangementDialogItem.service_song?.song_id ?? arrangementDialogItem.serviceSong?.song_id"
            :arrangements="getArrangements(arrangementDialogItem)"
            :available-groups="getAvailableGroups(arrangementDialogItem)"
            :selected-arrangement-id="getSelectedArrangementId(arrangementDialogItem)"
            :service-song-id="arrangementDialogItem.service_song?.id ?? arrangementDialogItem.serviceSong?.id"
            :service-song-name="(arrangementDialogItem.service_song?.cts_song_name ?? arrangementDialogItem.serviceSong?.cts_song_name) ?? arrangementDialogItem.title ?? ''"
            :service-song-ccli-id="String((arrangementDialogItem.service_song?.cts_ccli_id ?? arrangementDialogItem.serviceSong?.cts_ccli_id) ?? '')"
            :songs-catalog="songsCatalog"
            :worship-leader-name="service.worship_leader_name ?? null"
            :service-song-arrangement-id="arrangementDialogItem.service_song?.song_arrangement_id ?? arrangementDialogItem.serviceSong?.song_arrangement_id ?? null"
            :default-arrangement-id="(getArrangements(arrangementDialogItem).find((a) => a.is_default))?.id ?? null"
            @close="onArrangementDialogClosed"
            @unassigned="onArrangementDialogClosed"
        />

        <!-- Sticky bottom action bar -->
        <div data-testid="service-edit-action-bar" class="fixed bottom-0 left-0 right-0 z-30">
            <div class="border-t border-gray-200 bg-white/90 backdrop-blur-xl shadow-[0_-2px_12px_rgba(0,0,0,0.08)]">
                <div class="mx-auto flex max-w-5xl items-center justify-between gap-4 px-4 py-3.5 sm:px-6 lg:px-8">
                    <!-- Status indicator -->
                    <div class="flex items-center gap-2.5 text-sm">
                        <template v-if="isFinalized">
                            <span class="relative flex h-2.5 w-2.5">
                                <span class="absolute inline-flex h-full w-full animate-ping rounded-full bg-emerald-400 opacity-40"></span>
                                <span class="relative inline-flex h-2.5 w-2.5 rounded-full bg-emerald-500"></span>
                            </span>
                            <span class="font-semibold text-emerald-700">Abgeschlossen</span>
                            <span class="text-xs text-gray-400">{{ formatDateTime(service.finalized_at) }}</span>
                        </template>
                        <template v-else>
                            <span class="inline-flex h-2.5 w-2.5 rounded-full bg-amber-400"></span>
                            <span class="font-semibold text-amber-700">In Bearbeitung</span>
                        </template>
                    </div>

                    <!-- Action buttons -->
                    <div class="flex items-center gap-2.5">
                        <template v-if="isFinalized">
                            <button
                                data-testid="service-edit-reopen-button"
                                type="button"
                                class="inline-flex items-center gap-1.5 rounded-lg border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 shadow-sm transition hover:border-amber-300 hover:bg-amber-50 hover:text-amber-700"
                                @click="reopenService"
                            >
                                <svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
                                    <path stroke-linecap="round" stroke-linejoin="round" d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0l3.181 3.183a8.25 8.25 0 0013.803-3.7M4.031 9.865a8.25 8.25 0 0113.803-3.7l3.181 3.182" />
                                </svg>
                                Wieder öffnen
                            </button>
                            <button
                                data-testid="service-edit-download-button"
                                type="button"
                                class="inline-flex items-center gap-1.5 rounded-lg border border-emerald-200 bg-emerald-600 px-4 py-2 text-sm font-semibold text-white shadow-sm transition hover:bg-emerald-700"
                                @click="downloadService"
                            >
                                <svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
                                    <path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5M16.5 12L12 16.5m0 0L7.5 12m4.5 4.5V3" />
                                </svg>
                                Herunterladen
                            </button>
                        </template>
                        <template v-else>
                            <button
                                data-testid="download-preview-button"
                                type="button"
                                class="inline-flex items-center gap-1.5 rounded-lg border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 shadow-sm transition hover:border-blue-300 hover:bg-blue-50 hover:text-blue-700"
                                @click="downloadPreview"
                            >
                                <svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
                                    <path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5M16.5 12L12 16.5m0 0L7.5 12m4.5 4.5V3" />
                                </svg>
                                Vorschau herunterladen
                            </button>
                            <button
                                data-testid="service-edit-finalize-button"
                                type="button"
                                class="inline-flex items-center gap-1.5 rounded-lg border border-emerald-200 bg-emerald-600 px-4 py-2 text-sm font-semibold text-white shadow-sm transition hover:bg-emerald-700 disabled:cursor-not-allowed disabled:opacity-50"
                                :disabled="finalizing"
                                @click="finalizeService(false)"
                            >
                                <svg v-if="finalizing" class="h-4 w-4 animate-spin" fill="none" viewBox="0 0 24 24">
                                    <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
                                    <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"></path>
                                </svg>
                                <svg v-else class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
                                    <path stroke-linecap="round" stroke-linejoin="round" d="M9 12.75L11.25 15 15 9.75M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
                                </svg>
                                Abschließen
                            </button>
                            <button
                                data-testid="service-edit-finalize-download-button"
                                type="button"
                                class="inline-flex items-center gap-1.5 rounded-lg border border-emerald-200 bg-emerald-600 px-4 py-2 text-sm font-semibold text-white shadow-sm transition hover:bg-emerald-700 disabled:cursor-not-allowed disabled:opacity-50"
                                :disabled="finalizing"
                                @click="finalizeService(true)"
                            >
                                <svg v-if="finalizing" class="h-4 w-4 animate-spin" fill="none" viewBox="0 0 24 24">
                                    <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
                                    <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"></path>
                                </svg>
                                <svg v-else class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
                                    <path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5M16.5 12L12 16.5m0 0L7.5 12m4.5 4.5V3" />
                                </svg>
                                Abschließen &amp; Herunterladen
                            </button>
                        </template>
                    </div>
                </div>
            </div>
        </div>

        <!-- Toast notification -->
        <Teleport to="body">
            <Transition
                enter-active-class="transition duration-300 ease-out"
                enter-from-class="translate-y-2 opacity-0"
                enter-to-class="translate-y-0 opacity-100"
                leave-active-class="transition duration-200 ease-in"
                leave-from-class="translate-y-0 opacity-100"
                leave-to-class="translate-y-2 opacity-0"
            >
                <div
                    v-if="toastMessage"
                    class="fixed bottom-20 left-1/2 z-50 -translate-x-1/2 rounded-lg border px-5 py-3 text-sm font-medium shadow-lg"
                    :class="toastClasses()"
                >
                    {{ toastMessage }}
                </div>
            </Transition>
        </Teleport>

        <!-- Confirmation Dialog -->
        <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
                    v-if="confirmDialog"
                    class="fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4"
                    @click.self="cancelFinalize"
                >
                    <div class="w-full max-w-md rounded-xl bg-white p-6 shadow-xl">
                        <h3 class="text-lg font-semibold text-gray-900">Service abschließen?</h3>
                        <p class="mt-2 text-sm text-gray-600">
                            Es gibt noch offene Punkte. Möchtest du trotzdem abschließen?
                        </p>

                        <ul class="mt-3 space-y-1.5">
                            <li
                                v-for="(warning, idx) in confirmWarnings"
                                :key="idx"
                                class="flex items-start gap-2 text-sm text-amber-700"
                            >
                                <span class="mt-0.5 shrink-0" aria-hidden="true">⚠</span>
                                <span>{{ warning }}</span>
                            </li>
                        </ul>

                        <div class="mt-5 flex justify-end gap-3">
                            <button
                                data-testid="service-edit-confirm-cancel-button"
                                type="button"
                                class="rounded-md border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 transition hover:bg-gray-50"
                                @click="cancelFinalize"
                            >
                                Abbrechen
                            </button>
                            <button
                                data-testid="service-edit-confirm-submit-button"
                                type="button"
                                class="rounded-md border border-emerald-300 bg-emerald-600 px-4 py-2 text-sm font-semibold text-white transition hover:bg-emerald-700"
                                @click="confirmFinalize"
                            >
                                Trotzdem abschließen
                            </button>
                        </div>
                    </div>
                </div>
            </Transition>
        </Teleport>
    </AuthenticatedLayout>
</template>
