package kr.lunaticbum.back.lun.controllers

import com.google.gson.Gson
import jakarta.servlet.http.HttpServletRequest
import jakarta.servlet.http.HttpServletResponse
import kr.lunaticbum.back.lun.configs.GlobalEnvironment
import kr.lunaticbum.back.lun.configs.GlobalEnvironment.Companion.ApiKeyWordKey
import kr.lunaticbum.back.lun.configs.GlobalEnvironment.Companion.EncType11
import kr.lunaticbum.back.lun.configs.GlobalEnvironment.Companion.EncTypeKey
import kr.lunaticbum.back.lun.configs.JwtRule
import kr.lunaticbum.back.lun.model.*
import kr.lunaticbum.back.lun.utils.JwtUtil
import kr.lunaticbum.back.lun.utils.LogService
import kr.lunaticbum.back.lun.utils.extractModelData
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.MediaType
import org.springframework.http.ResponseCookie
import org.springframework.http.ResponseEntity
import org.springframework.security.authentication.AuthenticationManager
import org.springframework.security.core.userdetails.UserDetails
import org.springframework.web.bind.annotation.*
import org.springframework.web.reactive.function.client.WebClient
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.core.Authentication
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.security.web.authentication.RememberMeServices
import org.springframework.security.web.context.HttpSessionSecurityContextRepository
import java.io.File
import java.util.*
import javax.naming.AuthenticationException


@RestController
@RequestMapping("/user")
class UserController {


    @Autowired
    lateinit var globalEvv : GlobalEnvironment

    @Autowired
    lateinit var logService: LogService

    @Autowired
    lateinit var userManager: UserManager

    @GetMapping("join.bs")
    fun hello(httpServletRequest: HttpServletRequest): ResultMV {
        logService.log("onJoin")
        val vm = ResultMV("content/user/join")
//        when(System.currentTimeMillis() % 5L) {
//            0L -> vm.modelMap.put(EncTypeKey,"T4")
//            1L ->    vm.modelMap.put(EncTypeKey,"T3")
//            2L ->    vm.modelMap.put(EncTypeKey,"T2")
//            else -> vm.modelMap.put(EncTypeKey,"T0")
//        }

        val file = File("/")

        logService.log(file.absolutePath)
        vm.modelMap.put(EncTypeKey,EncType11)
        vm.modelMap.put(ApiKeyWordKey,"JOIN")
        return vm
    }

    @GetMapping("login.bs")
    fun userLogin(httpServletRequest: HttpServletRequest): ResultMV {
        logService.log("onJoin")
        val vm = ResultMV("content/user/login")
        vm.modelMap.put(EncTypeKey,EncType11)
        vm.modelMap.put(ApiKeyWordKey,"LOGIN")
        return vm
    }

//    @GetMapping("logout.bs")
//    fun logoutBs(session: HttpSession): ResultMV {
//        session.invalidate(); // 세션 날리기 (로그아웃)
//        return "redirect:/"; // 홈으로 이동
//    }

    @Autowired
    lateinit var authenticationManager: AuthenticationManager


    @ResponseBody
    @PostMapping("login.bjx")
    fun login(httpServletRequest: HttpServletRequest,   @RequestBody jsonString: String) : ResponseEntity<LoginResult> {
        try {

            logService.log(httpServletRequest.requestURI)
            logService.log(jsonString)
            var lResultCode = 0
            var lResultMsg = "Suscces"
            var u : UserDetails? = null
            var user : User? = null
            var tokenData : TokenData? = null
            var remeberMe = false
            var authResult : Authentication? = null
            jsonString.extractModelData { exception, originDataString ->
                if (exception == null) {
                    logService.log("originDataString >>> $originDataString")
                    val target = Gson().fromJson(originDataString, User::class.java) ?: User()
                    try {
                        val authToken = UsernamePasswordAuthenticationToken(target.user_id, target.user_pw)
                        authResult = authenticationManager.authenticate(authToken)  // 인증 시도
                        println("authResult >>>> $authResult")
                        // 인증 성공 시 SecurityContextHolder에 인증 정보 저장
                        SecurityContextHolder.getContext().authentication = authResult

                        // 인증 정보가 담긴 SecurityContext를 세션에 저장
                        val session = httpServletRequest.getSession(true)
                        session.setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, SecurityContextHolder.getContext())
                        println("authResult >>>> LOGIN OK")

                        val principal = authResult?.principal
                        if (principal is UserDetails) {
                            val username = principal.username

                            val session = httpServletRequest.getSession(true)
                            session.setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, SecurityContextHolder.getContext())
                            remeberMe = target.remeberMe ?: false
                        } else {
                            lResultMsg = "is wrong infomation id or passord"
                            lResultCode = 7100
                        }
                    } catch (e: Exception) {
                        e.printStackTrace()
                    }
                } else {
                    exception.printStackTrace()
                    lResultMsg = exception.message ?: "unknown exception"
                    lResultCode = 7999
                }
            }
            val responce = ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).headers {

            }.body(LoginResult().apply {
                this.isOk = lResultCode == 0
                this.resultCode = lResultCode
                this.resultMsg = lResultMsg
                this.token = if (remeberMe) "OK" else ""
            }).apply {

            }

            return responce
        }catch (e: Exception){
            return ResponseEntity.internalServerError().contentType(MediaType.APPLICATION_JSON).headers {

            }.body(LoginResult().apply {
                this.isOk = false
                this.resultCode = -999
                this.resultMsg = e.message ?: "unknown exception"
                this.token = ""
                this.refresh = ""
            }).apply {


            }
        }
    }


    private fun setTokenToCookie(tokenPrefix: String, token: String, maxAgeSeconds: Long): ResponseCookie {
        return ResponseCookie.from(tokenPrefix, token)
            .path("/")
            .maxAge(maxAgeSeconds)
            .httpOnly(true)
            .sameSite("None")
            .secure(true)
            .build()
    }

    @ResponseBody
    @PostMapping("logout.bjx")
    fun logout(httpServletRequest: HttpServletRequest) : ResponseEntity<ResponceResult> {
        val responce = ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(ResponceResult().apply {

        })
        return responce
    }

    @ResponseBody
    @PostMapping("joinUser.bjx")
    fun joinUser(httpServletRequest: HttpServletRequest, @RequestBody jsonString: String) : ResponseEntity<ResponceResult> {
        logService.log("${httpServletRequest.requestURI}")
        logService.log(jsonString)
        var lResultCode = 0
        var lResultMsg = "Suscces"
        var u : User? = null
        jsonString.extractModelData { exception, s ->
            if (exception == null) {
                val user = Gson().fromJson(s, User::class.java) ?: User()
                if (user.checkValid() == false) {
                    lResultCode = 7009
                    lResultMsg = "user insert Fail  Reason : Not Correct Data"
                }else if (userManager.findById(user!!.user_id!!)?.block() != null) {
                    lResultCode = 7001
                    lResultMsg = "user insert Fail  Reason : already has Same Id"
                }  else {
                    u = userManager.save(user).block()
                }
            } else {
                exception.printStackTrace()
                lResultMsg = exception.message ?: "unknown exception"
                lResultCode = 7999
            }
        }
        val responce = ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(ResponceResult().apply {
            this.resultCode = lResultCode
            this.resultMsg = lResultMsg
        })
        return responce
    }

    @ResponseBody
    @GetMapping("test/{path}")
    fun test(@PathVariable path : String): String {
        logService.log("path >>> $path")
        val client = WebClient.create()
        return client.get()
            .uri("https://api.telegram.org/${globalEvv.telegramBotKey}/sendMessage?chat_id=${globalEvv.telegramMyId}&text=${path}")
            .retrieve()
            .bodyToMono(String::class.java).block() ?: "FAIL"
    }
}