/*-
 * ~~~~~~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.repository.impl;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.felix.utils.properties.TypedProperties;
import org.apache.karaf.config.core.ConfigRepository;
import org.osgi.framework.InvalidSyntaxException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ru.entaxy.platform.base.support.osgi.OSGIUtils;
import ru.entaxy.platform.core.artifact.repository.ArtifactRepository;

public class RepositoryRegistrator {

    private static final Logger log = LoggerFactory.getLogger(RepositoryRegistrator.class);

    public static RepositoryRegistrator INSTANCE = new RepositoryRegistrator();

    private static final String REPO_CONFIG_PID = "org.ops4j.pax.url.mvn";

    private static final String PROP_ENTAXY_SYSTEM_REPO_LIST = "org.ops4j.pax.url.mvn.repositories.entaxy";
    private static final String PROP_ENTAXY_CUSTOM_REPO_LIST = "org.ops4j.pax.url.mvn.repositories.entaxy.custom";

    private static final String ENTAXY_PROPERTY_HTTP_PORT = "entaxy.org.osgi.service.http.port";

    private static final String URL_PREFIX = "http://localhost:${" + ENTAXY_PROPERTY_HTTP_PORT + "}";

    protected Map<String, ArtifactRepository> systemRepos = new HashMap<>();
    protected Map<String, ArtifactRepository> customRepos = new HashMap<>();

    private RepositoryRegistrator() {

    }

    public void addRepository(ArtifactRepository repository) {
        addRepository(repository, true);
    }
    public void addRepository(ArtifactRepository repository, boolean httpEnabled) {
        Map<String, ArtifactRepository> targetMap;
        String propertyName;
        if (repository.isSystem()) {
            targetMap = systemRepos;
            propertyName = PROP_ENTAXY_SYSTEM_REPO_LIST;
            // TODO implement for initializer
            return;
        } else {
            targetMap = customRepos;
            propertyName = PROP_ENTAXY_CUSTOM_REPO_LIST;
        }

        targetMap.put(repository.getName(), repository);

        String repositoryUrlsResult = calculatePropertyValue(targetMap, httpEnabled);
        try {
            setPropertyValue(propertyName, repositoryUrlsResult);
            return;
        } catch (IOException e) {
            log.error("Error updating config", e);
        } catch (InvalidSyntaxException e) {
            log.error("Error updating config", e);
        } catch (Exception e) {
            log.error("Error updating config", e);
        }

        targetMap.remove(repository.getName());
    }

    public void removeRepository(ArtifactRepository repository) {
        if (repository.isSystem()) {
            systemRepos.remove(repository.getName());
        } else {
            customRepos.remove(repository.getName());
        }
    }

    protected String calculatePropertyValue(Map<String, ArtifactRepository> repoMap, boolean httpEnabled) {
        List<ArtifactRepository> list = new ArrayList<>(repoMap.values());
        Collections.sort(list, new Comparator<ArtifactRepository>() {

            @Override
            public int compare(ArtifactRepository o1, ArtifactRepository o2) {
                return o1.getName().compareToIgnoreCase(o2.getName());
            }

        });

        String resultValue = "";
        List<String> urlList = new ArrayList<>();
        for (ArtifactRepository repo : list) {
            String url = URL_PREFIX.concat(repo.getUrl())
                    .concat("@id=").concat(repo.getName())
                    .concat("@checksum=ignore")
                    .concat(repo.isSnapshotsAllowed() ? "@snapshots" : "");
            if (!httpEnabled) {
                url = url.replace("http:", "https:");
            }
            urlList.add(url);
        }
        resultValue = urlList.stream().collect(Collectors.joining(", "));
        return resultValue;
    }

    protected void setPropertyValue(String propertyName, String propertyValue) throws Exception {
        ConfigRepository configRepository =
                OSGIUtils.services().ofClass(ConfigRepository.class).waitService(20000).get();

        TypedProperties properties = configRepository.getConfig(REPO_CONFIG_PID);

        String hashKey = propertyName + ".md5";

        String newHash = DigestUtils.md5Hex(propertyValue);
        String currentHash = properties.getOrDefault(hashKey, "").toString();

        // To avoid extra config rewriting
        // which may cause config loss while updating
        if (!newHash.equals(currentHash)) {
            properties.put(propertyName, propertyValue);
            properties.put(hashKey, newHash);
            configRepository.update(REPO_CONFIG_PID, properties);
        }

    }

}
