package com.uca.security;

import com.uca.core.UserCore;
import com.uca.entity.UserEntity;
import com.uca.exceptions.ServiceException;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.mindrot.jbcrypt.BCrypt;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;


public class doLogin {

    private static final String CONFIG_FILE_PATH = "src/com/uca/security/config.properties";
    private static final String TOKEN_CONFIG_KEY = "token";

    private static String getToken() {
        Properties props = new Properties();
        try (FileInputStream in = new FileInputStream(CONFIG_FILE_PATH)) {
            props.load(in);
            return props.getProperty(TOKEN_CONFIG_KEY);
        } catch (IOException e) {
            throw new RuntimeException("Could not load config file", e);
        }
    }

    private static void setToken(String token) {
        Properties props = new Properties();
        try (FileInputStream in = new FileInputStream(CONFIG_FILE_PATH)) {
            props.load(in);
            props.setProperty(TOKEN_CONFIG_KEY, token);
            try (FileOutputStream out = new FileOutputStream(CONFIG_FILE_PATH)) {
                props.store(out, "Config file for doLogin");
            }
        } catch (IOException e) {
            throw new RuntimeException("Could not save config file", e);
        }
    }

    private static String generateNewToken() {
        String newToken = UUID.randomUUID().toString();
        setToken(newToken);
        return newToken;
    }

    public static UserEntity introspect(String token) {
        if (token == null || token.isEmpty()) {
            return null;
        }
        try {
            Claims claims = Jwts.parser().setSigningKey(getToken()).parseClaimsJws(token).getBody();
            UserEntity entity = new UserEntity();
            entity.setIdentifier(claims.get("emitter", String.class));
            entity.setId(claims.get("uuid", Integer.class));
            return entity;
        } catch (Exception e) {
            return null;
        }
    }

    public static String login(UserEntity entity) throws IllegalArgumentException {
        String token = getToken();
        if (token == null || token.isEmpty()) {
            token = generateNewToken();
        }

        if (entity.getIdentifier() == null || entity.getIdentifier().isEmpty()) {
            throw new IllegalArgumentException("name could not be null");
        }
        if (entity.getPassword() == null || entity.getPassword().isEmpty()) {
            throw new IllegalArgumentException("password could not be null");
        }
        UserEntity user;
        try {
            user = UserCore.getByIdentifier(entity.getIdentifier(), true);
        } catch (ServiceException e) {
            throw new IllegalArgumentException("User does not exists.");
        }

        if (!BCrypt.checkpw(entity.getPassword(), user.getPassword())) {
            throw new IllegalArgumentException("Invalid password");
        }

        Map<String, Object> map = new HashMap<>();
        map.put("uuid", user.getId());
        map.put("id", user.getId());
        map.put("emitter", user.getIdentifier());
        Map<String, Object> header = new HashMap<>();
        header.put("kid", user.getId());

        return Jwts.builder()
                .setClaims(map)
                .setId(UUID.randomUUID().toString())
                .setHeader(header)
                .setHeaderParam("kid", user.getId())
                .setSubject(user.getIdentifier())
                // 1 day
                .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 24))
                .signWith(SignatureAlgorithm.HS512, token)
                .compact();
    }
}
