package com.jsc.oscm.security.token;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.ProviderNotFoundException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.jsc.oscm.model.SecurityUserInfo;
import com.jsc.oscm.model.ReturnT;

public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter {

    private final AuthenticationManager authenticationManager;
    private final TokenManager jwtTokenManager;

    public TokenLoginFilter(AuthenticationManager authenticationManager, TokenManager tokenManager) {
        this.authenticationManager = authenticationManager;
        this.jwtTokenManager = tokenManager;
        this.setPostOnly(false);
        this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/login"));
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
            throws AuthenticationException {
        // TODO Auto-generated method stub
        String userName = request.getParameter("username");
        String password = request.getParameter("password");
        return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(userName, password, new ArrayList<>()));
    }

    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
                                            Authentication authResult) throws IOException {
        // TODO Auto-generated method stub
        SecurityUserInfo userInfo = (SecurityUserInfo) authResult.getPrincipal();
        String token = jwtTokenManager.createToken(userInfo.getUsername());

        Map<String, String> result = new HashMap<>();
        result.put("username", userInfo.getUsername());
        result.put("token", token);
        ReturnT<Map<String, String>> returnT = new ReturnT<>();
        returnT.code = HttpStatus.OK.value();
        returnT.content = result;

        response.setStatus(HttpStatus.OK.value());
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.writeValue(response.getWriter(), returnT);
    }

    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
                                              AuthenticationException failed) throws IOException {
        // TODO Auto-generated method stub
        response.setStatus(HttpStatus.OK.value());
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);

        ReturnT<Map<String, String>> returnT = new ReturnT<>();
        if (failed instanceof BadCredentialsException) {
            returnT.code = 1;
            returnT.message = failed.getMessage();
        } else if (failed instanceof UsernameNotFoundException) {
            returnT.code = 1;
            returnT.message = failed.getMessage();
        } else if (failed instanceof AuthenticationCredentialsNotFoundException) {
            returnT.code = 1;
            returnT.message = failed.getMessage();
        } else if (failed instanceof ProviderNotFoundException) {
            returnT.code = 1;
            returnT.message = failed.getMessage();
        } else {
            returnT.code = 1;
            returnT.message = failed.getMessage();
        }
        ObjectMapper mapper = new ObjectMapper();
        mapper.writeValue(response.getWriter(), returnT);
    }

}
