package com.hclsoftware.sso.kerberos.service;

import com.hclsoftware.sso.kerberos.dto.LoginDto;
import com.hclsoftware.sso.kerberos.dto.ResponseDto;
import com.hclsoftware.sso.kerberos.pojo.LoginPojo;
import com.hclsoftware.sso.kerberos.utils.Serializer;
import com.ibm.as400.access.AS400;
import com.ibm.as400.security.auth.ProfileTokenCredential;
import org.ietf.jgss.GSSException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.kerberos.authentication.KerberosAuthenticationProvider;
import org.springframework.stereotype.Service;

import javax.security.auth.login.LoginException;
import java.beans.PropertyVetoException;
import java.io.IOException;
import java.util.Base64;
import java.util.Optional;

import static com.hclsoftware.sso.kerberos.constants.Constants.*;

@Service
public class AuthService {

    @Autowired
    private IBMiConnectorService ibMiConnectorService;
    @Autowired
    private KerberosAuthenticationProvider kerberosAuthenticationProvider;

    @Value("${app.as400Host}")
    private String as400Host;


    public ResponseDto authenticateUser3(LoginDto loginDto) throws IOException, GSSException {

        Authentication authentication = kerberosAuthenticationProvider.authenticate(new UsernamePasswordAuthenticationToken(loginDto.getUsername(), loginDto.getPassword()));
        SecurityContextHolder.getContext().setAuthentication(authentication);

        ResponseDto  responseDto = ibMiConnectorService.getResponseDtoForIbmIMc();

        LoginPojo loginPojo = LoginPojo.builder()
                .hostSystem(as400Host)
                .userName(loginDto.getUsername())
                .password(loginDto.getPassword().toCharArray())
                .build();
        loginPojoMap.put(responseDto.getToken(), loginPojo);

        return responseDto;

    }


    public ResponseDto refresh(String token) throws IOException, ClassNotFoundException, GSSException {
        ProfileTokenCredential profileTokenCredential = getProfileTokenCredential(token);
        long tokenExpirationTime = System.currentTimeMillis() + profileTokenCredential.getTimeoutInterval();
        if (isTokenExpired(tokenExpirationTime)){
            return reAuthenticateUser(token);
        }
        AS400 as400 = profileTokenCredential.getSystem();
        return new ResponseDto(as400.getSystemName(), as400.getUserId(), token);
    }

    private ResponseDto reAuthenticateUser(String token) throws IOException, GSSException {
        Optional<LoginPojo> loginPojoOptional = Optional.ofNullable(loginPojoMap.remove(token));
        if (loginPojoOptional.isPresent()){
            LoginDto loginDto = LoginDto.builder()
                    .username(loginPojoOptional.get().getUserName())
                    .password(new String(loginPojoOptional.get().getPassword()))
                    .build();
            return authenticateUser3(loginDto);
        }
         return new ResponseDto();

    }

    private static ProfileTokenCredential getProfileTokenCredential(String token) throws IOException, ClassNotFoundException {
        byte[] decode = Base64.getDecoder().decode(token);
        return (ProfileTokenCredential)Serializer.deserialize(decode);
    }

    public boolean isTokenExpired(long tokenExpirationTime) {
        return System.currentTimeMillis() >= tokenExpirationTime;
    }
}
