package com.github.nullptroma.wallenc.domain.datatypes

/** Журнал синхронизации: один актуальный [StorageSyncJournalEntry] на нормализованный путь. */
typealias StorageSyncJournal = Map<String, StorageSyncJournalEntry>

object StorageSyncPaths {
    fun normalize(path: String): String = if (path.startsWith("/")) path else "/$path"

    /**
     * Пути, которые участвуют в sync и попадают в журнал при пользовательских операциях.
     * Служебные каталоги, lock/journal/meta и файлы внутри *-enc-dir исключены.
     */
    fun isSyncableUserPath(path: String): Boolean {
        val p = normalize(path)
        if (p == "/" || p.isBlank()) return false
        if (p == "/wallenc-yandex-system" || p.startsWith("/wallenc-yandex-system/")) return false
        if (p.contains("-enc-dir/") || p.endsWith("-enc-dir")) return false
        val name = p.substringAfterLast('/')
        if (name == "sync-journal.json" || name == "sync-lock.json") return false
        if (name.endsWith(".enc-meta") || name.endsWith(".storage-info")) return false
        return true
    }
}

object StorageSyncJournalMerge {
    fun merge(into: StorageSyncJournal, entries: Map<String, StorageSyncJournalEntry>): StorageSyncJournal {
        if (entries.isEmpty()) return into
        val result = into.toMutableMap()
        for ((rawPath, entry) in entries) {
            val path = StorageSyncPaths.normalize(rawPath)
            if (!StorageSyncPaths.isSyncableUserPath(path)) continue
            val normalizedEntry = entry.copy(path = path)
            val current = result[path]
            if (current == null || compareEntries(normalizedEntry, current) > 0) {
                result[path] = normalizedEntry
            }
        }
        return result
    }

    fun merge(into: StorageSyncJournal, entry: StorageSyncJournalEntry): StorageSyncJournal =
        merge(into, mapOf(entry.path to entry))

    fun mergeAll(journals: Collection<StorageSyncJournal>): StorageSyncJournal {
        var acc: StorageSyncJournal = emptyMap()
        for (journal in journals) {
            acc = merge(acc, journal)
        }
        return acc
    }

    private fun compareEntries(a: StorageSyncJournalEntry, b: StorageSyncJournalEntry): Int {
        val seqCmp = a.revision.sequence.compareTo(b.revision.sequence)
        if (seqCmp != 0) return seqCmp
        val actorCmp = a.revision.actorId.compareTo(b.revision.actorId)
        if (actorCmp != 0) return actorCmp
        return a.revision.createdAt.compareTo(b.revision.createdAt)
    }
}
