package web

import codes.Somecodes
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import database.MariaDB
import io.javalin.Javalin
import io.javalin.apibuilder.ApiBuilder.before
import io.javalin.apibuilder.ApiBuilder.get
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.websocket.WsMessageContext
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.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")
                                    }
                                    "getSoundBankList" ->{
                                        println("getSoundBankList command received")
                                        SendReply(wsMessageContext, cmd.command, MariaDB.ArrayListtoString(db.SoundbankList))
                                    }
                                    "getMessageBankList"->{
                                        println("getMessageBankList command received")
                                        SendReply(wsMessageContext, cmd.command, MariaDB.ArrayListtoString(db.MessagebankList))
                                    }
                                    "getLanguageList"->{
                                        println("getLanguageList command received")
                                        SendReply(wsMessageContext, cmd.command, MariaDB.ArrayListtoString(db.LanguageLinkList))
                                    }
                                    "getTimerList"->{
                                        println("getTimerList command received")
                                        SendReply(wsMessageContext, cmd.command, MariaDB.ArrayListtoString(db.SchedulebankList))
                                    }
                                    "getLog" ->{
                                        println("getLog command received")
                                    }
                                    "getSetting" ->{
                                        println("getSetting command received")
                                    }
                                    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) }

                }
            }
        }.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()

    }
}