package web

import codes.Somecodes
import codes.Somecodes.Companion.ListAudioFiles
import codes.Somecodes.Companion.ValidDate
import codes.Somecodes.Companion.ValidFile
import codes.Somecodes.Companion.ValidScheduleDay
import codes.Somecodes.Companion.ValidScheduleTime
import codes.Somecodes.Companion.ValidString
import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import content.Category
import content.Language
import content.ScheduleDay
import content.VoiceType
import database.LanguageLink
import database.MariaDB
import database.Soundbank
import io.javalin.Javalin
import io.javalin.apibuilder.ApiBuilder.before
import io.javalin.apibuilder.ApiBuilder.delete
import io.javalin.apibuilder.ApiBuilder.get
import io.javalin.apibuilder.ApiBuilder.patch
import io.javalin.apibuilder.ApiBuilder.path
import io.javalin.apibuilder.ApiBuilder.post
import io.javalin.apibuilder.ApiBuilder.ws
import io.javalin.http.Context
import io.javalin.json.JavalinJackson
import io.javalin.websocket.WsMessageContext
import org.apache.poi.xssf.usermodel.XSSFWorkbook
import java.time.LocalDateTime

@Suppress("unused")
class WebApp(val listenPort: Int, val userlist: List<Pair<String, String>>, val db: MariaDB) {

    var app: Javalin? = null
    val objectmapper = jacksonObjectMapper()

    private fun SendReply(context: WsMessageContext, command: String, value: String) {
        try {
            if (context.session.isOpen) {
                context.send(objectmapper.writeValueAsString(WebsocketReply(command, value)))
            }
        } catch (_: Exception) {
        }
    }

    fun Start() {
        app = Javalin.create { config ->
            config.useVirtualThreads = true
            config.staticFiles.add("/webpage")
            config.jsonMapper(JavalinJackson(jacksonObjectMapper()))
            config.router.apiBuilder {
                path("/") {
                    get { ctx ->
                        // Serve the main page
                        ctx.sessionAttribute("user", null) // Clear user session
                        ctx.redirect("login.html")
                    }

                }
                path("login.html") {
                    post { it ->
                        // get username and password from form
                        val username = it.formParam("username")
                        val password = it.formParam("password")
                        if (username == null || password == null) {
                            it.status(400).result("Username and password are required")
                            return@post
                        }
                        // Check if user exists in userlist
                        val user = userlist.find { it.first == username && it.second == password }
                        if (user == null) {
                            it.status(401).result("Invalid username or password")
                            return@post
                        }
                        // Set user session
                        it.sessionAttribute("user", user.first)
                        println("User ${user.first} logged in")
                        // Redirect to home page
                        it.redirect("home.html")
                    }
                }

                path("home.html") {
                    before { CheckUsers(it) }
                    ws("/ws") { ws ->
                        // WebSocket endpoint for home
                        ws.onClose { wsCloseContext ->
                            // TODO Handle WebSocket close event
                            println("WebSocket closed: ${wsCloseContext.session.remoteAddress}")
                        }
                        ws.onMessage { wsMessageContext ->
                            try {
                                val cmd =
                                    objectmapper.readValue(wsMessageContext.message(), WebsocketCommand::class.java)
                                when (cmd.command) {
                                    "getSystemTime" -> {
                                        SendReply(
                                            wsMessageContext,
                                            cmd.command,
                                            LocalDateTime.now().format(Somecodes.datetimeformat1)
                                        )
                                    }

                                    "getCPUStatus" -> {
                                        Somecodes.getCPUUsage { vv ->
                                            SendReply(wsMessageContext, cmd.command, vv)
                                        }
                                    }

                                    "getMemoryStatus" -> {
                                        SendReply(wsMessageContext, cmd.command, Somecodes.getMemoryUsage())
                                    }

                                    "getDiskStatus" -> {
                                        SendReply(wsMessageContext, cmd.command, Somecodes.getDiskUsage())
                                    }

                                    "getNetworkStatus" -> {
                                        // TODO Get Network status
                                        SendReply(wsMessageContext, cmd.command, "OK")
                                    }

                                    "getPagingQueue" ->{
                                        SendReply(wsMessageContext, cmd.command, MariaDB.ArrayListtoString(db.Read_Queue_Paging()))
                                    }

                                    "getAASQueue" ->{
                                        SendReply(wsMessageContext, cmd.command, MariaDB.ArrayListtoString(db.Read_Queue_Table()))
                                    }

                                    else -> {
                                        SendReply(wsMessageContext, cmd.command, "Unknown command")
                                    }
                                }
                            } catch (e: Exception) {
                                println("Error processing WebSocket message: ${e.message}")
                            }

                        }
                        ws.onConnect { wsConnectContext ->
                            // TODO Handle WebSocket connect event
                            println("WebSocket connected: ${wsConnectContext.session.remoteAddress}")
                        }

                    }
                }
                path("soundbank.html") {
                    before { CheckUsers(it) }
                }
                path("messagebank.html") {
                    before { CheckUsers(it) }
                }
                path("language.html") {
                    before { CheckUsers(it) }
                }
                path("log.html") {
                    before { CheckUsers(it) }
                }
                path("setting.html") {
                    before { CheckUsers(it) }
                }
                path("timer.html") {
                    before { CheckUsers(it) }
                }
                path("api") {
                    path("VoiceType"){
                        get{
                            it.result(objectmapper.writeValueAsString(VoiceType.entries.map { vt -> vt.name }))
                        }
                    }
                    path("Category") {
                        get {
                            it.result(objectmapper.writeValueAsString(Category.entries.map { cat -> cat.name }) )
                        }
                    }
                    path("Language") {
                        get {
                            it.result(objectmapper.writeValueAsString(Language.entries.map { lang -> lang.name }) )
                        }
                    }
                    path("ScheduleDay") {
                        get {
                            it.result(objectmapper.writeValueAsString(ScheduleDay.entries.map { day -> day.toString() }))
                        }
                    }
                    path("SoundBank") {
                        get("List") {
                            // get soundbank list
                            it.result(MariaDB.ArrayListtoString(db.SoundbankList))
                        }
                        get("ListFiles"){
                            it.result(objectmapper.writeValueAsString(ListAudioFiles("C:\\soundbank")))
                        }
                        post("Add") {
                            try {
                                val addvalue = objectmapper.readValue(it.body(), Soundbank::class.java)
                                if (ValidString(addvalue.Description)) {
                                    if (ValidString(addvalue.TAG)) {
                                        if (ValidString(addvalue.Category)) {
                                            if (ValidString(addvalue.Language)) {
                                                if (ValidString(addvalue.Path)) {
                                                    // check apakah TAG sudah ada untuk language dan category yang sama
                                                    val exists = db.SoundbankList.any { sb ->
                                                        sb.TAG == addvalue.TAG && sb.Language == addvalue.Language && sb.Category == addvalue.Category
                                                    }
                                                    if (!exists) {
                                                        if (ValidFile(addvalue.Path)) {
                                                            if (db.Add_Soundbank(addvalue)) {
                                                                it.result("OK")
                                                            } else it.status(500)
                                                                .result("Failed to add soundbank to database")
                                                        } else it.status(400)
                                                            .result("Invalid Path, file does not exist")
                                                    } else it.status(400)
                                                        .result("TAG=${addvalue.TAG} already exists for the same Language=${addvalue.Language} and Category=${addvalue.Category}")
                                                } else it.status(400).result("Invalid Path")
                                            } else it.status(400).result("Invalid Language")
                                        } else it.status(400).result("Invalid Category")
                                    } else it.status(400).result("Invalid TAG")
                                } else it.status(400).result("Invalid Description")
                            } catch (_: Exception) {
                                it.status(400).result("Invalid request body")
                            }
                        }
                        delete("List") {
                            // truncate soundbank table
                            if (db.Clear_Soundbank()) {
                                it.result("OK")
                            } else {
                                it.status(500).result("Failed to truncate soundbank table")
                            }
                        }
                        delete("DeleteByIndex/{index}") {
                            // delete by index
                            val index = it.pathParam("index").toUIntOrNull()
                            if (index == null) {
                                it.status(400).result("Invalid index")
                            } else {
                                if (db.Delete_Soundbank_by_index(index)) {
                                    it.result("OK")
                                } else {
                                    it.status(500).result("Failed to delete soundbank with index $index")
                                }
                            }
                        }
                        patch("UpdateByIndex/{index}") {
                            // update by index
                            val index = it.pathParam("index").toUIntOrNull()
                            if (index == null) {
                                // tidak ada path param index
                                it.status(400).result("Invalid index")
                            } else {
                                val sb = db.SoundbankList.find { xx -> xx.index == index }
                                if (sb == null) {
                                    // soundbank dengan index tersebut tidak ditemukan
                                    it.status(404).result("Soundbank with index $index not found")
                                } else {
                                    // soundbank dengan index tersebut ditemukan, sekarang update
                                    val json: JsonNode = objectmapper.readTree(it.body())
                                    if (json.isEmpty) {
                                        it.status(400).result("UpdateByIndex with index=$index has empty body")
                                    } else {
                                        val _description = json.get("Description").asText()
                                        val _tag = json.get("TAG").asText()
                                        val _category = json.get("Category").asText()
                                        val _language = json.get("Language").asText()
                                        val _path = json.get("Path").asText()
                                        var changed = false
                                        if (ValidString(_description) && _description != sb.Description) {
                                            sb.Description = _description
                                            changed = true
                                        }
                                        if (ValidString(_tag) && _tag != sb.TAG) {
                                            sb.TAG = _tag
                                            changed = true
                                        }
                                        if (ValidString(_category) && _category != sb.Category) {
                                            if (Category.entries.any { cat ->
                                                    cat.name == _category
                                                }) {
                                                sb.Category = _category
                                                changed = true
                                            } else {
                                                it.status(400).result("Invalid Category")
                                                return@patch
                                            }
                                        }
                                        if (ValidString(_language) && _language != sb.Language) {
                                            sb.Language = _language
                                            changed = true
                                        }
                                        if (ValidString(_path) && _path != sb.Path) {
                                            if (ValidFile(_path)) {
                                                sb.Path = _path
                                                changed = true
                                            } else {
                                                it.status(400).result("Invalid Path, file does not exist")
                                                return@patch
                                            }
                                        }
                                        if (changed) {
                                            if (db.Update_Soundbank_by_index(index, sb)) {
                                                it.result("OK")
                                            } else it.status(500).result("Failed to update soundbank with index $index")
                                        } else it.status(400)
                                            .result("Nothing has changed for soundbank with index $index")
                                    }
                                }
                            }
                        }
                        get("ExportXLSX") {
                            val xlsxdata = db.Export_Soundbank_XLSX()
                            if (xlsxdata != null) {
                                it.header(
                                    "Content-Type",
                                    "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
                                )
                                it.header("Content-Disposition", "attachment; filename=\"soundbank.xlsx\"")
                                it.outputStream().use { out ->
                                    xlsxdata.write(out)
                                }
                            } else {
                                it.status(500).result("Failed to export soundbank to XLSX")
                            }
                        }
                        post("ImportXLSX") {
                            val uploaded = it.uploadedFile("file")
                            if (uploaded == null) {
                                it.status(400).result("No file uploaded")
                                return@post
                            }
                            try {
                                val xlsx = XSSFWorkbook(uploaded.content())
                                if (db.Import_Soundbank_XLSX(xlsx)) {
                                    it.result("OK")
                                } else {
                                    it.status(500).result("Failed to import soundbank from XLSX")
                                }
                            } catch (e: Exception) {
                                it.status(400).result("Invalid XLSX file")
                            }
                        }
                    }
                    path("MessageBank") {
                        get("List") {
                            // get messagebank list
                            it.result(MariaDB.ArrayListtoString(db.MessagebankList))
                        }
                        post("Add"){
                            // TODO add new messagebank
                        }
                        delete("List") {
                            // truncate messagebank table
                            if (db.Clear_Messagebank()) {
                                it.result("OK")
                            } else {
                                it.status(500).result("Failed to truncate messagebank table")
                            }
                        }
                        delete("DeleteByIndex/{index}") {
                            // delete by index
                            val index = it.pathParam("index").toUIntOrNull()
                            if (index == null) {
                                it.status(400).result("Invalid index")
                            } else {
                                if (db.Delete_Messagebank_by_index(index)) {
                                    it.result("OK")
                                } else {
                                    it.status(500).result("Failed to delete messagebank with index $index")
                                }
                            }
                        }
                        patch("UpdateByIndex/{index}") {
                            // update messagebank by index
                            val index = it.pathParam("index").toUIntOrNull()
                            if (index == null) {
                                it.status(400).result("Invalid index")
                            } else {
                                val mb = db.MessagebankList.find { xx -> xx.index == index }
                                if (mb == null) {
                                    it.status(404).result("Messagebank with index $index not found")
                                } else {
                                    val json: JsonNode = objectmapper.readTree(it.body())
                                    if (json.isEmpty) {
                                        it.status(400).result("UpdateByIndex with index=$index has empty body")
                                    } else {
                                        val _description = json.get("Description").asText()
                                        val _language = json.get("Language").asText()
                                        val _ann_id = json.get("ANN_ID").asInt().toUInt()
                                        val _voice_type = json.get("Voice_Type").asText()
                                        val _message_detail = json.get("Message_Detail").asText()
                                        val _message_tags = json.get("Message_TAGS").asText()

                                        var changed = false
                                        if (ValidString(_description) && _description != mb.Description) {
                                            mb.Description = _description
                                            changed = true
                                        }
                                        if (ValidString(_language) && _language != mb.Language) {
                                            mb.Language = _language
                                            changed = true
                                        }
                                        if (_ann_id > 0u && _ann_id != mb.ANN_ID) {
                                            mb.ANN_ID = _ann_id
                                            changed = true
                                        }
                                        if (ValidString(_voice_type) && _voice_type != mb.Voice_Type) {
                                            if (VoiceType.entries.any { vt -> vt.name == _voice_type }) {
                                                mb.Voice_Type = _voice_type
                                                changed = true
                                            } else {
                                                it.status(400).result("Invalid Voice_Type")
                                                return@patch
                                            }
                                        }
                                        if (ValidString(_message_detail) && _message_detail != mb.Message_Detail) {
                                            mb.Message_Detail = _message_detail
                                            changed = true
                                        }
                                        if (ValidString(_message_tags) && _message_tags != mb.Message_TAGS) {
                                            mb.Message_TAGS = _message_tags
                                            changed = true
                                        }
                                        if (changed) {
                                            if (db.Update_Messagebank_by_index(index, mb)) {
                                                it.result("OK")
                                            } else it.status(500)
                                                .result("Failed to update messagebank with index $index")
                                        } else it.status(400)
                                            .result("Nothing has changed for messagebank with index $index")
                                    }
                                }
                            }
                        }
                        get("ExportXLSX") {
                            val xlsxdata = db.Export_Messagebank_XLSX()
                            if (xlsxdata != null) {
                                it.header(
                                    "Content-Type",
                                    "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
                                )
                                it.header("Content-Disposition", "attachment; filename=\"messagebank.xlsx\"")
                                it.outputStream().use { out ->
                                    xlsxdata.write(out)
                                }
                            } else {
                                it.status(500).result("Failed to export messagebank to XLSX")
                            }
                        }
                        post("ImportXLSX") {
                            val uploaded = it.uploadedFile("file")
                            if (uploaded == null) {
                                it.status(400).result("No file uploaded")
                                return@post
                            }
                            try {
                                val xlsx = XSSFWorkbook(uploaded.content())
                                if (db.Import_Messagebank_XLSX(xlsx)) {
                                    it.result("OK")
                                } else {
                                    it.status(500).result("Failed to import messagebank from XLSX")
                                }
                            } catch (e: Exception) {
                                it.status(400).result("Invalid XLSX file")
                            }
                        }
                    }
                    path("LanguageLink") {
                        get("List") {
                            // get language link list
                            it.result(MariaDB.ArrayListtoString(db.LanguageLinkList))
                        }
                        post("Add"){
                            // Parse JSON from request body
                            val json: JsonNode = objectmapper.readTree(it.body())
                            val tag = json.get("tag").asText()
                            val languages = json.get("language").asText().split(";")
                            if (ValidString(tag)){
                                if (languages.all { xx -> Language.entries.any { yy -> yy.name== xx} }){
                                    if (db.LanguageLinkList.any { ll -> ll.TAG==tag }){
                                        val newvalue = LanguageLink(0u, tag, languages.joinToString(";"))
                                        if (db.Add_LanguageLink(newvalue)){
                                            it.result("OK")
                                        } else it.status(500).result("Failed to add language link to database")
                                    } else it.status(400).result("TAG=$tag already exists" )
                                } else it.status(400).result("Contains unsupported language" )
                            } else it.status(400).result("Invalid tag or language")
                        }
                        delete("List") {
                            // truncate language link table
                            if (db.Clear_LanguageLink()) {
                                it.result("OK")
                            } else {
                                it.status(500).result("Failed to truncate language link table")
                            }
                        }
                        delete("DeleteByIndex/{index}") {
                            // delete by index
                            val index = it.pathParam("index").toUIntOrNull()
                            if (index == null) {
                                it.status(400).result("Invalid index")
                            } else {
                                if (db.Delete_LanguageLink_by_index(index)) {
                                    it.result("OK")
                                } else {
                                    it.status(500).result("Failed to delete language link with index $index")
                                }
                            }
                        }
                        patch("UpdateByIndex/{index}") {
                            // update by index
                            val index = it.pathParam("index").toUIntOrNull()
                            if (index == null) {
                                it.status(400).result("Invalid index")
                            } else {
                                val ll = db.LanguageLinkList.find { xx -> xx.index == index }
                                if (ll == null) {
                                    it.status(404).result("Language link with index $index not found")
                                } else {
                                    val json: JsonNode = objectmapper.readTree(it.body())
                                    if (json.isEmpty) {
                                        it.status(400).result("UpdateByIndex with index=$index has empty body")
                                    } else {
                                        val _tag = json.get("TAG").asText()
                                        val _language = json.get("Language").asText()
                                        var changed = false
                                        if (ValidString(_language) && _language != ll.Language) {
                                            ll.Language = _language
                                            changed = true
                                        }
                                        if (ValidString(_tag) && _tag != ll.TAG) {
                                            ll.TAG = _tag
                                            changed = true
                                        }
                                        if (changed) {
                                            if (db.Update_LanguageLink_by_index(index, ll)) {
                                                it.result("OK")
                                            } else it.status(500)
                                                .result("Failed to update language link with index $index")
                                        } else it.status(400)
                                            .result("Nothing has changed for language link with index $index")
                                    }
                                }
                            }
                        }
                        get("ExportXLSX") {
                            val xlsxdata = db.Export_LanguageLink_XLSX()
                            if (xlsxdata != null) {
                                it.header(
                                    "Content-Type",
                                    "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
                                )
                                it.header("Content-Disposition", "attachment; filename=\"languagelink.xlsx\"")
                                it.outputStream().use { out ->
                                    xlsxdata.write(out)
                                }
                            } else {
                                it.status(500).result("Failed to export language link to XLSX")
                            }
                        }
                        post("ImportXLSX") {
                            val uploaded = it.uploadedFile("file")
                            if (uploaded == null) {
                                it.status(400).result("No file uploaded")
                                return@post
                            }
                            try {
                                val xlsx = XSSFWorkbook(uploaded.content())
                                if (db.Import_LanguageLink_XLSX(xlsx)) {
                                    it.result("OK")
                                } else {
                                    it.status(500).result("Failed to import language link from XLSX")
                                }
                            } catch (e: Exception) {
                                it.status(400).result("Invalid XLSX file")
                            }
                        }
                    }
                    path("ScheduleBank") {
                        get("List") {
                            // get timer list
                            it.result(MariaDB.ArrayListtoString(db.SchedulebankList))
                        }
                        delete("List") {
                            // truncate timer table
                            if (db.Clear_Schedulebank()) {
                                it.result("OK")
                            } else {
                                it.status(500).result("Failed to truncate schedulebank table")
                            }
                        }
                        delete("DeleteByIndex/{index}") {
                            // delete by index
                            val index = it.pathParam("index").toUIntOrNull()
                            if (index == null) {
                                it.status(400).result("Invalid index")
                            } else {
                                if (db.Delete_Schedulebank_by_index(index)) {
                                    it.result("OK")
                                } else {
                                    it.status(500).result("Failed to delete schedule with index $index")
                                }
                            }
                        }
                        patch("UpdateByIndex/{index}") {
                            // update by index
                            val index = it.pathParam("index").toUIntOrNull()
                            if (index == null) {
                                it.status(400).result("Invalid index")
                            } else {
                                val sb = db.SchedulebankList.find { xx -> xx.index == index }
                                if (sb == null) {
                                    it.status(404).result("Schedule with index $index not found")
                                } else {
                                    val json: JsonNode = objectmapper.readTree(it.body())
                                    if (json.isEmpty) {
                                        it.status(400).result("UpdateByIndex with index=$index has empty body")
                                    } else {
                                        val _description = json.get("Description").asText()
                                        val _time = json.get("Time").asText()
                                        val _day = json.get("Day").asText()
                                        val _soundpath = json.get("Soundpath").asText()
                                        val _repeat = json.get("Repeat").asInt().toUByte()
                                        val _enable = json.get("Enable").asBoolean()
                                        val _broadcast_zones = json.get("BroadcastZones").asText()
                                        val _language = json.get("Language").asText()
                                        var changed = false
                                        if (ValidString(_description) && _description != sb.Description) {
                                            sb.Description = _description
                                            changed = true
                                        }
                                        if (ValidString(_time) && _time != sb.Time) {
                                            if (ValidScheduleTime(_time)) {
                                                sb.Time = _time
                                                changed = true
                                            } else {
                                                it.status(400).result("Invalid Time format, must be HH:mm")
                                                return@patch
                                            }
                                        }
                                        if (ValidString(_day) && _day != sb.Day) {
                                            if (ValidScheduleDay(_day)) {
                                                sb.Day = _day
                                                changed = true
                                            } else {
                                                it.status(400).result("Invalid Day format")
                                                return@patch
                                            }
                                        }
                                        if (ValidString(_soundpath) && _soundpath != sb.Soundpath) {
                                            sb.Soundpath = _soundpath
                                            changed = true
                                        }
                                        if (_repeat != sb.Repeat) {
                                            sb.Repeat = _repeat
                                            changed = true
                                        }
                                        if (_enable != sb.Enable) {
                                            sb.Enable = _enable
                                            changed = true
                                        }
                                        if (ValidString(_broadcast_zones) && _broadcast_zones != sb.BroadcastZones) {
                                            sb.BroadcastZones = _broadcast_zones
                                            changed = true
                                        }
                                        if (ValidString(_language) && _language != sb.Language) {
                                            if (Language.entries.any{ lang -> lang.name == _language }) {
                                                sb.Language = _language
                                                changed = true
                                            } else {
                                                it.status(400).result("Invalid Language")
                                                return@patch
                                            }
                                        }
                                        if (changed) {
                                            if (db.Update_Schedulebank_by_index(index, sb)) {
                                                it.result("OK")
                                            } else it.status(500)
                                                .result("Failed to update schedule with index $index")
                                        } else it.status(400)
                                            .result("Nothing has changed for schedule with index $index")
                                    }
                                }
                            }
                        }
                        get("ExportXLSX") {
                            val xlsxdata = db.Export_Schedulebank_XLSX()
                            if (xlsxdata != null) {
                                it.header(
                                    "Content-Type",
                                    "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
                                )
                                it.header("Content-Disposition", "attachment; filename=\"schedulebank.xlsx\"")
                                it.outputStream().use { out ->
                                    xlsxdata.write(out)
                                }
                            } else {
                                it.status(500).result("Failed to export schedulebank to XLSX")
                            }
                        }
                        post("ImportXLSX") {
                            val uploaded = it.uploadedFile("file")
                            if (uploaded == null) {
                                it.status(400).result("No file uploaded")
                                return@post
                            }
                            try {
                                val xlsx = XSSFWorkbook(uploaded.content())
                                if (db.Import_Schedulebank_XLSX(xlsx)) {
                                    it.result("OK")
                                } else {
                                    it.status(500).result("Failed to import schedulebank from XLSX")
                                }
                            } catch (e: Exception) {
                                it.status(400).result("Invalid XLSX file")
                            }
                        }
                    }
                    path("Log") {
                        get("List/<logdate>/<logfilter>") { get1 ->
                            val logdate = get1.pathParam("logdate")
                            val logfilter = get1.pathParam("logfilter")
                            if (ValidDate(logdate)) {
                                if (ValidString(logfilter)) {
                                    // ada log filter
                                    db.GetLog(logdate, logfilter) {
                                        get1.result(MariaDB.ArrayListtoString(it))
                                    }
                                } else {
                                    db.GetLog(logdate) {
                                        get1.result(MariaDB.ArrayListtoString(it))
                                    }
                                }
                            } else get1.status(400).result("Invalid logdate")
                        }
                        get("ExportXLSX/<logdate>/<logfilter>") { get1 ->
                            val logdate = get1.pathParam("logdate")
                            val logfilter = get1.pathParam("logfilter")
                            if (ValidDate(logdate)) {
                                val xlsxdata = if (ValidString(logfilter)) {
                                    db.Export_Log_XLSX(logdate, logfilter)
                                } else {
                                    db.Export_Log_XLSX(logdate, "")
                                }
                                if (xlsxdata != null) {
                                    get1.header(
                                        "Content-Type",
                                        "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
                                    )
                                    get1.header("Content-Disposition", "attachment; filename=\"log_$logdate.xlsx\"")
                                    get1.outputStream().use { out ->
                                        xlsxdata.write(out)
                                    }
                                } else {
                                    get1.status(500).result("Failed to export log to XLSX")
                                }
                            } else get1.status(400).result("Invalid logdate")
                        }
                    }
                }
            }
        }.start(listenPort)

    }


    fun CheckUsers(ctx: Context) {
        val user = ctx.sessionAttribute<String?>("user")
        if (user == null) {
            ctx.redirect("login.html")
        }
        val foundUser = userlist.find { it.first == user }
        if (foundUser == null) {
            ctx.redirect("login.html")
        }
    }

    fun Stop() {
        app?.stop()

    }
}