package ru.forbion.f7cloud.feature.tasks

import java.time.LocalDate

/**
 * Умные (виртуальные) списки Задач — агрегируют задачи ПО ВСЕМ реальным спискам.
 * Семантика строго по веб-Tasks Nextcloud (согласовано с лидом, mail/070 п.2):
 *
 * - **Важное** (starred): незавершённые с высоким приоритетом (VTODO PRIORITY 1–4).
 * - **Сегодня**: незавершённые, у которых start ИЛИ due не в будущем (today или раньше,
 *   т.е. включая просроченные). Задачи вовсе без дат сюда НЕ попадают.
 * - **На неделе**: то же, но горизонт — конец текущей недели (today .. today+6).
 * - **Все**: все незавершённые (включая будущий start).
 * - **Текущие** (current): незавершённые, у которых start НЕ в будущем (уже стартовали
 *   или без start). Отличие от «Все» — исключает задачи с будущим start.
 * - **Завершенные**: завершённые.
 *
 * Чистая логика без Android/сети — покрыта юнит-тестами (`TasksSmartListsTest`).
 *
 * NB: start приходит из core (`DavTask.startRaw` ← DTSTART в `parseVTodo`). Границу окна
 * «неделя» и точное участие start сверить на веб-версии glb/апстриме nextcloud/tasks v0.17.1.
 */
enum class SmartListKey(val title: String, val icon: String) {
    IMPORTANT("Важное", "important-gray.svg"),
    TODAY("Сегодня", "calendar-today-gray.svg"),
    WEEK("На неделе", "calendar-nextweek-gray.svg"),
    ALL("Все", "calendar-icon-gray.svg"),
    CURRENT("Текущие", "current-gray.svg"),
    COMPLETED("Завершенные", "check-done-gray.svg"),
}

/**
 * Режим видимости умной коллекции в панели — как в веб-Tasks (server `show` 0/1/2):
 * [HIDDEN] всегда скрыта · [VISIBLE] всегда видима · [AUTO] видима только при count > 0.
 */
enum class SmartListMode { HIDDEN, VISIBLE, AUTO }

/**
 * Настройка видимости умных коллекций (шит «Параметры задач»). Хранит только НЕ-дефолтные
 * режимы — для компактной сериализации в SharedPreferences. Умолчание — [DEFAULT_MODE].
 */
data class SmartListVisibility(
    private val modes: Map<SmartListKey, SmartListMode> = emptyMap(),
) {
    fun mode(key: SmartListKey): SmartListMode = modes[key] ?: DEFAULT_MODE

    fun withMode(key: SmartListKey, mode: SmartListMode): SmartListVisibility =
        SmartListVisibility(
            if (mode == DEFAULT_MODE) modes - key else modes + (key to mode),
        )

    /** Только заданные вручную (не-дефолтные) режимы — для персиста. */
    fun explicitModes(): Map<SmartListKey, SmartListMode> = modes

    companion object {
        /** Умолчание: AUTO (показывать при непустом счётчике) — сверить с сервером live. */
        val DEFAULT_MODE = SmartListMode.AUTO
        val DEFAULT = SmartListVisibility()

        fun of(modes: Map<SmartListKey, SmartListMode>): SmartListVisibility =
            SmartListVisibility(modes.filterValues { it != DEFAULT_MODE })
    }
}

object TasksSmartLists {
    /** Высокий приоритет VTODO (1 — наивысший, 4 — ещё «важный»); 0 = не задан. */
    private val HIGH_PRIORITY = 1..4

    /** Горизонт списка «На неделе»: сегодня плюс 6 дней (окно текущей недели). */
    private const val WEEK_HORIZON_DAYS = 6L

    /** Попадает ли [task] в умный список [key] при опорной дате [today]. */
    fun matches(key: SmartListKey, task: TaskItem, today: LocalDate): Boolean = when (key) {
        SmartListKey.IMPORTANT -> !task.isCompleted && task.priority in HIGH_PRIORITY
        SmartListKey.TODAY -> !task.isCompleted && task.dueOrStartOnOrBefore(today)
        SmartListKey.WEEK -> !task.isCompleted && task.dueOrStartOnOrBefore(today.plusDays(WEEK_HORIZON_DAYS))
        SmartListKey.ALL -> !task.isCompleted
        SmartListKey.CURRENT -> !task.isCompleted && task.hasStarted(today)
        SmartListKey.COMPLETED -> task.isCompleted
    }

    /** Задачи умного списка [key], сохраняя исходный порядок [tasks]. */
    fun filter(key: SmartListKey, tasks: List<TaskItem>, today: LocalDate): List<TaskItem> =
        tasks.filter { matches(key, it, today) }

    /** Число задач в умном списке (для бейджа в панели). */
    fun count(key: SmartListKey, tasks: List<TaskItem>, today: LocalDate): Int =
        tasks.count { matches(key, it, today) }

    /** Счётчики всех коллекций сразу (по агрегату задач всех списков). */
    fun counts(tasks: List<TaskItem>, today: LocalDate): Map<SmartListKey, Int> =
        SmartListKey.entries.associateWith { key -> count(key, tasks, today) }

    /**
     * Коллекции для показа в панели (в порядке enum) с учётом режима видимости и счётчиков:
     * VISIBLE — всегда, AUTO — при count > 0, HIDDEN — никогда.
     */
    fun visibleKeys(
        visibility: SmartListVisibility,
        counts: Map<SmartListKey, Int>,
    ): List<SmartListKey> = SmartListKey.entries.filter { key ->
        when (visibility.mode(key)) {
            SmartListMode.VISIBLE -> true
            SmartListMode.HIDDEN -> false
            SmartListMode.AUTO -> (counts[key] ?: 0) > 0
        }
    }

    /** Уже стартовала: нет start, либо start сегодня/в прошлом. */
    private fun TaskItem.hasStarted(today: LocalDate): Boolean {
        val start = startLocalDate() ?: return true
        return !start.isAfter(today)
    }

    /**
     * Есть start ИЛИ due, и хотя бы один из них не позже [limit].
     * Задача без обеих дат не попадает в «Сегодня»/«На неделе».
     */
    private fun TaskItem.dueOrStartOnOrBefore(limit: LocalDate): Boolean {
        val start = startLocalDate()
        val due = dueLocalDate()
        if (start == null && due == null) return false
        return (start != null && !start.isAfter(limit)) || (due != null && !due.isAfter(limit))
    }
}
