package za.org.grassroot.webapp.controller.rest;

import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import za.org.grassroot.webapp.enums.RestMessage;
import za.org.grassroot.webapp.model.rest.wrappers.ResponseWrapper;
import za.org.grassroot.webapp.util.RestUtil;

import javax.crypto.KeyGenerator;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Date;

@RestController
@RequestMapping("/auth")
public class AuthenticationController {

    private static  Key key = null;

    @RequestMapping(value = "/login", method = RequestMethod.GET)
    public ResponseEntity<ResponseWrapper> login(@RequestParam("phoneNumber")String phoneNumber,
                                                 @RequestParam("password")String password,
                                                 @RequestParam("clientType") String clientType) {

        //authenticate user before issuing token
        try {

            //TODO: authenticate user before issuing token

            // Generate a token for the user
            String token = generateToken(phoneNumber);

            // Return the token on the response
            return RestUtil.okayResponseWithData(RestMessage.LOGIN_SUCCESS, token);

        } catch (Exception e) {
            return RestUtil.errorResponse(HttpStatus.UNAUTHORIZED, RestMessage.INVALID_OTP);
        }

    }

    @RequestMapping(value = "/validateToken", method = RequestMethod.GET)
    public ResponseEntity<ResponseWrapper> validateToken(@RequestParam("token")String token) {
        try {
            Jwts.parser().setSigningKey(getKey()).parse(token);
            return RestUtil.messageOkayResponse(RestMessage.TOKEN_STILL_VALID);
        }
         catch (ExpiredJwtException e) {
             return RestUtil.errorResponse(HttpStatus.EXPECTATION_FAILED, RestMessage.TOKEN_EXPIRED);
         }
        catch (Exception e) {
            return RestUtil.errorResponse(HttpStatus.EXPECTATION_FAILED, RestMessage.INVALID_TOKEN);
        }

    }

    private String generateToken(String phoneNumber) throws NoSuchAlgorithmException {
        Key key = getKey();
        Instant now = Instant.now();
        Instant exp = now.plus(1L, ChronoUnit.MINUTES);
        String jwtToken = Jwts.builder()
                .setSubject(phoneNumber)
                .setIssuedAt(new Date())
                .setExpiration(Date.from(exp))
                .signWith(SignatureAlgorithm.HS512, key)
                .compact();
        return jwtToken;
    }

    private static Key getKey() throws NoSuchAlgorithmException {
        if(key == null) {
            key = KeyGenerator.getInstance("AES").generateKey();
        }
        return key;
    }
}

@@ -159,16 +159,79 @@
 orithm;%0A
+import org.springframework.beans.factory.annotation.Autowired;%0A
 import o
@@ -559,24 +559,89 @@
 Controller;%0A
+import za.org.grassroot.integration.keyprovider.KeyPairProvider;%0A
 import za.or
@@ -808,29 +808,42 @@
 java
-x.crypto.KeyGenerator
+.security.NoSuchAlgorithmException
 ;%0Aim
@@ -861,16 +861,23 @@
 ecurity.
+Private
 Key;%0Aimp
@@ -898,32 +898,17 @@
 ity.
-NoSuchAlgorithmException
+PublicKey
 ;%0Aim
@@ -1083,38 +1083,62 @@
     
-private static  Key key = null
+@Autowired%0A    private KeyPairProvider keyPairProvider
 ;%0A%0A 
@@ -1871,32 +1871,65 @@
 (Exception e) %7B%0A
+            e.printStackTrace();%0A
             retu
@@ -2249,16 +2249,25 @@
 gKey(get
+JWTPublic
 Key()).p
@@ -2763,36 +2763,8 @@
 n %7B%0A
-        Key key = getKey();%0A
     
@@ -2828,16 +2828,17 @@
 w.plus(1
+0
 L, Chron
@@ -3072,18 +3072,33 @@
 thm.
-HS512, key
+RS256, getJWTPrivateKey()
 )%0A  
@@ -3171,181 +3171,200 @@
 ate 
-stat
+Publ
 ic
- 
 Key get
-Key() throws NoSuchAlgorithmException %7B%0A        if(key == null) %7B
+JWTPublicKey() %7B%0A        return keyPairProvider.getJWTKey().getPublic();
 %0A    
+%7D%0A%0A
     
-    key = KeyGenerator.getInstance(%22AES%22).generateKey();%0A        %7D%0A        return key
+private PrivateKey getJWTPrivateKey() %7B%0A        return keyPairProvider.getJWTKey().getPrivate()
 ;%0A  

Use KeyPair Provider in authentication controller