/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
 */

package ee.forgr.capacitor_updater;

import com.getcapacitor.JSObject;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Objects;
import java.util.TimeZone;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;

public class BundleInfo {

    private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");

    public static final String ID_BUILTIN = "builtin";
    public static final String VERSION_UNKNOWN = "unknown";
    public static final String DOWNLOADED_BUILTIN = "1970-01-01T00:00:00.000Z";

    private final String downloaded;
    private final String id;
    private final String version;
    private final String checksum;
    private final BundleStatus status;

    static {
        sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
    }

    public BundleInfo(final BundleInfo source) {
        this(source.id, source.version, source.status, source.downloaded, source.checksum);
    }

    public BundleInfo(final String id, final String version, final BundleStatus status, final Date downloaded, final String checksum) {
        this(id, version, status, sdf.format(downloaded), checksum);
    }

    public BundleInfo(final String id, final String version, final BundleStatus status, final String downloaded, final String checksum) {
        this.downloaded = downloaded.trim();
        this.id = id;
        this.version = version;
        this.checksum = checksum;
        this.status = status;
    }

    public Boolean isBuiltin() {
        return ID_BUILTIN.equals(this.id);
    }

    public Boolean isUnknown() {
        return VERSION_UNKNOWN.equals(this.id);
    }

    public Boolean isErrorStatus() {
        return BundleStatus.ERROR == this.status;
    }

    public Boolean isDeleted() {
        return BundleStatus.DELETED == this.status;
    }

    public boolean isDownloaded() {
        return (!this.isBuiltin() && this.downloaded != null && !this.downloaded.isEmpty() && !this.isDeleted());
    }

    public String getDownloaded() {
        return this.isBuiltin() ? DOWNLOADED_BUILTIN : this.downloaded;
    }

    public BundleInfo setDownloaded(Date downloaded) {
        return new BundleInfo(this.id, this.version, this.status, downloaded, this.checksum);
    }

    public String getChecksum() {
        return this.isBuiltin() ? "" : this.checksum;
    }

    public BundleInfo setChecksum(String checksum) {
        return new BundleInfo(this.id, this.version, this.status, this.downloaded, checksum);
    }

    public String getId() {
        return this.isBuiltin() ? ID_BUILTIN : this.id;
    }

    public BundleInfo setId(String id) {
        return new BundleInfo(id, this.version, this.status, this.downloaded, this.checksum);
    }

    public String getVersionName() {
        return this.version == null ? ID_BUILTIN : this.version;
    }

    public BundleInfo setVersionName(String version) {
        return new BundleInfo(this.id, version, this.status, this.downloaded, this.checksum);
    }

    public BundleStatus getStatus() {
        return this.isBuiltin() ? BundleStatus.SUCCESS : this.status;
    }

    public BundleInfo setStatus(BundleStatus status) {
        return new BundleInfo(this.id, this.version, status, this.downloaded, this.checksum);
    }

    public static BundleInfo fromJSON(final JSObject json) throws JSONException {
        return BundleInfo.fromJSON(json.toString());
    }

    public static BundleInfo fromJSON(final String jsonString) throws JSONException {
        JSONObject json = new JSONObject(new JSONTokener(jsonString));
        return new BundleInfo(
            json.has("id") ? json.getString("id") : "",
            json.has("version") ? json.getString("version") : BundleInfo.VERSION_UNKNOWN,
            json.has("status") ? BundleStatus.fromString(json.getString("status")) : BundleStatus.PENDING,
            json.has("downloaded") ? json.getString("downloaded") : "",
            json.has("checksum") ? json.getString("checksum") : ""
        );
    }

    public JSObject toJSON() {
        final JSObject result = new JSObject();
        result.put("id", this.getId());
        result.put("version", this.getVersionName());
        result.put("downloaded", this.getDownloaded());
        result.put("checksum", this.getChecksum());
        result.put("status", this.getStatus());
        return result;
    }

    @Override
    public boolean equals(final Object o) {
        if (this == o) return true;
        if (!(o instanceof BundleInfo)) return false;
        final BundleInfo that = (BundleInfo) o;
        return this.getId().equals(that.getId());
    }

    @Override
    public int hashCode() {
        return Objects.hash(this.version);
    }

    @Override
    public String toString() {
        return this.toJSON().toString();
    }
}
