package inn.ocsf.bee.freigeld.serve

import io.jsonwebtoken.ExpiredJwtException
import org.springframework.context.annotation.Configuration
import org.springframework.messaging.Message
import org.springframework.messaging.MessageChannel
import org.springframework.messaging.simp.config.ChannelRegistration
import org.springframework.messaging.simp.config.MessageBrokerRegistry
import org.springframework.messaging.simp.stomp.StompCommand
import org.springframework.messaging.simp.stomp.StompHeaderAccessor
import org.springframework.messaging.support.ChannelInterceptor
import org.springframework.messaging.support.MessageHeaderAccessor
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.core.Authentication
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker
import org.springframework.web.socket.config.annotation.StompEndpointRegistry
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer
import javax.inject.Inject

@Configuration
@EnableWebSocketMessageBroker
class WebSocket : WebSocketMessageBrokerConfigurer {

    @Inject
    private lateinit var jwtTokenUtil: JwtTokenUtil

    @Inject
    private lateinit var jwtUserDetailsService: JwtUserDetailsService

    override fun configureMessageBroker(registry: MessageBrokerRegistry) {
        registry.enableSimpleBroker("/topic")
        registry.setApplicationDestinationPrefixes("/app")
        registry.setUserDestinationPrefix("/user")
    }

    override fun registerStompEndpoints(registry: StompEndpointRegistry) {
        registry.addEndpoint("/ws")
    }

    override fun configureClientInboundChannel(registration: ChannelRegistration) {
        registration.interceptors(object : ChannelInterceptor {
            override fun preSend(message: Message<*>, channel: MessageChannel): Message<*>? {
                val accessor: StompHeaderAccessor? = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor::class.java)
                if (accessor != null && StompCommand.CONNECT.equals(accessor.command)) {
                    var usernamePasswordAuthenticationToken: Authentication? = null
                    val jwtToken = accessor.passcode
                    var username: String? = null
                    try {
                        username = jwtTokenUtil.getUsernameFromToken(jwtToken)
                    } catch (e: IllegalArgumentException) {
                        //System.out.println("Unable to get JWT Token")
                    } catch (e: ExpiredJwtException) {
                        //System.out.println("JWT Token has expired")
                    }
                    if (username != null) {
                        val userDetails = jwtUserDetailsService.loadUserByUsername(username)
                        usernamePasswordAuthenticationToken = UsernamePasswordAuthenticationToken(userDetails, null, userDetails.authorities)
                    }

                    if (usernamePasswordAuthenticationToken == null) throw IllegalArgumentException("where is my token, bitch?")
                    accessor.user = usernamePasswordAuthenticationToken
                }
                return message
            }
        })
    }
}