package kr.lunaticbum.back.lun.configs

import com.fasterxml.jackson.databind.ObjectMapper
import jakarta.servlet.http.HttpServletRequest
import jakarta.servlet.http.HttpServletResponse
import kr.lunaticbum.back.lun.model.UserManager
import kr.lunaticbum.back.lun.utils.LogService
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.http.HttpMethod
import org.springframework.http.HttpStatus
import org.springframework.http.MediaType
import org.springframework.security.access.AccessDeniedException
import org.springframework.security.authentication.AuthenticationManager
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer
import org.springframework.security.config.http.SessionCreationPolicy
import org.springframework.security.core.AuthenticationException
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
import org.springframework.security.web.AuthenticationEntryPoint
import org.springframework.security.web.SecurityFilterChain
import org.springframework.security.web.access.AccessDeniedHandler
import org.springframework.web.ErrorResponse


@Configuration
@EnableWebSecurity
class SecurityConfig(
    private val userManager: UserManager,
    private val bCryptPasswordEncoder: BCryptPasswordEncoder
) {
    @Autowired
    lateinit var logService: LogService

    @Bean
    fun webSecurityCustomizer(): WebSecurityCustomizer {
        return WebSecurityCustomizer { web ->
            web.ignoring().requestMatchers("/blog/post/images/**")
        }
    }

    @Bean
    fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http.csrf { csrf ->
            csrf.ignoringRequestMatchers(
                "/user/login.bjx", "/user/joinUser.bjx","/tlg/repotToMe.bjx",
                "/blog/post/imageUpload.bjx", "/blog/post.bjx",
                "/blog/post/images/**"
            ) // 여기 예외 추가
        }.authorizeHttpRequests { auth ->
            auth
                .requestMatchers(
                    "/",
                    "/home.bs",
                    "/bums/where.bs" ,
                    "/tlg/repotToMe.bjx",
                    "/user/login.bs", "/user/signup.bs","/user/login.bjx",
                    "/blog/viewer/**" , "/blog/posts" , "/blog/rankOfViews.bjx","/blog/recentOfPost.bjx",
//                    "/blog/post/imageUpload.bjx",
                    "/blog/post/images/**",
                    "/css/**", "/js/**", "/images/**", "/webjars/**", "/assets/**").permitAll()
                .anyRequest().authenticated()
        }.formLogin { form ->
            form.loginPage("/user/login.bs")
                .defaultSuccessUrl("/", true)
                .permitAll()
        }.rememberMe { rememberMe ->
            rememberMe
                .key("BsTs*!12@")  // 보통 안전한 키 지정
                .tokenValiditySeconds(60 * 60 * 24 * 7) // 7일간 유효
                .userDetailsService(userManager)  // 사용자 정보 서비스 지정
        }.logout { logout ->
            logout.logoutUrl("/user/logout.bs").logoutSuccessUrl("/").permitAll()
        }
        return http.build()
    }

    @Bean
    fun authenticationManager(http: HttpSecurity): AuthenticationManager {
        val authenticationManagerBuilder = http.getSharedObject(AuthenticationManagerBuilder::class.java)
        authenticationManagerBuilder
            .userDetailsService(userManager)
            .passwordEncoder(bCryptPasswordEncoder)
        return authenticationManagerBuilder.build()  // .and() 없이 직접 build() 호출
    }
//    @Bean
//    fun filterChain(http: HttpSecurity): SecurityFilterChain {
//
//        http.csrf {
//            it.ignoringRequestMatchers("/user/joinUser.bjx").disable()
//        }
//        http.cors { it.disable() }
//        http.headers {
//            it.frameOptions { frameOptionsConfig ->
//                frameOptionsConfig.disable()
//            }
//        }
//
//        http.authorizeHttpRequests {
//            logService.log(it.toString())
//            it.requestMatchers(HttpMethod.POST,"/user/**").permitAll()
//            it.requestMatchers("/blog/viewer/**").permitAll()
//            it.anyRequest().permitAll()
//        }
//        http.sessionManagement {
//            it.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
//        }
//            .exceptionHandling { it ->
//                it.authenticationEntryPoint(unauthorizedEntryPoint)
//                    .accessDeniedHandler(accessDeniedHandler)
//            }
////            .formLogin { formLogin ->
////                formLogin
////                    .loginPage("/user/join")
////////                    .usernameParameter("username")
////////                    .passwordParameter("password")
////                    .loginProcessingUrl("/user/joinUser.api")
////                    .defaultSuccessUrl("/", true)
////            }
//
//        return http.build()
//    }

    private val unauthorizedEntryPoint =
        AuthenticationEntryPoint { request: HttpServletRequest?, response: HttpServletResponse, authException: AuthenticationException? ->
            val fail: ErrorResponse = ErrorResponse.create( Throwable("아직 못들어와"),
                HttpStatus.UNAUTHORIZED, "Spring security unauthorized..."
            )
            response.status = HttpStatus.UNAUTHORIZED.value()
            val json = ObjectMapper().writeValueAsString(fail)
            response.contentType = MediaType.APPLICATION_JSON_VALUE
            val writer = response.writer
            writer.write(json)
            writer.flush()
        }

    private val accessDeniedHandler =
        AccessDeniedHandler { request: HttpServletRequest?, response: HttpServletResponse, accessDeniedException: AccessDeniedException? ->
            val fail: ErrorResponse = ErrorResponse.create( Throwable("아직 못들어와"),
                HttpStatus.FORBIDDEN, "Spring security forbidden..."
            )
            response.status = HttpStatus.FORBIDDEN.value()
            val json = ObjectMapper().writeValueAsString(fail)
            response.contentType = MediaType.APPLICATION_JSON_VALUE
            val writer = response.writer
            writer.write(json)
            writer.flush()
        }

    @Bean
    fun bCryptPasswordEncoder(): BCryptPasswordEncoder {
        return BCryptPasswordEncoder()
    }
}