/*-
 * ~~~~~~licensing~~~~~~
 * artifact-management
 * ==========
 * Copyright (C) 2020 - 2025 EmDev LLC
 * ==========
 * You may not use this file except in accordance with the License Terms of the Copyright
 * Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
 * rights to the Software and any copies are the property of the Copyright Holder. Unless
 * it is explicitly allowed the Copyright Holder, the User is prohibited from using the
 * Software for commercial purposes to provide services to third parties.
 * 
 * The Copyright Holder hereby declares that the Software is provided on an "AS IS".
 * Under no circumstances does the Copyright Holder guarantee or promise that the
 * Software provided by him will be suitable or not suitable for the specific purposes
 * of the User, that the Software will meet all commercial and personal subjective
 * expectations of the User, that the Software will work properly, without technical
 * errors, quickly and uninterruptedly.
 * 
 * Under no circumstances shall the Copyright Holder or its Affiliates is not liable
 * to the User for any direct or indirect losses of the User, his expenses or actual
 * damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
 * or damage to data, property, etc.
 * ~~~~~~/licensing~~~~~~
 */
package ru.entaxy.platform.core.artifact;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.HashSet;
import java.util.Set;

import org.apache.camel.tooling.model.Strings;

import ru.entaxy.platform.base.support.CommonUtils;

public class ArtifactCoordinates {

    public static final ArtifactCoordinates EMPTY = new ArtifactCoordinates();

    public static final String DEFAULT_VERSION = "1.0.0";

    public static final String DEFAULT_TYPE = "jar";

    public static final String SNAPSHOT_QUALIFIER = "SNAPSHOT";

    // x.y.z[-qualifier]
    public static final String VERSION_POLICY_CLEAR = "";
    // x.y.z-timestamp
    public static final String VERSION_POLICY_TIMESTAMPED = "timestamped";
    // x.y.z-yyMMddHHmmss
    public static final String VERSION_POLICY_DATED = "dated";
    // x.yyMMdd.HHmmss[-qualifier]
    public static final String VERSION_POLICY_DATED_EMBEDDED = "dated-embedded";

    public static ArtifactCoordinates fromUrl(String url) {
        if (!CommonUtils.isValid(url))
            return null;
        ArtifactCoordinates result = new ArtifactCoordinates();

        String current = url;
        // trim protocol
        int index = url.lastIndexOf(':');
        if (index >= 0)
            current = current.substring(index + 1);

        String[] fragments = current.split("/");
        if (fragments.length < 2)
            return null;

        result.groupId(fragments[0]);
        result.artifactId(fragments[1]);

        // split version on version itself and qualifier
        if (fragments.length > 2) {
            int ind = fragments[2].indexOf('-');
            if (ind > 0) {
                result.version(fragments[2].substring(0, ind));
                if (fragments[2].length() > ind + 1)
                    result.qualifier(fragments[2].substring(ind + 1));
            } else {
                result.version(fragments[2]);
            }
        }

        if (fragments.length > 3)
            result.type(fragments[3]);

        if (fragments.length > 4)
            result.classifier(fragments[4]);

        return result;
    }

    protected String groupId;
    protected String artifactId;
    protected String version = "1.0";
    protected String type;
    protected String classifier;

    protected String versionPolicy = VERSION_POLICY_CLEAR;

    protected String versionQualifier = "";

    protected String timestamp = "";

    protected Calendar calendar = null;

    protected boolean isSnapshot = false;

    protected Set<String> allowedPolicies = new HashSet<>() {
        /**
        * 
        */
        private static final long serialVersionUID = 1L;

        {
            add(VERSION_POLICY_CLEAR);
            add(VERSION_POLICY_DATED);
            add(VERSION_POLICY_DATED_EMBEDDED);
            add(VERSION_POLICY_TIMESTAMPED);
        }
    };

    public ArtifactCoordinates groupId(String groupId) {
        setGroupId(groupId);
        return this;
    }

    public ArtifactCoordinates artifactId(String artifactId) {
        setArtifactId(artifactId);
        return this;
    }

    public ArtifactCoordinates versionPolicy(String versionPolicy) {
        if (this.allowedPolicies.contains(versionPolicy))
            this.versionPolicy = versionPolicy;
        return this;
    }

    public ArtifactCoordinates version(String version) {
        this.versionQualifier = "";
        setVersion(version);
        return this;
    }

    public ArtifactCoordinates timestampedVersion(String version) {
        this.version(version);
        this.timestamped();
        // versionQualifier = "-" + Calendar.getInstance().getTimeInMillis();
        return this;
    }

    public ArtifactCoordinates timestamp(String timestamp) {
        this.timestamp = timestamp;
        return this;
    }

    public ArtifactCoordinates timestamped() {
        return timestamped(Calendar.getInstance().getTimeInMillis() + "");
    }

    public ArtifactCoordinates timestamped(String timestamp) {
        if (CommonUtils.isValid(timestamp)) {
            this.timestamp = timestamp;
            this.versionPolicy(VERSION_POLICY_TIMESTAMPED);
        } else {
            this.timestamp = "";
            this.versionPolicy(VERSION_POLICY_CLEAR);
        }
        return this;
    }

    public ArtifactCoordinates datedVersion(String version) {
        this.version(version);
        this.dated();
        // versionQualifier = "-" + Calendar.getInstance().getTimeInMillis();
        return this;
    }

    public ArtifactCoordinates dated() {
        this.calendar = Calendar.getInstance();
        versionPolicy(VERSION_POLICY_DATED);
        return this;
    }

    public ArtifactCoordinates datedEmbeddedVersion(String version) {
        this.version(version);
        this.datedEmbedded();
        return this;
    }

    public ArtifactCoordinates datedEmbedded() {
        this.calendar = Calendar.getInstance();
        versionPolicy(VERSION_POLICY_DATED_EMBEDDED);
        return this;
    }

    protected String getResultQualifier() {
        if (isSnapshot)
            return "-" + SNAPSHOT_QUALIFIER;
        if (CommonUtils.isValid(this.versionQualifier))
            return "-" + this.versionQualifier;
        return "";
    }

    protected String calculateFinalVersion() {
        if (VERSION_POLICY_TIMESTAMPED.equals(this.versionPolicy)) {
            if (!CommonUtils.isValid(this.timestamp))
                this.timestamp = Calendar.getInstance().getTimeInMillis() + "";
            return this.version + "-" + this.timestamp;
        }
        if (VERSION_POLICY_DATED.equals(this.versionPolicy)) {
            prepareCalendar();
            return this.version + "-" + ((new SimpleDateFormat("yyMMddHHmmss")).format(this.calendar.getTime()));
        }
        if (VERSION_POLICY_DATED_EMBEDDED.equals(this.versionPolicy)) {
            prepareCalendar();
            return this.version.split("\\.")[0]
                    + "."
                    + ((new SimpleDateFormat("yyMMdd.HHmmss")).format(this.calendar.getTime()))
                    + getResultQualifier();
        }
        return this.version + this.getResultQualifier();
    }

    protected void prepareCalendar() {
        if (this.calendar == null)
            this.calendar = Calendar.getInstance();
        if (CommonUtils.isValid(this.timestamp)) {
            try {
                this.calendar.setTimeInMillis(Long.parseLong(this.timestamp));
            } catch (Exception e) {
                // NOOP
            }
        }
    }

    public ArtifactCoordinates type(String type) {
        setType(type);
        return this;
    }

    public ArtifactCoordinates qualifier(String qualifier) {
        if (CommonUtils.isValid(qualifier))
            this.versionQualifier = qualifier;
        else
            this.versionQualifier = "";
        return this;
    }

    public ArtifactCoordinates classifier(String classifier) {
        setClassifier(classifier);
        return this;
    }

    public ArtifactCoordinates set(ArtifactCoordinates newCoordinates) {
        groupId(newCoordinates.getGroupId())
                .artifactId(newCoordinates.getArtifactId())
                .version(newCoordinates.getVersion())
                .type(newCoordinates.getType())
                .classifier(newCoordinates.getClassifier());
        return this;
    }

    public ArtifactCoordinates update(ArtifactCoordinates newCoordinates) {
        if (null != newCoordinates.getGroupId())
            groupId(newCoordinates.getGroupId());
        if (null != newCoordinates.getArtifactId())
            artifactId(newCoordinates.getArtifactId());
        if (null != newCoordinates.getVersion())
            version(newCoordinates.getVersion());
        if (null != newCoordinates.getType())
            type(newCoordinates.getType());
        if (null != newCoordinates.getClassifier())
            classifier(newCoordinates.getClassifier());
        return this;
    }

    public boolean isSnapshot() {
        return this.isSnapshot || SNAPSHOT_QUALIFIER.equals(this.versionQualifier);
    }

    public void setSnapshot(boolean isSnapshot) {
        this.isSnapshot = isSnapshot;
    }

    public String getGroupId() {
        return groupId;
    }

    public void setGroupId(String groupId) {
        this.groupId = groupId;
    }

    public String getArtifactId() {
        return artifactId;
    }

    public void setArtifactId(String artifactId) {
        this.artifactId = artifactId;
    }

    public String getVersion() {
        return this.calculateFinalVersion();
    }

    public void setVersion(String version) {
        if (!CommonUtils.isValid(version))
            this.version = DEFAULT_VERSION;
        else {
            String[] splitted = version.split("\\.");
            String[] splittedDefault = DEFAULT_VERSION.split("\\.");

            String result = "";
            for (int i = 0; i < splittedDefault.length; i++) {
                if (i != 0)
                    result += ".";
                if ((splitted.length >= i + 1) && CommonUtils.isValid(splitted[i]))
                    result += splitted[i];
                else
                    result += splittedDefault[i];
            }

            this.version = result;
        }
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getClassifier() {
        return classifier;
    }

    public void setClassifier(String classifier) {
        this.classifier = classifier;
    }

    public String getVersionPolicy() {
        return versionPolicy;
    }

    public void setVersionPolicy(String versionPolicy) {
        this.versionPolicy(versionPolicy);
    }

    public String toAssetName() {
        String result = getArtifactId().concat("-").concat(getVersion());
        if (CommonUtils.isValid(getClassifier()))
            result = result.concat("-").concat(getClassifier());
        result = result.concat(".").concat(CommonUtils.getValid(getType(), DEFAULT_TYPE));
        return result;
    }

    public String toRepositoryPath() {
        return String.format("%s/%s/%s/%s", getGroupId().replace('.', '/'), getArtifactId(), getVersion(),
                toAssetName());
    }

    public String toMavenString() {
        return toString();
    }


    @Override
    public String toString() {
        String result = String.format("%s/%s/%s", getGroupId(), getArtifactId(), getVersion());
        if (!Strings.isNullOrEmpty(type)) {
            result += "/" + type;
            if (!Strings.isNullOrEmpty(classifier))
                result += "/" + classifier;
        }
        return result;
    }

}
