package com.bio.bio_backend.global.security;

import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import com.bio.bio_backend.global.dto.ApiResponseDto;
import com.bio.bio_backend.domain.user.member.dto.LoginRequestDto;
import com.bio.bio_backend.domain.user.member.dto.LoginResponseDto;
import com.bio.bio_backend.domain.user.member.dto.MemberDto;
import com.bio.bio_backend.domain.user.member.service.MemberService;
import com.bio.bio_backend.global.constants.ApiResponseCode;
import com.bio.bio_backend.global.utils.JwtUtils;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.env.Environment;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.Objects;

@RequiredArgsConstructor
@Slf4j
public class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

    private final AuthenticationManager authenticationManager;
    private final MemberService memberService;
    private final JwtUtils jwtUtils;
    private final Environment env;

    // 사용자 login 인증 처리
    @SneakyThrows
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
            throws AuthenticationException {

        LoginRequestDto requestDto = new ObjectMapper().readValue(request.getInputStream(), LoginRequestDto.class);

//        UsernamePasswordAuthenticationToken authToken;
        UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(requestDto.getUserId(), requestDto.getPassword());

        /*
        if (req.getLoginLogFlag() == 1) {
            authToken = new UsernamePasswordAuthenticationToken("admin2", "test123!"); // 비밀번호는 실제 비밀번호로 설정해야 함
        } else {
            throw new AuthenticationServiceException("login fail");
        }
         */
        return authenticationManager.authenticate(authToken);
    }

    // 사용자 인증 성공 후 token 발급
    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response,
                                            FilterChain chain, Authentication authResult) throws IOException, ServletException {

        UserDetails userDetails = (UserDetails) authResult.getPrincipal();

        MemberDto member = (MemberDto) userDetails;
        
        String accessToken = jwtUtils.generateToken(member.getUserId(), member.getRole().getValue(),
                Long.parseLong(Objects.requireNonNull(env.getProperty("token.expiration_time_access"))));

        String refreshToken = jwtUtils.generateToken(member.getUserId(), member.getRole().getValue(),
                Long.parseLong(Objects.requireNonNull(env.getProperty("token.expiration_time_refresh"))));
        

        member.setRefreshToken(refreshToken);
        member.setLastLoginAt(LocalDateTime.now());

        memberService.updateRefreshToken(member);

        // Refresh 토큰 쿠키 저장
        Cookie refreshTokenCookie = new Cookie("RefreshToken", refreshToken);
        refreshTokenCookie.setHttpOnly(true);
        refreshTokenCookie.setSecure(false);
        refreshTokenCookie.setPath("/");
        refreshTokenCookie.setMaxAge(Integer.parseInt(env.getProperty("token.expiration_time_refresh")));

        // JWT 토큰 전달
        response.setHeader("Authorization", "Bearer " + accessToken);
//        response.addCookie(refreshTokenCookie);
        response.addHeader("Set-Cookie", 
        	    String.format("%s=%s; HttpOnly; Secure; Path=/; Max-Age=%d; SameSite=None", 
        	    refreshTokenCookie.getName(), 
        	    refreshTokenCookie.getValue(), 
        	    refreshTokenCookie.getMaxAge()));

        SecurityContextHolderStrategy contextHolder = SecurityContextHolder.getContextHolderStrategy();
        SecurityContext context = contextHolder.createEmptyContext();
        context.setAuthentication(authResult);
        contextHolder.setContext(context);

        LoginResponseDto memberData = new LoginResponseDto();
        memberData.setUserId(member.getUserId());
        memberData.setRole(member.getRole().getValue());
        memberData.setLastLoginAt(member.getLastLoginAt());

        // login 성공 메시지 전송
        response.setStatus(HttpStatus.OK.value());
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        new ObjectMapper().writeValue(response.getWriter(),
                ApiResponseDto.success(ApiResponseCode.LOGIN_SUCCESSFUL, memberData));
    }
}
