package ru.forbion.f7cloud.feature.calendar

import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.BasicTextField
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.AttachFile
import androidx.compose.material.icons.filled.Autorenew
import androidx.compose.material.icons.filled.Check
import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.DateRange
import androidx.compose.material.icons.filled.Edit
import androidx.compose.material.icons.filled.Folder
import androidx.compose.material.icons.filled.InsertDriveFile
import androidx.compose.material.icons.filled.Upload
import androidx.compose.material.icons.filled.KeyboardArrowDown
import androidx.compose.material.icons.filled.Link
import androidx.compose.material.icons.filled.LocalOffer
import androidx.compose.material.icons.filled.Notes
import androidx.compose.material.icons.filled.Notifications
import androidx.compose.material.icons.filled.Place
import androidx.compose.material.icons.filled.Public
import androidx.compose.material.icons.filled.Schedule
import androidx.compose.material.icons.filled.Visibility
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Checkbox
import androidx.compose.material3.CheckboxDefaults
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.RadioButton
import androidx.compose.material3.Surface
import androidx.compose.material3.Switch
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
import ru.forbion.f7cloud.core.designsystem.F7Colors
import ru.forbion.f7cloud.core.designsystem.F7OutlinedField
import ru.forbion.f7cloud.core.designsystem.F7PrimaryButton
import ru.forbion.f7cloud.core.designsystem.F7SecondaryButton
import ru.forbion.f7cloud.core.designsystem.F7TextButton
import java.time.LocalDate
import java.time.YearMonth
import java.time.format.DateTimeFormatter
import java.util.Locale

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun CalendarYearView(
    year: Int,
    selectedDay: java.time.LocalDate,
    events: List<CalendarEventItem>,
    onSelectMonth: (YearMonth) -> Unit,
    modifier: Modifier = Modifier,
) {
    val months = CalendarRepository.yearMonths(year)
    Column(
        modifier = modifier
            .fillMaxWidth()
            .verticalScroll(rememberScrollState()),
        verticalArrangement = Arrangement.spacedBy(8.dp),
    ) {
        months.chunked(3).forEach { row ->
            Row(horizontalArrangement = Arrangement.spacedBy(8.dp), modifier = Modifier.fillMaxWidth()) {
                row.forEach { month ->
                    val count = events.count { event ->
                        val day = java.time.Instant.ofEpochMilli(event.startEpochMilli)
                            .atZone(java.time.ZoneId.systemDefault()).toLocalDate()
                        day.year == month.year && day.month == month.month
                    }
                    Column(
                        modifier = Modifier
                            .weight(1f)
                            .clip(RoundedCornerShape(10.dp))
                            .background(if (month == YearMonth.from(selectedDay)) F7Colors.PrimaryLight else F7Colors.Surface)
                            .clickable { onSelectMonth(month) }
                            .padding(10.dp),
                    ) {
                        Text(month.month.getDisplayName(java.time.format.TextStyle.FULL_STANDALONE, java.util.Locale.forLanguageTag("ru")), style = MaterialTheme.typography.labelLarge, fontWeight = FontWeight.SemiBold)
                        Text("$count событ.", style = MaterialTheme.typography.labelSmall, color = F7Colors.TextSecondary)
                    }
                }
            }
        }
    }
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun CalendarTrashSheet(
    items: List<CalendarTrashItem>,
    onDismiss: () -> Unit,
    onRestore: (CalendarTrashItem) -> Unit,
    onPurge: (CalendarTrashItem) -> Unit,
) {
    val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
    ModalBottomSheet(onDismissRequest = onDismiss, sheetState = sheetState, containerColor = F7Colors.Surface) {
        Column(Modifier.padding(horizontal = 16.dp).padding(bottom = 24.dp)) {
            Text("Корзина", style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.Bold)
            if (items.isEmpty()) Text("Корзина пуста", color = F7Colors.TextSecondary, modifier = Modifier.padding(top = 12.dp))
            items.forEach { item ->
                Column(Modifier.fillMaxWidth().padding(vertical = 8.dp)) {
                    Text(item.summary, fontWeight = FontWeight.SemiBold)
                    Text(item.calendarUri, style = MaterialTheme.typography.labelSmall, color = F7Colors.TextMuted)
                    Row(horizontalArrangement = Arrangement.spacedBy(8.dp), modifier = Modifier.padding(top = 6.dp)) {
                        F7TextButton(text = "Восстановить", onClick = { onRestore(item) })
                        F7TextButton(text = "Удалить навсегда", onClick = { onPurge(item) })
                    }
                }
                HorizontalDivider(color = F7Colors.Border)
            }
        }
    }
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun CalendarTasksSheet(
    tasks: List<CalendarTaskItem>,
    onDismiss: () -> Unit,
) {
    val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
    ModalBottomSheet(onDismissRequest = onDismiss, sheetState = sheetState, containerColor = F7Colors.Surface) {
        Column(Modifier.padding(horizontal = 16.dp).padding(bottom = 24.dp)) {
            Text("Незапланированные задачи", style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.Bold)
            if (tasks.isEmpty()) Text("Нет задач без срока", color = F7Colors.TextSecondary, modifier = Modifier.padding(top = 12.dp))
            tasks.forEach { task ->
                Column(Modifier.padding(vertical = 8.dp)) {
                    Text(task.summary, fontWeight = FontWeight.Medium)
                    Text(task.calendarName, style = MaterialTheme.typography.labelSmall, color = F7Colors.TextMuted)
                }
                HorizontalDivider(color = F7Colors.Border)
            }
        }
    }
}

@Composable
fun CalendarCreateBookDialog(
    draft: CalendarCreateBookDraft,
    saving: Boolean,
    onDismiss: () -> Unit,
    onDraftChange: (CalendarCreateBookDraft) -> Unit,
    onSave: () -> Unit,
) {
    AlertDialog(
        onDismissRequest = { if (!saving) onDismiss() },
        title = { Text("Добавить календарь") },
        text = {
            Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
                CreateBookMode.entries.forEach { mode ->
                    Row(Modifier.fillMaxWidth().clickable { onDraftChange(draft.copy(mode = mode)) }, verticalAlignment = Alignment.CenterVertically) {
                        RadioButton(selected = draft.mode == mode, onClick = { onDraftChange(draft.copy(mode = mode)) })
                        Text(
                            when (mode) {
                                CreateBookMode.NEW -> "Новый календарь"
                                CreateBookMode.WITH_TASKS -> "Календарь со списком задач"
                                CreateBookMode.SUBSCRIBE -> "Подписка по ссылке"
                            },
                            modifier = Modifier.padding(start = 4.dp),
                        )
                    }
                }
                F7OutlinedField(value = draft.name, onValueChange = { onDraftChange(draft.copy(name = it)) }, label = "Название")
                if (draft.mode == CreateBookMode.SUBSCRIBE) {
                    F7OutlinedField(value = draft.subscriptionUrl, onValueChange = { onDraftChange(draft.copy(subscriptionUrl = it)) }, label = "URL подписки (WebCal)")
                }
            }
        },
        confirmButton = { F7PrimaryButton(text = if (saving) "Сохранение…" else "Создать", onClick = onSave, enabled = !saving) },
        dismissButton = { TextButton(onClick = onDismiss) { Text("Отмена") } },
    )
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun CalendarAppSettingsSheet(
    settings: CalendarUserSettings,
    onDismiss: () -> Unit,
    onChange: (CalendarUserSettings) -> Unit,
    onImportClick: () -> Unit,
) {
    val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
    ModalBottomSheet(onDismissRequest = onDismiss, sheetState = sheetState, containerColor = F7Colors.Surface) {
        Column(Modifier.padding(16.dp).verticalScroll(rememberScrollState()), verticalArrangement = Arrangement.spacedBy(10.dp)) {
            Text("Параметры календаря", style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.Bold)
            SettingsSwitch("Показывать выходные", settings.showWeekends) { onChange(settings.copy(showWeekends = it)) }
            SettingsSwitch("Номера недель", settings.showWeekNumbers) { onChange(settings.copy(showWeekNumbers = it)) }
            SettingsSwitch("Показывать задачи", settings.showTasks) { onChange(settings.copy(showTasks = it)) }
            SettingsSwitch("Боковая панель задач", settings.tasksSidebar) { onChange(settings.copy(tasksSidebar = it)) }
            F7OutlinedField(
                value = settings.defaultReminderMinutes.toString(),
                onValueChange = { v -> v.toIntOrNull()?.let { onChange(settings.copy(defaultReminderMinutes = it)) } },
                label = "Напоминание по умолчанию (мин)",
            )
            F7SecondaryButton(text = "Импорт .ics", onClick = onImportClick)
        }
    }
}

@Composable
private fun SettingsSwitch(label: String, checked: Boolean, onChecked: (Boolean) -> Unit) {
    Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically) {
        Text(label)
        Switch(checked = checked, onCheckedChange = onChecked)
    }
}

@Composable
fun CalendarFullEventEditorDialog(
    state: CalendarUiState,
    onDismiss: () -> Unit,
    onDraftChange: (CalendarEventDraft) -> Unit,
    onSave: () -> Unit,
    onDelete: () -> Unit,
    onSearchAttendees: (String) -> Unit,
    onAddAttendee: (CalendarAttendeeSuggestion) -> Unit,
    onRemoveAttendee: (String) -> Unit,
    onSearchLocations: (String) -> Unit,
    onApplyLocation: (CalendarLocationSuggestion) -> Unit,
    onOpenTalkPicker: () -> Unit = {},
    onPickDeviceAttachment: () -> Unit = {},
    onPickFilesAttachment: () -> Unit = {},
    onRemoveAttachment: (String) -> Unit = {},
    onOpenFreeBusy: () -> Unit = {},
) {
    val draft = state.eventDraft
    val isEdit = state.editorMode == CalendarEditorMode.EDIT
    val context = LocalContext.current
    val dateFmt = remember { DateTimeFormatter.ofPattern("d MMM yyyy", Locale.forLanguageTag("ru")) }
    val selectedCalendar = state.calendars.firstOrNull { it.href == draft.calendarHref }
        ?: state.calendars.firstOrNull { it.visible }

    fun pickDate(current: LocalDate, onPick: (LocalDate) -> Unit) {
        android.app.DatePickerDialog(
            context,
            { _, y, m, d -> onPick(LocalDate.of(y, m + 1, d)) },
            current.year, current.monthValue - 1, current.dayOfMonth,
        ).show()
    }
    fun pickTime(current: String, onPick: (String) -> Unit) {
        val parts = current.split(":")
        val h = parts.getOrNull(0)?.toIntOrNull() ?: 10
        val mi = parts.getOrNull(1)?.toIntOrNull() ?: 0
        android.app.TimePickerDialog(
            context,
            { _, hh, mm -> onPick("%02d:%02d".format(hh, mm)) },
            h, mi, true,
        ).show()
    }

    // Discard-диалог: закрытие с несохранёнными изменениями требует подтверждения
    // (_calendar-discard-dialog-mobile.css). Исходник фиксируем на открытии окна.
    val initialDraft = remember { draft }
    var discardConfirm by remember { mutableStateOf(false) }
    val requestClose: () -> Unit = {
        if (!state.saving && !state.deleting) {
            if (draft != initialDraft) discardConfirm = true else onDismiss()
        }
    }
    if (discardConfirm) {
        AlertDialog(
            onDismissRequest = { discardConfirm = false },
            title = { Text("Отменить изменения?") },
            text = { Text("Внесённые изменения не будут сохранены.") },
            confirmButton = {
                TextButton(onClick = { discardConfirm = false; onDismiss() }) {
                    Text("Отменить изменения", color = F7Colors.Error)
                }
            },
            dismissButton = {
                TextButton(onClick = { discardConfirm = false }) {
                    Text("Продолжить редактирование", color = F7Colors.TextPrimary)
                }
            },
        )
    }

    Dialog(
        onDismissRequest = requestClose,
        properties = DialogProperties(usePlatformDefaultWidth = false),
    ) {
        Surface(
            shape = RoundedCornerShape(16.dp),
            color = Color.White,
            modifier = Modifier.fillMaxWidth(0.94f).fillMaxHeight(0.94f),
        ) {
            Column(Modifier.padding(horizontal = 16.dp, vertical = 14.dp)) {
                // Шапка: заголовок + крестик
                Row(
                    Modifier.fillMaxWidth(),
                    horizontalArrangement = Arrangement.SpaceBetween,
                    verticalAlignment = Alignment.CenterVertically,
                ) {
                    Text(
                        if (isEdit) "Редактировать событие" else "Создать событие",
                        style = MaterialTheme.typography.titleLarge,
                        fontWeight = FontWeight.Bold,
                        color = F7Colors.TextPrimary,
                    )
                    IconButton(onClick = requestClose, modifier = Modifier.size(28.dp)) {
                        Icon(Icons.Default.Close, contentDescription = "Закрыть", tint = F7Colors.TextSecondary)
                    }
                }
                Spacer(Modifier.height(12.dp))

                Column(
                    Modifier.weight(1f).verticalScroll(rememberScrollState()),
                    verticalArrangement = Arrangement.spacedBy(12.dp),
                ) {
                    // Название + зелёная галочка-сохранение
                    Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(10.dp)) {
                        EventPill(icon = null, modifier = Modifier.weight(1f)) {
                            EventInput(
                                value = draft.title,
                                onValueChange = { onDraftChange(draft.copy(title = it)) },
                                placeholder = "Название",
                                modifier = Modifier.weight(1f),
                            )
                        }
                        EventSaveButton(enabled = !state.saving, onClick = onSave)
                    }

                    // Начало
                    EventFieldLabel("Начало")
                    Row(horizontalArrangement = Arrangement.spacedBy(10.dp)) {
                        EventPill(icon = Icons.Default.DateRange, modifier = Modifier.weight(1f), onClick = {
                            pickDate(draft.date) { picked ->
                                // endDate не может быть раньше начала; равенство = однодневное (null)
                                val newEnd = draft.endDate?.coerceAtLeast(picked)?.takeIf { it != picked }
                                onDraftChange(draft.copy(date = picked, endDate = newEnd))
                            }
                        }) {
                            Text(draft.date.format(dateFmt), color = EVENT_TEXT, fontSize = 14.sp)
                        }
                        if (!draft.allDay) {
                            EventPill(icon = Icons.Default.Schedule, modifier = Modifier.weight(1f), onClick = { pickTime(draft.startTime) { onDraftChange(draft.copy(startTime = it)) } }) {
                                Text(draft.startTime, color = EVENT_TEXT, fontSize = 14.sp)
                            }
                        }
                    }

                    // Окончание (дата может отличаться от начала — многодневные события)
                    EventFieldLabel("Окончание")
                    Row(horizontalArrangement = Arrangement.spacedBy(10.dp)) {
                        val endDay = (draft.endDate ?: draft.date).coerceAtLeast(draft.date)
                        EventPill(icon = Icons.Default.DateRange, modifier = Modifier.weight(1f), onClick = {
                            pickDate(endDay) { picked ->
                                onDraftChange(draft.copy(endDate = picked.coerceAtLeast(draft.date).takeIf { it != draft.date }))
                            }
                        }) {
                            Text(endDay.format(dateFmt), color = EVENT_TEXT, fontSize = 14.sp)
                        }
                        if (!draft.allDay) {
                            EventPill(icon = Icons.Default.Schedule, modifier = Modifier.weight(1f), onClick = { pickTime(draft.endTime) { onDraftChange(draft.copy(endTime = it)) } }) {
                                Text(draft.endTime, color = EVENT_TEXT, fontSize = 14.sp)
                            }
                        }
                    }

                    // Таймзона (инфо)
                    EventPill(icon = Icons.Default.Public) {
                        Text(java.time.ZoneId.systemDefault().id, color = EVENT_TEXT, fontSize = 14.sp)
                    }

                    // Повторение: пресеты + «Настроить…» (кастомный RRULE в модалке как на сайте)
                    var repeatModalOpen by remember { mutableStateOf(false) }
                    EventSelectPill(
                        icon = Icons.Default.Autorenew,
                        label = when {
                            draft.customRrule.isNotBlank() -> RecurrenceRule.describe(draft.customRrule)
                            draft.recurrence == RecurrencePreset.NONE -> "Не повторять"
                            else -> draft.recurrence.label
                        },
                        trailing = Icons.Default.Edit,
                        options = RecurrencePreset.entries.map { p ->
                            p.label to { onDraftChange(draft.copy(recurrence = p, customRrule = "")) }
                        } + ("Настроить…" to { repeatModalOpen = true }),
                    )
                    if (repeatModalOpen) {
                        CalendarRepeatModal(
                            initial = RecurrenceRule.parse(draft.customRrule.ifBlank { draft.recurrence.rrule })
                                ?: RecurrenceRule(byDays = setOf(RecurrenceRule.ICS_DAYS[draft.date.dayOfWeek.value - 1])),
                            onDismiss = { repeatModalOpen = false },
                            onApply = { rule ->
                                onDraftChange(draft.copy(recurrence = RecurrencePreset.NONE, customRrule = rule.toRrule()))
                                repeatModalOpen = false
                            },
                            onClear = {
                                onDraftChange(draft.copy(recurrence = RecurrencePreset.NONE, customRrule = ""))
                                repeatModalOpen = false
                            },
                        )
                    }

                    // Весь день
                    Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.clickable { onDraftChange(draft.copy(allDay = !draft.allDay)) }) {
                        Checkbox(
                            checked = draft.allDay,
                            onCheckedChange = { onDraftChange(draft.copy(allDay = it)) },
                            colors = CheckboxDefaults.colors(checkedColor = F7Colors.Primary),
                        )
                        Text("Весь день", color = F7Colors.TextPrimary, fontSize = 14.sp)
                    }

                    // Календарь
                    if (state.calendars.isNotEmpty()) {
                        EventCalendarPill(
                            calendarName = selectedCalendar?.displayName ?: "Календарь",
                            colorHex = selectedCalendar?.color,
                            options = state.calendars.filter { it.visible },
                            onSelect = { onDraftChange(draft.copy(calendarHref = it.href)) },
                        )
                    }

                    // Описание
                    EventPill(icon = Icons.Default.Notes, minHeight = 120.dp, iconTop = true) {
                        EventInput(
                            value = draft.description,
                            onValueChange = { onDraftChange(draft.copy(description = it)) },
                            placeholder = "Добавьте описание",
                            singleLine = false,
                            modifier = Modifier.fillMaxWidth(),
                        )
                    }

                    // Местоположение + добавить Talk-комнату (зелёный +)
                    Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(10.dp)) {
                        EventPill(icon = Icons.Default.Place, modifier = Modifier.weight(1f)) {
                            EventInput(
                                value = draft.location,
                                onValueChange = { onSearchLocations(it) },
                                placeholder = "Добавить местоположение",
                                modifier = Modifier.weight(1f),
                            )
                        }
                        EventRoundButton(
                            icon = Icons.Default.Add,
                            active = draft.talkRoomUrl.isNotBlank(),
                            onClick = onOpenTalkPicker,
                        )
                    }
                    if (draft.talkRoomUrl.isNotBlank()) {
                        Text(
                            "Беседа Talk прикреплена",
                            modifier = Modifier.padding(start = 8.dp),
                            color = F7Colors.Primary,
                            fontSize = 13.sp,
                        )
                    }
                    state.locationSuggestions.take(4).forEach { s ->
                        Text(
                            s.address.ifBlank { s.name },
                            modifier = Modifier.clickable { onApplyLocation(s) }.padding(start = 8.dp),
                            color = F7Colors.Primary,
                            fontSize = 13.sp,
                        )
                    }

                    // Напоминания: несколько, добавление из пресетов, удаление крестиком
                    EventSelectPill(
                        icon = Icons.Default.Notifications,
                        label = if (draft.reminders.isEmpty()) "Добавить напоминание" else "Напоминаний: ${draft.reminders.size}",
                        trailing = Icons.Default.KeyboardArrowDown,
                        options = REMINDER_PRESETS
                            .filter { (min, _) -> min !in draft.reminders }
                            .map { (min, lbl) -> lbl to { onDraftChange(draft.copy(reminders = (draft.reminders + min).sorted())) } },
                    )
                    draft.reminders.forEach { min ->
                        Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(start = 4.dp)) {
                            Icon(Icons.Default.Notifications, contentDescription = null, tint = EVENT_PLACEHOLDER, modifier = Modifier.size(16.dp))
                            Spacer(Modifier.width(8.dp))
                            Text(reminderLabelFor(min), color = F7Colors.TextPrimary, fontSize = 13.sp, modifier = Modifier.weight(1f))
                            IconButton(onClick = { onDraftChange(draft.copy(reminders = draft.reminders - min)) }, modifier = Modifier.size(24.dp)) {
                                Icon(Icons.Default.Close, contentDescription = "Удалить напоминание", tint = F7Colors.TextSecondary, modifier = Modifier.size(16.dp))
                            }
                        }
                    }

                    // Вложения: меню «Из файлов / Загрузить с устройства» + список с удалением
                    var attachMenu by remember { mutableStateOf(false) }
                    Box {
                        EventPill(icon = Icons.Default.AttachFile, onClick = { attachMenu = true }) {
                            Text(
                                if (draft.attachments.isEmpty()) "Нет ни одного вложения" else "Вложений: ${draft.attachments.size}",
                                color = EVENT_TEXT, fontSize = 14.sp, modifier = Modifier.weight(1f),
                            )
                            if (state.attachmentUploading) {
                                Text("Загрузка…", color = EVENT_PLACEHOLDER, fontSize = 12.sp)
                            } else {
                                Icon(Icons.Default.Add, contentDescription = "Добавить вложение", tint = EVENT_PLACEHOLDER, modifier = Modifier.size(18.dp))
                            }
                        }
                        DropdownMenu(expanded = attachMenu, onDismissRequest = { attachMenu = false }) {
                            DropdownMenuItem(
                                leadingIcon = { Icon(Icons.Default.Folder, contentDescription = null) },
                                text = { Text("Добавить из файлов") },
                                onClick = { attachMenu = false; onPickFilesAttachment() },
                            )
                            DropdownMenuItem(
                                leadingIcon = { Icon(Icons.Default.Upload, contentDescription = null) },
                                text = { Text("Загрузить с устройства") },
                                onClick = { attachMenu = false; onPickDeviceAttachment() },
                            )
                        }
                    }
                    draft.attachments.forEach { att ->
                        Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(start = 4.dp)) {
                            Icon(Icons.Default.InsertDriveFile, contentDescription = null, tint = EVENT_PLACEHOLDER, modifier = Modifier.size(16.dp))
                            Spacer(Modifier.width(8.dp))
                            Text(att.fileName.ifBlank { att.url.substringAfterLast('/') }, color = F7Colors.TextPrimary, fontSize = 13.sp, maxLines = 1, overflow = TextOverflow.Ellipsis, modifier = Modifier.weight(1f))
                            IconButton(onClick = { onRemoveAttachment(att.url) }, modifier = Modifier.size(24.dp)) {
                                Icon(Icons.Default.Close, contentDescription = "Удалить", tint = F7Colors.TextSecondary, modifier = Modifier.size(16.dp))
                            }
                        }
                    }

                    // Статус
                    EventSelectPill(
                        icon = Icons.Default.Check,
                        label = draft.status.label,
                        trailing = Icons.Default.KeyboardArrowDown,
                        options = EventStatus.entries.map { st -> st.label to { onDraftChange(draft.copy(status = st)) } },
                    )

                    // Видимость
                    EventSelectPill(
                        icon = Icons.Default.Visibility,
                        label = draft.classification.label,
                        trailing = Icons.Default.KeyboardArrowDown,
                        options = EventClassification.entries.map { cl -> cl.label to { onDraftChange(draft.copy(classification = cl)) } },
                    )

                    // Категории
                    EventPill(icon = Icons.Default.LocalOffer) {
                        EventInput(
                            value = draft.categories,
                            onValueChange = { onDraftChange(draft.copy(categories = it)) },
                            placeholder = "Категории",
                            modifier = Modifier.weight(1f),
                        )
                    }

                    // Участники
                    EventPill(icon = Icons.Default.Add) {
                        EventInput(
                            value = draft.attendeeQuery,
                            onValueChange = onSearchAttendees,
                            placeholder = "Добавить участника",
                            modifier = Modifier.weight(1f),
                        )
                    }
                    state.attendeeSuggestions.take(5).forEach { s ->
                        Text(
                            "${s.name} · ${s.email}",
                            modifier = Modifier.clickable { onAddAttendee(s) }.padding(start = 8.dp),
                            color = F7Colors.Primary,
                            fontSize = 13.sp,
                        )
                    }
                    draft.attendees.forEach { a ->
                        Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically) {
                            Text(a.displayName.ifBlank { a.email }, color = F7Colors.TextPrimary, fontSize = 14.sp)
                            F7TextButton(text = "✕", onClick = { onRemoveAttendee(a.email) })
                        }
                    }
                    if (draft.attendees.isNotEmpty()) {
                        TextButton(onClick = onOpenFreeBusy) {
                            Text("Показать занятость участников", color = F7Colors.Primary, fontSize = 13.sp)
                        }
                    }
                }

                // Футер
                Spacer(Modifier.height(12.dp))
                Row(
                    Modifier.fillMaxWidth(),
                    horizontalArrangement = Arrangement.End,
                    verticalAlignment = Alignment.CenterVertically,
                ) {
                    if (isEdit) {
                        TextButton(onClick = onDelete, enabled = !state.deleting) {
                            Text(if (state.deleting) "Удаление…" else "Удалить", color = F7Colors.Error)
                        }
                        Spacer(Modifier.width(4.dp))
                    }
                    TextButton(onClick = requestClose, enabled = !state.saving) {
                        Text("Отмена", color = F7Colors.TextSecondary)
                    }
                    Spacer(Modifier.width(8.dp))
                    F7PrimaryButton(
                        text = if (state.saving) "Сохранение…" else "Сохранить",
                        onClick = onSave,
                        enabled = !state.saving,
                    )
                }
            }
        }
    }
}

// --- Токены и вспомогательные композаблы редактора события (см. _calendar-edit-full-fields.css) ---
private val EVENT_FIELD_BG = Color(0xFFFBFBFB)
private val EVENT_FIELD_BORDER = Color(0xFFE6E6E6)
private val EVENT_TEXT = Color(0xFF151515)
private val EVENT_PLACEHOLDER = Color(0xFF808080)

private val REMINDER_PRESETS = listOf(
    0 to "во время начала события",
    5 to "за 5 минут",
    10 to "за 10 минут",
    15 to "за 15 минут",
    30 to "за 30 минут",
    60 to "за 1 час",
    1440 to "за 1 день",
)

private fun reminderLabelFor(min: Int): String =
    REMINDER_PRESETS.firstOrNull { it.first == min }?.second ?: "за $min мин"

@Composable
private fun EventFieldLabel(text: String) {
    Text(text, color = F7Colors.TextPrimary, fontSize = 15.sp, fontWeight = FontWeight.SemiBold)
}

@Composable
private fun EventPill(
    icon: ImageVector?,
    modifier: Modifier = Modifier,
    minHeight: androidx.compose.ui.unit.Dp = 40.dp,
    iconTop: Boolean = false,
    onClick: (() -> Unit)? = null,
    content: @Composable RowScope.() -> Unit,
) {
    Row(
        modifier = modifier
            .fillMaxWidth()
            .heightIn(min = minHeight)
            .clip(RoundedCornerShape(8.dp))
            .background(EVENT_FIELD_BG)
            .border(1.dp, EVENT_FIELD_BORDER, RoundedCornerShape(8.dp))
            .then(if (onClick != null) Modifier.clickable { onClick() } else Modifier)
            .padding(horizontal = 12.dp, vertical = if (minHeight > 40.dp) 12.dp else 0.dp),
        verticalAlignment = if (iconTop) Alignment.Top else Alignment.CenterVertically,
    ) {
        if (icon != null) {
            Icon(
                icon,
                contentDescription = null,
                tint = EVENT_PLACEHOLDER,
                modifier = Modifier.size(16.dp).then(if (iconTop) Modifier.padding(top = 2.dp) else Modifier),
            )
            Spacer(Modifier.width(12.dp))
        }
        content()
    }
}

@Composable
private fun EventInput(
    value: String,
    onValueChange: (String) -> Unit,
    placeholder: String,
    modifier: Modifier = Modifier,
    singleLine: Boolean = true,
) {
    BasicTextField(
        value = value,
        onValueChange = onValueChange,
        singleLine = singleLine,
        textStyle = TextStyle(color = EVENT_TEXT, fontSize = 14.sp, lineHeight = 20.sp, fontWeight = FontWeight.Medium),
        cursorBrush = SolidColor(F7Colors.Primary),
        modifier = modifier,
        decorationBox = { inner ->
            Box {
                if (value.isEmpty()) {
                    Text(placeholder, color = EVENT_PLACEHOLDER, fontSize = 14.sp, lineHeight = 20.sp)
                }
                inner()
            }
        },
    )
}

@Composable
private fun EventSelectPill(
    icon: ImageVector,
    label: String,
    trailing: ImageVector,
    options: List<Pair<String, () -> Unit>>,
) {
    var expanded by remember { mutableStateOf(false) }
    Box {
        EventPill(icon = icon, onClick = { expanded = true }) {
            Text(label, color = EVENT_TEXT, fontSize = 14.sp, maxLines = 1, overflow = TextOverflow.Ellipsis, modifier = Modifier.weight(1f))
            Icon(trailing, contentDescription = null, tint = EVENT_PLACEHOLDER, modifier = Modifier.size(16.dp))
        }
        DropdownMenu(expanded = expanded, onDismissRequest = { expanded = false }) {
            options.forEach { (text, action) ->
                DropdownMenuItem(text = { Text(text) }, onClick = { action(); expanded = false })
            }
        }
    }
}

@Composable
private fun EventCalendarPill(
    calendarName: String,
    colorHex: String?,
    options: List<CalendarBookItem>,
    onSelect: (CalendarBookItem) -> Unit,
) {
    var expanded by remember { mutableStateOf(false) }
    val dotColor = parseCalendarColor(colorHex)
    Box {
        EventPill(icon = null, onClick = { expanded = true }) {
            Box(Modifier.size(12.dp).clip(CircleShape).background(dotColor))
            Spacer(Modifier.width(12.dp))
            Text(calendarName, color = EVENT_TEXT, fontSize = 14.sp, maxLines = 1, overflow = TextOverflow.Ellipsis, modifier = Modifier.weight(1f))
            Box(Modifier.size(24.dp).clip(CircleShape).background(F7Colors.Primary), contentAlignment = Alignment.Center) {
                Icon(Icons.Default.Edit, contentDescription = null, tint = Color.White, modifier = Modifier.size(13.dp))
            }
        }
        DropdownMenu(expanded = expanded, onDismissRequest = { expanded = false }) {
            options.forEach { cal ->
                DropdownMenuItem(
                    text = {
                        Row(verticalAlignment = Alignment.CenterVertically) {
                            Box(Modifier.size(10.dp).clip(CircleShape).background(parseCalendarColor(cal.color)))
                            Spacer(Modifier.width(8.dp))
                            Text(cal.displayName)
                        }
                    },
                    onClick = { onSelect(cal); expanded = false },
                )
            }
        }
    }
}

@Composable
private fun EventSaveButton(enabled: Boolean, onClick: () -> Unit) {
    Box(
        Modifier
            .size(40.dp)
            .clip(CircleShape)
            .background(if (enabled) F7Colors.Primary else F7Colors.Border)
            .clickable(enabled = enabled) { onClick() },
        contentAlignment = Alignment.Center,
    ) {
        Icon(Icons.Default.Check, contentDescription = "Сохранить", tint = Color.White, modifier = Modifier.size(20.dp))
    }
}

@Composable
private fun EventRoundButton(icon: ImageVector, active: Boolean, onClick: () -> Unit) {
    Box(
        Modifier
            .size(40.dp)
            .clip(CircleShape)
            .background(if (active) F7Colors.Primary else F7Colors.PrimaryGradientStart)
            .clickable { onClick() },
        contentAlignment = Alignment.Center,
    ) {
        Icon(icon, contentDescription = null, tint = Color.White, modifier = Modifier.size(20.dp))
    }
}

private fun parseCalendarColor(hex: String?): Color {
    val raw = hex?.trim()?.removePrefix("#") ?: return Color(0xFF0082C9)
    return runCatching {
        val v = when (raw.length) {
            6 -> raw.toLong(16) or 0xFF000000
            8 -> raw.toLong(16)
            3 -> {
                val r = raw[0]; val g = raw[1]; val b = raw[2]
                "$r$r$g$g$b$b".toLong(16) or 0xFF000000
            }
            else -> return Color(0xFF0082C9)
        }
        Color(v)
    }.getOrDefault(Color(0xFF0082C9))
}

/**
 * Выбор беседы Talk для события (кнопка «+» у поля местоположения). Как на вебе:
 * список существующих бесед + создание публичной/приватной.
 */
@Composable
fun CalendarTalkPickerDialog(
    state: CalendarUiState,
    onDismiss: () -> Unit,
    onSelect: (CalendarTalkRoom) -> Unit,
    onCreate: (Int) -> Unit,
) {
    Dialog(onDismissRequest = onDismiss, properties = DialogProperties(usePlatformDefaultWidth = false)) {
        Surface(
            shape = RoundedCornerShape(16.dp),
            color = Color.White,
            modifier = Modifier.fillMaxWidth(0.94f).fillMaxHeight(0.9f),
        ) {
            Column(Modifier.padding(horizontal = 16.dp, vertical = 14.dp)) {
                Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically) {
                    Text("Выберите беседу", style = MaterialTheme.typography.titleLarge, fontWeight = FontWeight.Bold, color = F7Colors.TextPrimary)
                    IconButton(onClick = onDismiss, modifier = Modifier.size(28.dp)) {
                        Icon(Icons.Default.Close, contentDescription = "Закрыть", tint = F7Colors.TextSecondary)
                    }
                }
                Spacer(Modifier.height(8.dp))
                Column(Modifier.weight(1f).verticalScroll(rememberScrollState()), verticalArrangement = Arrangement.spacedBy(2.dp)) {
                    when {
                        state.talkPickerLoading -> Text("Загрузка…", color = F7Colors.TextSecondary, fontSize = 14.sp, modifier = Modifier.padding(vertical = 12.dp))
                        state.talkRooms.isEmpty() -> Text("Нет доступных бесед", color = F7Colors.TextSecondary, fontSize = 14.sp, modifier = Modifier.padding(vertical = 12.dp))
                        else -> state.talkRooms.forEach { room ->
                            Row(
                                Modifier.fillMaxWidth().clickable { onSelect(room) }.padding(vertical = 12.dp),
                                verticalAlignment = Alignment.CenterVertically,
                            ) {
                                Box(Modifier.size(32.dp).clip(CircleShape).background(F7Colors.PrimaryLight), contentAlignment = Alignment.Center) {
                                    Icon(Icons.Default.Link, contentDescription = null, tint = F7Colors.Primary, modifier = Modifier.size(18.dp))
                                }
                                Spacer(Modifier.width(12.dp))
                                Text(room.displayName, color = F7Colors.TextPrimary, fontSize = 15.sp, maxLines = 1, overflow = TextOverflow.Ellipsis)
                            }
                            HorizontalDivider(color = F7Colors.BorderLight)
                        }
                    }
                }
                Spacer(Modifier.height(12.dp))
                Text("Или создать новую беседу", color = F7Colors.TextPrimary, fontSize = 14.sp, fontWeight = FontWeight.SemiBold)
                Spacer(Modifier.height(8.dp))
                TalkCreateRow("Создать публичную беседу", enabled = !state.talkPickerLoading) { onCreate(3) }
                Spacer(Modifier.height(8.dp))
                TalkCreateRow("Создать приватную беседу", enabled = !state.talkPickerLoading) { onCreate(2) }
            }
        }
    }
}

@Composable
private fun TalkCreateRow(label: String, enabled: Boolean, onClick: () -> Unit) {
    Row(
        Modifier
            .fillMaxWidth()
            .heightIn(min = 44.dp)
            .clip(RoundedCornerShape(8.dp))
            .background(F7Colors.PrimaryLight)
            .clickable(enabled = enabled) { onClick() }
            .padding(horizontal = 14.dp),
        horizontalArrangement = Arrangement.SpaceBetween,
        verticalAlignment = Alignment.CenterVertically,
    ) {
        Text(label, color = F7Colors.TextPrimary, fontSize = 14.sp)
        Icon(Icons.Default.Add, contentDescription = null, tint = F7Colors.Primary, modifier = Modifier.size(18.dp))
    }
}

/** Занятость участников на день события (free/busy): интервалы занятости, конфликт — красным. */
@Composable
fun CalendarFreeBusyDialog(
    state: CalendarUiState,
    onDismiss: () -> Unit,
) {
    val draft = state.eventDraft
    val zone = java.time.ZoneId.systemDefault()
    val timeFmt = remember { DateTimeFormatter.ofPattern("HH:mm") }
    // Окно события для подсветки конфликтов
    val eventStart = remember(draft) {
        if (draft.allDay) draft.date.atStartOfDay(zone).toInstant().toEpochMilli()
        else draft.date.atTime(
            draft.startTime.substringBefore(':').toIntOrNull() ?: 10,
            draft.startTime.substringAfter(':').toIntOrNull() ?: 0,
        ).atZone(zone).toInstant().toEpochMilli()
    }
    val eventEnd = remember(draft) {
        val endDay = (draft.endDate ?: draft.date).coerceAtLeast(draft.date)
        if (draft.allDay) endDay.plusDays(1).atStartOfDay(zone).toInstant().toEpochMilli()
        else endDay.atTime(
            draft.endTime.substringBefore(':').toIntOrNull() ?: 11,
            draft.endTime.substringAfter(':').toIntOrNull() ?: 0,
        ).atZone(zone).toInstant().toEpochMilli()
    }

    Dialog(onDismissRequest = onDismiss, properties = DialogProperties(usePlatformDefaultWidth = false)) {
        Surface(
            shape = RoundedCornerShape(16.dp),
            color = Color.White,
            modifier = Modifier.fillMaxWidth(0.94f),
        ) {
            Column(
                Modifier.padding(horizontal = 16.dp, vertical = 14.dp).verticalScroll(rememberScrollState()),
                verticalArrangement = Arrangement.spacedBy(12.dp),
            ) {
                Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically) {
                    Text("Занятость участников", style = MaterialTheme.typography.titleLarge, fontWeight = FontWeight.Bold, color = F7Colors.TextPrimary)
                    IconButton(onClick = onDismiss, modifier = Modifier.size(28.dp)) {
                        Icon(Icons.Default.Close, contentDescription = "Закрыть", tint = F7Colors.TextSecondary)
                    }
                }
                Text(
                    draft.date.format(DateTimeFormatter.ofPattern("d MMMM yyyy", Locale.forLanguageTag("ru"))),
                    color = F7Colors.TextSecondary, fontSize = 13.sp,
                )
                when {
                    state.freeBusyLoading -> Text("Загрузка…", color = F7Colors.TextSecondary, fontSize = 14.sp)
                    state.freeBusyError != null -> Text(state.freeBusyError, color = F7Colors.Error, fontSize = 14.sp)
                    else -> draft.attendees.forEach { attendee ->
                        val busy = state.freeBusyResult[attendee.email].orEmpty()
                        val conflict = busy.any { it.startEpochMilli < eventEnd && it.endEpochMilli > eventStart }
                        Column(Modifier.fillMaxWidth()) {
                            Text(
                                attendee.displayName.ifBlank { attendee.email },
                                color = F7Colors.TextPrimary, fontSize = 14.sp, fontWeight = FontWeight.SemiBold,
                            )
                            if (busy.isEmpty()) {
                                Text("Свободен весь день", color = F7Colors.Primary, fontSize = 13.sp)
                            } else {
                                busy.forEach { p ->
                                    val overlaps = p.startEpochMilli < eventEnd && p.endEpochMilli > eventStart
                                    val s = java.time.Instant.ofEpochMilli(p.startEpochMilli).atZone(zone)
                                    val e = java.time.Instant.ofEpochMilli(p.endEpochMilli).atZone(zone)
                                    Text(
                                        "Занят ${s.format(timeFmt)}–${e.format(timeFmt)}",
                                        color = if (overlaps) F7Colors.Error else F7Colors.TextSecondary,
                                        fontSize = 13.sp,
                                    )
                                }
                            }
                            if (conflict) {
                                Text("⚠ Конфликт со временем события", color = F7Colors.Error, fontSize = 12.sp)
                            }
                        }
                        HorizontalDivider(color = F7Colors.BorderLight)
                    }
                }
            }
        }
    }
}

/** Окно управления календарём: имя, цвет, шаринг, удаление (по _calendar-edit-calendar-modal-mobile.css). */
@Composable
fun CalendarEditBookDialog(
    state: CalendarUiState,
    onDismiss: () -> Unit,
    onSave: (String, String?) -> Unit,
    onDelete: () -> Unit,
    onSearchSharees: (String) -> Unit,
    onAddSharee: (CalendarShareeSuggestion, Boolean) -> Unit,
    onRemoveSharee: (String) -> Unit,
) {
    val target = state.editCalendarTarget ?: return
    var name by remember(target.href) { mutableStateOf(target.displayName) }
    var color by remember(target.href) { mutableStateOf(target.color) }
    var shareQuery by remember(target.href) { mutableStateOf("") }
    var confirmDelete by remember(target.href) { mutableStateOf(false) }

    Dialog(onDismissRequest = onDismiss, properties = DialogProperties(usePlatformDefaultWidth = false)) {
        Surface(
            shape = RoundedCornerShape(16.dp),
            color = Color.White,
            modifier = Modifier.fillMaxWidth(0.94f),
        ) {
            Column(
                Modifier.padding(horizontal = 16.dp, vertical = 14.dp).verticalScroll(rememberScrollState()),
                verticalArrangement = Arrangement.spacedBy(12.dp),
            ) {
                Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically) {
                    Text("Настройки календаря", style = MaterialTheme.typography.titleLarge, fontWeight = FontWeight.Bold, color = F7Colors.TextPrimary)
                    IconButton(onClick = onDismiss, modifier = Modifier.size(28.dp)) {
                        Icon(Icons.Default.Close, contentDescription = "Закрыть", tint = F7Colors.TextSecondary)
                    }
                }

                EventFieldLabel("Название")
                EventPill(icon = null) {
                    EventInput(value = name, onValueChange = { name = it }, placeholder = "Название календаря", modifier = Modifier.weight(1f))
                }

                EventFieldLabel("Цвет")
                Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(8.dp)) {
                    CALENDAR_PALETTE.forEach { hex ->
                        val selected = color?.equals(hex, ignoreCase = true) == true
                        Box(
                            Modifier
                                .weight(1f)
                                .height(36.dp)
                                .clip(CircleShape)
                                .background(parseCalendarColor(hex))
                                .then(if (selected) Modifier.border(3.dp, F7Colors.TextPrimary, CircleShape) else Modifier)
                                .clickable { color = hex },
                        )
                    }
                }

                EventFieldLabel("Поделиться")
                EventPill(icon = Icons.Default.Add) {
                    EventInput(
                        value = shareQuery,
                        onValueChange = { shareQuery = it; onSearchSharees(it) },
                        placeholder = "Пользователь или группа",
                        modifier = Modifier.weight(1f),
                    )
                }
                state.shareeSuggestions.take(5).forEach { s ->
                    Text(
                        (if (s.isGroup) "Группа: " else "") + s.displayName,
                        modifier = Modifier.clickable { onAddSharee(s, true); shareQuery = "" }.padding(start = 8.dp),
                        color = F7Colors.Primary,
                        fontSize = 13.sp,
                    )
                }
                state.editCalendarShares.forEach { sharee ->
                    Row(Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
                        Text(
                            sharee.displayName + if (sharee.writable) " (редактирование)" else " (чтение)",
                            color = F7Colors.TextPrimary, fontSize = 14.sp, modifier = Modifier.weight(1f),
                            maxLines = 1, overflow = TextOverflow.Ellipsis,
                        )
                        IconButton(onClick = { onRemoveSharee(sharee.principal) }, modifier = Modifier.size(24.dp)) {
                            Icon(Icons.Default.Close, contentDescription = "Убрать доступ", tint = F7Colors.TextSecondary, modifier = Modifier.size(16.dp))
                        }
                    }
                }

                HorizontalDivider(color = F7Colors.BorderLight)
                if (!confirmDelete) {
                    Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically) {
                        TextButton(onClick = { confirmDelete = true }, enabled = !state.editCalendarBusy) {
                            Text("Удалить календарь", color = F7Colors.Error)
                        }
                        F7PrimaryButton(
                            text = if (state.editCalendarBusy) "Сохранение…" else "Сохранить",
                            onClick = { onSave(name, color) },
                            enabled = !state.editCalendarBusy,
                        )
                    }
                } else {
                    Text("Удалить календарь и все его события?", color = F7Colors.TextPrimary, fontSize = 14.sp, fontWeight = FontWeight.SemiBold)
                    Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.End) {
                        TextButton(onClick = { confirmDelete = false }) { Text("Отмена", color = F7Colors.TextSecondary) }
                        Spacer(Modifier.width(8.dp))
                        TextButton(onClick = onDelete, enabled = !state.editCalendarBusy) {
                            Text(if (state.editCalendarBusy) "Удаление…" else "Удалить", color = F7Colors.Error)
                        }
                    }
                }
            }
        }
    }
}

/** Стандартная палитра Nextcloud для календарей. */
private val CALENDAR_PALETTE = listOf(
    "#0082C9", "#7CBC3D", "#E9322D", "#F1DB50", "#795AAB", "#E97D30", "#00C7B4",
)

/** Модалка «Повторять событие» — 1:1 с _calendar-repeat-modal.css (интервал+частота,
 *  кружки дней недели для недельного, окончание: никогда/до даты/N раз). */
@Composable
fun CalendarRepeatModal(
    initial: RecurrenceRule,
    onDismiss: () -> Unit,
    onApply: (RecurrenceRule) -> Unit,
    onClear: () -> Unit,
) {
    var rule by remember { mutableStateOf(initial) }
    val context = LocalContext.current
    val dateFmt = remember { DateTimeFormatter.ofPattern("dd.MM.yyyy") }

    Dialog(onDismissRequest = onDismiss, properties = DialogProperties(usePlatformDefaultWidth = false)) {
        Surface(
            shape = RoundedCornerShape(16.dp),
            color = Color.White,
            modifier = Modifier.fillMaxWidth(0.94f),
        ) {
            Column(Modifier.padding(horizontal = 16.dp, vertical = 14.dp), verticalArrangement = Arrangement.spacedBy(12.dp)) {
                Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically) {
                    Text("Повторять событие", style = MaterialTheme.typography.titleLarge, fontWeight = FontWeight.Bold, color = F7Colors.TextPrimary)
                    IconButton(onClick = onDismiss, modifier = Modifier.size(28.dp)) {
                        Icon(Icons.Default.Close, contentDescription = "Закрыть", tint = F7Colors.TextSecondary)
                    }
                }

                // Интервал + частота
                Row(horizontalArrangement = Arrangement.spacedBy(10.dp), verticalAlignment = Alignment.CenterVertically) {
                    EventPill(icon = null, modifier = Modifier.width(96.dp)) {
                        EventInput(
                            value = rule.interval.toString(),
                            onValueChange = { v ->
                                val n = v.filter { it.isDigit() }.take(3).toIntOrNull()
                                rule = rule.copy(interval = (n ?: 1).coerceAtLeast(1))
                            },
                            placeholder = "1",
                            modifier = Modifier.weight(1f),
                        )
                    }
                    var freqMenu by remember { mutableStateOf(false) }
                    Box(Modifier.weight(1f)) {
                        EventPill(icon = null, onClick = { freqMenu = true }) {
                            Text(freqLabel(rule.freq, rule.interval), color = EVENT_TEXT, fontSize = 14.sp, modifier = Modifier.weight(1f))
                            Icon(Icons.Default.KeyboardArrowDown, contentDescription = null, tint = EVENT_PLACEHOLDER, modifier = Modifier.size(16.dp))
                        }
                        DropdownMenu(expanded = freqMenu, onDismissRequest = { freqMenu = false }) {
                            listOf("DAILY", "WEEKLY", "MONTHLY", "YEARLY").forEach { f ->
                                DropdownMenuItem(
                                    text = { Text(freqLabel(f, rule.interval)) },
                                    onClick = { rule = rule.copy(freq = f); freqMenu = false },
                                )
                            }
                        }
                    }
                }

                // Дни недели (только WEEKLY): кружки 40dp, выбранный — зелёный градиент
                if (rule.freq == "WEEKLY") {
                    Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(8.dp)) {
                        RecurrenceRule.ICS_DAYS.forEach { day ->
                            val selected = day in rule.byDays
                            Box(
                                Modifier
                                    .weight(1f)
                                    .height(40.dp)
                                    .clip(CircleShape)
                                    .then(
                                        if (selected) {
                                            Modifier.background(
                                                androidx.compose.ui.graphics.Brush.linearGradient(
                                                    listOf(F7Colors.PrimaryGradientStart, F7Colors.PrimaryGradientEnd),
                                                ),
                                            )
                                        } else {
                                            Modifier
                                                .background(EVENT_FIELD_BG)
                                                .border(1.dp, EVENT_FIELD_BORDER, CircleShape)
                                        },
                                    )
                                    .clickable {
                                        rule = rule.copy(
                                            byDays = if (selected) rule.byDays - day else rule.byDays + day,
                                        )
                                    },
                                contentAlignment = Alignment.Center,
                            ) {
                                Text(
                                    RecurrenceRule.DAY_LABELS[day] ?: day,
                                    color = EVENT_TEXT,
                                    fontSize = 14.sp,
                                    fontWeight = FontWeight.Medium,
                                )
                            }
                        }
                    }
                }

                // Окончание
                EventFieldLabel("Окончание")
                var endMenu by remember { mutableStateOf(false) }
                Box {
                    EventPill(icon = null, onClick = { endMenu = true }) {
                        Text(
                            when (rule.endType) {
                                RecurrenceRule.EndType.NEVER -> "Никогда"
                                RecurrenceRule.EndType.UNTIL -> "До даты"
                                RecurrenceRule.EndType.COUNT -> "После N повторений"
                            },
                            color = EVENT_TEXT, fontSize = 14.sp, modifier = Modifier.weight(1f),
                        )
                        Icon(Icons.Default.KeyboardArrowDown, contentDescription = null, tint = EVENT_PLACEHOLDER, modifier = Modifier.size(16.dp))
                    }
                    DropdownMenu(expanded = endMenu, onDismissRequest = { endMenu = false }) {
                        DropdownMenuItem(text = { Text("Никогда") }, onClick = { rule = rule.copy(endType = RecurrenceRule.EndType.NEVER); endMenu = false })
                        DropdownMenuItem(text = { Text("До даты") }, onClick = { rule = rule.copy(endType = RecurrenceRule.EndType.UNTIL, untilDate = rule.untilDate ?: LocalDate.now().plusMonths(1)); endMenu = false })
                        DropdownMenuItem(text = { Text("После N повторений") }, onClick = { rule = rule.copy(endType = RecurrenceRule.EndType.COUNT); endMenu = false })
                    }
                }
                when (rule.endType) {
                    RecurrenceRule.EndType.UNTIL -> {
                        val until = rule.untilDate ?: LocalDate.now().plusMonths(1)
                        EventPill(icon = Icons.Default.DateRange, onClick = {
                            android.app.DatePickerDialog(
                                context,
                                { _, y, m, d -> rule = rule.copy(untilDate = LocalDate.of(y, m + 1, d)) },
                                until.year, until.monthValue - 1, until.dayOfMonth,
                            ).show()
                        }) {
                            Text(until.format(dateFmt), color = EVENT_TEXT, fontSize = 14.sp)
                        }
                    }
                    RecurrenceRule.EndType.COUNT -> {
                        EventPill(icon = null) {
                            EventInput(
                                value = rule.count.toString(),
                                onValueChange = { v ->
                                    val n = v.filter { it.isDigit() }.take(3).toIntOrNull()
                                    rule = rule.copy(count = (n ?: 1).coerceAtLeast(1))
                                },
                                placeholder = "10",
                                modifier = Modifier.weight(1f),
                            )
                            Text("раз", color = EVENT_PLACEHOLDER, fontSize = 14.sp)
                        }
                    }
                    RecurrenceRule.EndType.NEVER -> Unit
                }

                // Футер
                Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.End, verticalAlignment = Alignment.CenterVertically) {
                    TextButton(onClick = onClear) { Text("Не повторять", color = F7Colors.TextSecondary) }
                    Spacer(Modifier.width(8.dp))
                    F7PrimaryButton(text = "Применить", onClick = { onApply(rule) })
                }
            }
        }
    }
}

private fun freqLabel(freq: String, interval: Int): String = when (freq) {
    "DAILY" -> if (interval == 1) "день" else "дней"
    "WEEKLY" -> if (interval == 1) "неделя" else "недель"
    "MONTHLY" -> if (interval == 1) "месяц" else "месяцев"
    else -> if (interval == 1) "год" else "лет"
}

@Composable
fun CalendarFilesPickerDialog(
    state: CalendarUiState,
    onDismiss: () -> Unit,
    onNavigate: (String) -> Unit,
    onPick: (ru.forbion.f7cloud.core.network.DavClient.DavEntry) -> Unit,
) {
    val path = state.filesPickerPath
    Dialog(onDismissRequest = onDismiss, properties = DialogProperties(usePlatformDefaultWidth = false)) {
        Surface(
            shape = RoundedCornerShape(16.dp),
            color = Color.White,
            modifier = Modifier.fillMaxWidth(0.94f).fillMaxHeight(0.9f),
        ) {
            Column(Modifier.padding(horizontal = 16.dp, vertical = 14.dp)) {
                Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically) {
                    Text("Выберите файл", style = MaterialTheme.typography.titleLarge, fontWeight = FontWeight.Bold, color = F7Colors.TextPrimary)
                    IconButton(onClick = onDismiss, modifier = Modifier.size(28.dp)) {
                        Icon(Icons.Default.Close, contentDescription = "Закрыть", tint = F7Colors.TextSecondary)
                    }
                }
                // Хлебная крошка / кнопка «вверх»
                Row(Modifier.fillMaxWidth().padding(vertical = 6.dp), verticalAlignment = Alignment.CenterVertically) {
                    if (path.isNotBlank()) {
                        IconButton(onClick = { onNavigate(path.substringBeforeLast('/', "")) }, modifier = Modifier.size(28.dp)) {
                            Icon(Icons.Default.ArrowBack, contentDescription = "Назад", tint = F7Colors.TextSecondary)
                        }
                        Spacer(Modifier.width(6.dp))
                    }
                    Text("/${path}", color = F7Colors.TextSecondary, fontSize = 13.sp, maxLines = 1, overflow = TextOverflow.Ellipsis)
                }
                HorizontalDivider(color = F7Colors.BorderLight)
                Column(Modifier.weight(1f).verticalScroll(rememberScrollState())) {
                    when {
                        state.filesPickerLoading -> Text("Загрузка…", color = F7Colors.TextSecondary, fontSize = 14.sp, modifier = Modifier.padding(vertical = 12.dp))
                        state.filesPickerEntries.isEmpty() -> Text("Папка пуста", color = F7Colors.TextSecondary, fontSize = 14.sp, modifier = Modifier.padding(vertical = 12.dp))
                        else -> state.filesPickerEntries.forEach { entry ->
                            Row(
                                Modifier.fillMaxWidth().clickable {
                                    if (entry.isDirectory) {
                                        onNavigate(if (path.isBlank()) entry.name else "$path/${entry.name}")
                                    } else {
                                        onPick(entry)
                                    }
                                }.padding(vertical = 12.dp),
                                verticalAlignment = Alignment.CenterVertically,
                            ) {
                                Icon(
                                    if (entry.isDirectory) Icons.Default.Folder else Icons.Default.InsertDriveFile,
                                    contentDescription = null,
                                    tint = if (entry.isDirectory) F7Colors.Primary else F7Colors.TextSecondary,
                                    modifier = Modifier.size(20.dp),
                                )
                                Spacer(Modifier.width(12.dp))
                                Text(entry.name, color = F7Colors.TextPrimary, fontSize = 15.sp, maxLines = 1, overflow = TextOverflow.Ellipsis)
                            }
                            HorizontalDivider(color = F7Colors.BorderLight)
                        }
                    }
                }
            }
        }
    }
}
