package com.rera.mss.controller

import com.rera.mss.model.Name
import com.rera.mss.model.Role
import com.rera.mss.model.User
import com.rera.mss.payload.ApiResponse
import com.rera.mss.payload.JwtAuthenticationResponse
import com.rera.mss.payload.LoginRequest
import com.rera.mss.payload.SignUpRequest
import com.rera.mss.repository.RoleRepository
import com.rera.mss.repository.UserRepository
import com.rera.mss.security.JwtTokenProvider
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.security.authentication.AuthenticationManager
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.security.crypto.password.PasswordEncoder
import org.springframework.web.bind.annotation.*
import org.springframework.web.servlet.support.ServletUriComponentsBuilder
import java.net.URI
import javax.validation.Valid

@RestController
@RequestMapping("/api/auth")
class AuthController(
        private val authenticationManager: AuthenticationManager,
        private val userRepository: UserRepository,
        private val roleRepository: RoleRepository,
        private val passwordEncoder: PasswordEncoder,
        private val tokenProvider: JwtTokenProvider
) {
    @PostMapping("/signin")
    fun authenticateUser(
            @Valid
            @RequestBody
            loginRequest: LoginRequest
    ): ResponseEntity<JwtAuthenticationResponse> {

        val authentication = authenticationManager.authenticate(
                UsernamePasswordAuthenticationToken(loginRequest.username, loginRequest.password)
        )
        SecurityContextHolder.getContext().authentication = authentication
        val jwt: String = tokenProvider.generateToken(authentication)
        return ResponseEntity.ok(JwtAuthenticationResponse(jwt))
    }

    @PostMapping("/signup")
    fun registerUser(
            @Valid
            @RequestBody
            signUpRequest: SignUpRequest
    ): ResponseEntity<ApiResponse> {

        if (userRepository.existsByUsername(signUpRequest.username)) {
            return ResponseEntity(ApiResponse(false, "Username is already taken."), HttpStatus.BAD_REQUEST)
        }
        if (userRepository.existsByEmail(signUpRequest.email)) {
            return ResponseEntity(ApiResponse(false, "Email is already taken."), HttpStatus.BAD_REQUEST)
        }

        val user = User(
                username = signUpRequest.username,
                password = passwordEncoder.encode(signUpRequest.password),
                email = signUpRequest.email,
                firstName = signUpRequest.firstName,
                lastName = signUpRequest.lastName
        )

        val role: Role = roleRepository.findByName(Name.ROLE_USER) ?: throw Exception("User Role not set.")

        user.addRole(role)

        val result: User = userRepository.save(user)

        val location: URI = ServletUriComponentsBuilder
                .fromCurrentContextPath().path("/api/users/{username}")
                .buildAndExpand(result.username).toUri()
        return ResponseEntity.created(location).body(ApiResponse(true, "User registered successfully."))

    }
}