package dp.kotul.apigateway.filter.pre

import com.netflix.zuul.ZuulFilter
import com.netflix.zuul.context.RequestContext
import dp.kotul.jwt.JwtParser
import dp.kotul.starter.filter.AUTHORIZATION_HEADER
import dp.kotul.starter.filter.RequestCorrelation
import io.jsonwebtoken.JwtException
import org.slf4j.Logger
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE
import org.springframework.stereotype.Component
import javax.servlet.http.HttpServletResponse

const val BEARER_PREFIX = "Bearer "

@Component
class AuthenticationFilter(val jwtParser: JwtParser, val log: Logger) : ZuulFilter() {

    override fun filterType(): String {
        return PRE_TYPE
    }

    override fun filterOrder(): Int {
        return 1
    }

    override fun shouldFilter(): Boolean {
        return true
    }

    override fun run(): Any? {
        val ctx = RequestContext.getCurrentContext()
        val request = ctx.request

        log.info(String.format("%s request to %s", request.method, request.requestURL.toString()))

        // check JWT in authorization header
        val authorizationHeader = request.getHeader(AUTHORIZATION_HEADER)
        if (authorizationHeader != null && authorizationHeader.startsWith(BEARER_PREFIX)) {
            val user = jwtParser.verifyBearerAndGetNullableUser(authorizationHeader)

            if (user == null) {
                setUnauthorized(ctx)
                return null
            }

            log.info("Found valid jwt token in header: usrId=${user.usrId}, comId=${user.comId}")
            ctx.addZuulRequestHeader(RequestCorrelation.CORRELATION_ID_HEADER, RequestCorrelation.getId())
            return null
        } else {
            throw JwtException("No valid authorization header")
        }
    }

    private fun setUnauthorized(ctx: RequestContext) {
        log.info("Sending response 401")
        ctx.responseStatusCode = HttpServletResponse.SC_UNAUTHORIZED
        ctx.setSendZuulResponse(false)
    }
}
