package de.sebse.fuplanner2.blackboard

import android.content.Context
import com.android.volley.VolleyError
import com.beust.klaxon.JsonObject
import com.beust.klaxon.Parser
import de.sebse.fuplanner2.database.*
import de.sebse.fuplanner2.network.Requester
import de.sebse.fuplanner2.utils.*
import de.sebse.fuplanner2.worker.FetchResourceErrorType
import de.sebse.fuplanner2.worker.FetchResourceException


suspend fun Blackboard.getEvents(ctx: Context, database: AppDatabase, user: User, course: Course): UpdateResult<Event> {
    if (!isAvailable(user)) return UpdateResult()
    if (course.moduleType != MODULE_TYPE) return UpdateResult()
    val courseId = course.uid ?: return UpdateResult()

    val requester = Requester(ctx)
    val stored = database.eventDao().getAll2(courseId)

    val latestSemester = database.courseDao().getLatestSemesterName()
    if (course.isSummerSemester != latestSemester.semester || course.year != latestSemester.year)
        return updateResultOf(stored, stored)

    try {
        val new = course.lvNumber.map { lvNumber ->
            val vvNumber = Cache.getCache(database, lvNumber, "Blackboard_VVNumber", REFRESH_FREQUENCY_EVENT_CACHE_MILLIS) {
                requester.head(
                    FETCH_VV_COURSE_ID.format(lvNumber),
                    null
                ).let {
                    Regex("lv/([0-9]+)\\?")
                        .find(it.headers?.get("Location") ?: "")
                        ?.groups
                        ?.get(1)
                        ?.value
                } ?: ""
            }

            val body = requester
                .get(FETCH_VV_COURSE.format(vvNumber), null)
                .body
            Regex("<span id=\"link_to_details_[^~]*?</span>")
                .findAll(body)
                .map event@{
                    val (start, duration) = Regex("[A-Z][a-z], [0-9]{2}\\.[0-9]{2}\\.[0-9]{4} [0-9]{2}:[0-9]{2} - [0-9]{2}:[0-9]{2}")
                        .find(it.value)
                        ?.value
                        ?.let { dateString ->
                            val start = dateString.substring(4, 20)
                                .dateStringToLong("dd.MM.yyyy HH:mm")
                                ?: return@event null
                            val duration = (0L
                                    + (dateString.substring(23, 25).toLongOrNull(10) ?: return@event null) * 60
                                    - (dateString.substring(15, 17).toLongOrNull(10) ?: return@event null) * 60
                                    + (dateString.substring(26, 28).toLongOrNull(10) ?: return@event null) * 1
                                    - (dateString.substring(18, 20).toLongOrNull(10) ?: return@event null) * 1)
                            Pair(start, duration * 60000)
                        } ?: return@event null
                    val title = Regex("<div class=\"course_title\">([^<]*?)</div>")
                        .find(it.value)
                        ?.groups
                        ?.get(1)
                        ?.value
                        ?.trim()
                        ?: course.title
                    val location = Regex("<div class=\"appointment_details_column\">[^~]*?</div>")
                        .findAll(it.value)
                        .map {
                            if (it.value.contains("Räume:"))
                                Regex("</b>([^~]*?)</p>")
                                    .findAll(it.value)
                                    .map { it.groups.get(1)?.value?.trim() }
                                    .filterNotNull()
                                    .toList()
                            else
                                listOf()
                        }
                        .flatten()
                        .joinToString(separator = ", ")
                    val type = Regex("<span class=\"[^\"]*?category[^\"]*?\">([^<]*)</span>")
                        .find(it.value)
                        ?.groups
                        ?.get(1)
                        ?.value
                        ?.trim()
                        ?: "Class section - Lecture"
                    Event(null, courseId, System.currentTimeMillis(), title, duration, start, location, type)
                }
                .toList()
                .filterNotNull()
        }.flatten()

        val result = updateResultOf(stored, new)
        database.eventDao().run {
            delete(result.removed)
            upsert(result.values)
        }
        return result
    } catch (e: VolleyError) {
        val statusCode = e.networkResponse.statusCode
        throw FetchResourceException(FetchResourceErrorType.ERR_NETWORK_ERROR, statusCode)
    }
}