package de.kif.backend.util

import de.kif.backend.Configuration
import de.kif.backend.repository.TrackRepository
import de.kif.common.model.Language
import de.kif.common.model.Track
import de.kif.common.model.WorkGroup
import io.ktor.client.HttpClient
import io.ktor.client.request.get
import mu.KotlinLogging
import kotlin.math.max

object WikiImporter {

    private val logger = KotlinLogging.logger {}

    private suspend fun loadDocument(url: String): String = HttpClient().get(url)

    suspend fun loadSections(url: String = Configuration.General.wikiUrl): List<String> {
        val data = loadDocument(url)

        val lines = data.split("\n")

        return lines.filter {
            it.matches("==.*==".toRegex())
        }.map {
            it.replace("==", "").trim()
        }
    }

    /**
     * Import ak data from the wiki
     *
     * @param url Url to the wiki entry. It must point to the raw version not the rendered ("https://wiki.kif.rocks/w/index.php?title=KIF470:Arbeitskreise&action=raw").
     * @param sections Track association. A negative id skip's a section. All other id values will be mapped to the
     * corresponding track or null.
     */
    suspend fun import(
        url: String = Configuration.General.wikiUrl,
        sections: Map<String, Long?> = emptyMap()
    ): List<WorkGroup> {
        logger.info { "Start import of work groups..." }

        val data = loadDocument(url)

        val tracks = TrackRepository.all().associateBy { it.id }

        val workGroups = mutableListOf<WorkGroup>()

        val dataRegex = """(== (.*) ==)|(\{\{.*\n((\|.*\n)+)}})""".toRegex()

        var track: Track? = null
        var skip = false

        for (dataMatch in dataRegex.findAll(data)) {
            val header = dataMatch.groupValues[2]
            val content = dataMatch.groupValues[4]

            if (header.isNotBlank()) {
                val trackId = sections[header.trim()]

                when {
                    trackId == null -> {
                        skip = false
                        track = null
                    }
                    trackId < 0 -> {
                        skip = true
                        track = null
                    }
                    else -> {
                        skip = false
                        track = tracks[trackId]
                    }
                }
            } else if (content.isNotBlank()) {
                if (skip) continue
                val ak = content
                    .split("\n|")
                    .mapNotNull {
                        it.split("=")
                            .map { it.removePrefix("|").trim() }
                            .let { if (it.size > 1) it[0] to it[1] else null }
                    }
                    .toMap()

                val name = ak["name"]?.trim() ?: continue
                var desc = ak["beschreibung"]?.trim() ?: ""
                val participant = ak["wieviele"]?.trim() ?: ""
                val who = ak["wer"]?.trim() ?: ""
                val time = ak["wann"]?.trim() ?: ""
                val length = ak["dauer"]?.trim() ?: ""

                if (name.isBlank() && desc.isBlank()) continue

                if (who.isNotBlank() || time.isNotBlank() || length.isNotBlank()) {
                    desc += "\n"
                    desc += "\n"
                    desc += "--- Aus dem Wiki übernommen ---"
                    desc += "\n"
                    desc += "\n"

                    if (who.isNotBlank()) {
                        desc += "Wer = $who\n"
                    }
                    if (time.isNotBlank()) {
                        desc += "Wann = $time\n"
                    }
                    if (length.isNotBlank()) {
                        desc += "Dauer = $length\n"
                    }
                }

                var akLength = 60

                if (length.isNotBlank()) {
                    val regex = """(\d+) *(h|[Ss]tund|[Ss]lot)""".toRegex()
                    val match = regex.find(length)

                    if (match != null) {
                        akLength = max(akLength, (match.groupValues.getOrNull(1)?.toIntOrNull() ?: 0) * 60)
                    }
                }

                var interested = 0

                if (length.isNotBlank()) {
                    val regex = """\d+""".toRegex()
                    val match = regex.find(participant)

                    if (match != null) {
                        interested = match.groupValues.getOrNull(0)?.toIntOrNull() ?: 0
                    }
                }

                workGroups += WorkGroup(
                    id = null,
                    name = name,
                    description = desc,
                    interested = interested,
                    track = track,
                    projector = false,
                    resolution = false,
                    internet = false,
                    whiteboard = false,
                    blackboard = false,
                    accessible = false,
                    length = akLength,
                    language = Language.GERMAN,
                    constraints = emptyList()
                )
            }
        }

        logger.info { "Found ${workGroups.size} work groups" }

        return workGroups
    }
}
