package com.wonderpush.sdk.remoteconfig;

import com.wonderpush.sdk.SimpleVersion;
import org.json.JSONException;
import org.json.JSONObject;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Date;

public class RemoteConfig {

    public static RemoteConfig with(@Nonnull JSONObject data, @Nonnull String version, @Nonnull Date fetchDate, long maxAge, long minAge) {
        return new RemoteConfig(data, version, fetchDate, maxAge, minAge);
    }

    public static RemoteConfig with(@Nonnull JSONObject data, @Nonnull String version, @Nonnull Date fetchDate, long maxAge) {
        return new RemoteConfig(data, version, fetchDate, maxAge, 0);
    }

    public static RemoteConfig with(@Nonnull JSONObject data, @Nonnull String version, @Nonnull Date fetchDate) {
        return new RemoteConfig(data, version, fetchDate, 0, 0);
    }

    public static RemoteConfig with(@Nonnull JSONObject data, @Nonnull String version) {
        return new RemoteConfig(data, version, DateHelper.now(), 0, 0);
    }

    @Nonnull
    private JSONObject data;
    @Nonnull
    private String version;
    @Nonnull
    private Date fetchDate;
    private long maxAge;
    private long minAge;

    private RemoteConfig(@Nonnull JSONObject data, @Nonnull String version, @Nonnull Date fetchDate, long maxAge, long minAge) {
        this.data = data;
        SimpleVersion simpleVersion = new SimpleVersion(version);
        this.version = simpleVersion.isValid() ? simpleVersion.toString() : version;
        this.fetchDate = fetchDate;
        this.maxAge = maxAge;
        this.minAge = minAge;
    }

    /**
     * Tries to deserializes a remote config from the given string, usually generated by calling toString() on a RemoteConfig object.
     * @param remoteConfigString
     * @return
     */
    public static @Nullable RemoteConfig with(String remoteConfigString) {
        try {
            JSONObject json = new JSONObject(remoteConfigString);
            return RemoteConfig.with(json);
        } catch (JSONException e) {
        }
        return null;
    }

    /**
     * Tries to deserializes a remote config from the given string, usually generated by calling toString() on a RemoteConfig object.
     * @param json
     * @return
     */
    public static @Nullable RemoteConfig with(JSONObject json) {
        try {
            JSONObject data = json.optJSONObject("data");
            String version = json.getString("version");
            Long maxAge = json.optLong("maxAge", json.optLong("cacheTtl", 0));
            Long minAge = json.optLong("minAge", 0);
            Long fetchTime = json.optLong("fetchDate", DateHelper.now().getTime());
            return RemoteConfig.with(data == null ? new JSONObject() : data, version, new Date(fetchTime), maxAge, minAge);
        } catch (JSONException e) {
        }
        return null;
    }

    public boolean hasHigherVersionThan(RemoteConfig other) {
        return compareVersions(version, other.version) > 0;
    }

    public boolean isExpired() {
        return maxAge > 0 && DateHelper.now().getTime() > (fetchDate.getTime() + maxAge);
    }

    /**
     * Compares version1 and version2.
     * @param version1
     * @param version2
     * @return 1 when version1 > version2, -1 when version1 < version2 and 0 when versions are equivalent
     */
    public static int compareVersions(String version1, String version2) {
        SimpleVersion ours = new SimpleVersion(version1);
        SimpleVersion theirs = new SimpleVersion(version2);
        return ours.compareTo(theirs);
    }

    public String getVersion() {
        return version;
    }

    public Date getFetchDate() {
        return fetchDate;
    }

    public long getMaxAge() {
        return maxAge;
    }

    public long getMinAge() {
        return minAge;
    }

    public JSONObject getData() {
        return data;
    }

    @Override
    public String toString() {
        try {
            JSONObject json = new JSONObject();
            json.put("data", data);
            json.put("version", version);
            json.put("fetchDate", fetchDate.getTime());
            json.put("maxAge", maxAge);
            json.put("minAge", minAge);
            return json.toString();
        } catch (JSONException e) {
            return null;
        }
    }

    public boolean hasReachedMinAge() {
        long now = DateHelper.now().getTime();
        long minAgeTime = (fetchDate.getTime() + minAge);
        return minAgeTime <= now;
    }
}

@@ -2596,17 +2596,46 @@
 inAge%22, 
-0
+json.optLong(%22cacheMinAge%22, 0)
 );%0A     

support for alt syntax "cacheMinAge"