package com.authy.api;

import com.authy.AuthyException;
import org.json.JSONException;
import org.json.JSONObject;
import sun.net.www.protocol.http.HttpURLConnection;

import java.util.HashMap;
import java.util.Map;

/**
 * @author Julian Camargo
 */
public class Tokens extends Resource {
    public static final String TOKEN_VERIFICATION_PATH = "/protected/json/verify/";

    public Tokens(String uri, String key) {
        super(uri, key);
    }

    public Tokens(String uri, String key, boolean testFlag) {
        super(uri, key, testFlag);
    }

    public Token verify(int userId, String token) throws AuthyException {
        return verify(userId, token, null);
    }

    public Token verify(int userId, String token, Map<String, String> options) throws AuthyException {
        InternalToken internalToken = new InternalToken();
        internalToken.setOption(options);

        StringBuilder path = new StringBuilder(TOKEN_VERIFICATION_PATH);
        validateToken(token);
        path.append(token).append('/');
        path.append(userId);

        final Response response = this.get(path.toString(), internalToken);
        return tokenFromJson(response.getStatus(), response.getBody());
    }

    private Token tokenFromJson(int status, String content) throws AuthyException {
        if (status == 200) {
            try {
                JSONObject tokenJSON = new JSONObject(content);
                String message = tokenJSON.optString("message");
                return new Token(status, content, message);

            } catch (JSONException e) {
                throw new AuthyException("Invalid response from server", e, status);
            }
        }

        final Error error = errorFromJson(content);
        throw new AuthyException("Invalid token", status, error.getCode());
    }

    private void validateToken(String token) throws AuthyException {
        int len = token.length();
        if (!isInteger(token)) {
            throw new AuthyException("Invalid Token. Only digits accepted.", HttpURLConnection.HTTP_BAD_REQUEST,
                    Error.Code.TOKEN_INVALID);
        }
        if (len < 6 || len > 10) {
            throw new AuthyException("Invalid Token. Unexpected length.", HttpURLConnection.HTTP_BAD_REQUEST,
                    Error.Code.TOKEN_INVALID);
        }
    }

    private boolean isInteger(String s) {
        try {
            Long.parseLong(s);
        } catch (NumberFormatException e) {
            return false;
        }
        return true;
    }

    class InternalToken implements Formattable {
        Map<String, String> options;

        InternalToken() {
            options = new HashMap<>();
        }

        void setOption(Map<String, String> options) {
            if (options != null) {
                this.options = options;
            }
        }

        public String toXML() {
            return null;
        }

        public Map<String, String> toMap() {
            if (!options.containsKey("force")) {
                options.put("force", "true");
            }

            return options;
        }
    }
}