package moe.fuqiuluo.shamrock.remote.config

import moe.fuqiuluo.shamrock.helper.ErrorTokenException
import moe.fuqiuluo.shamrock.helper.LogicException
import moe.fuqiuluo.shamrock.helper.ParamsException
import io.ktor.server.application.Application
import io.ktor.server.application.install
import io.ktor.server.plugins.statuspages.StatusPages
import io.ktor.server.request.uri
import io.ktor.server.response.respond
import io.ktor.util.AttributeKey
import kotlinx.serialization.json.JsonElement
import moe.fuqiuluo.shamrock.helper.Level
import moe.fuqiuluo.shamrock.helper.LogCenter
import moe.fuqiuluo.shamrock.remote.structures.CommonResult
import moe.fuqiuluo.shamrock.remote.structures.ErrorCatch
import moe.fuqiuluo.shamrock.remote.structures.Status

val ECHO_KEY = AttributeKey<JsonElement>("echo")

fun Application.statusPages() {
    install(StatusPages) {
        exception<ParamsException> { call, cause ->
            val echo = if (call.attributes.contains(ECHO_KEY)) {
                call.attributes[ECHO_KEY]
            } else null
            call.respond(
                CommonResult(
                status = "failed",
                retcode = Status.BadParam.code,
                data = ErrorCatch(call.request.uri, cause.message ?: ""),
                echo = echo
            )
            )
        }
        exception<LogicException> { call, cause ->
            val echo = if (call.attributes.contains(ECHO_KEY)) {
                call.attributes[ECHO_KEY]
            } else null
            call.respond(
                CommonResult(
                status = "failed",
                retcode = Status.LogicError.code,
                data = ErrorCatch(call.request.uri, cause.message ?: ""),
                echo = echo
            )
            )
        }
        exception<ErrorTokenException> { call, cause ->
            val echo = if (call.attributes.contains(ECHO_KEY)) {
                call.attributes[ECHO_KEY]
            } else null
            call.respond(
                CommonResult(
                status = "failed",
                retcode = Status.ErrorToken.code,
                data = ErrorCatch(call.request.uri, cause.message ?: ""),
                echo = echo
            )
            )
        }
        exception<Throwable> { call, cause ->
            val echo = if (call.attributes.contains(ECHO_KEY)) {
                call.attributes[ECHO_KEY]
            } else null
            LogCenter.log(cause.stackTraceToString(), Level.ERROR)
            call.respond(
                CommonResult(
                status = "failed",
                retcode = Status.InternalHandlerError.code,
                data = ErrorCatch(call.request.uri, cause.message ?: ""),
                echo = echo
            )
            )
        }
    }
}