/* BdfServer_JsonProducers - Copyright (c) 2022-2023 Vincent Calame - Exemole
 * Logiciel libre donné sous triple licence :
 * 1) selon les termes de la CeCILL V2
 * 2) selon les termes de l’EUPL V.1.1
 * 3) selon les termes de la GNU GPLv3
 * Voir le fichier licences.txt
 */


package fr.exemole.bdfserver.jsonproducers.administration;

import fr.exemole.bdfserver.api.users.BdfUser;
import fr.exemole.bdfserver.tools.diagnostic.urlscan.UrlInfo;
import fr.exemole.bdfserver.tools.diagnostic.urlscan.UrlReport;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import net.fichotheque.corpus.FicheMeta;
import net.fichotheque.corpus.metadata.CorpusField;
import net.fichotheque.corpus.metadata.FieldKey;
import net.fichotheque.utils.CorpusMetadataUtils;
import net.mapeadores.util.http.RedirectionUrl;
import net.mapeadores.util.http.UrlStatus;
import net.mapeadores.util.json.JSONWriter;
import net.mapeadores.util.localisation.Lang;
import net.mapeadores.util.json.JsonProperty;


/**
 *
 * @author Vincent Calame
 */
public class UrlInfosJsonProperty implements JsonProperty {

    private final Collection<UrlInfo> infos;
    private final BdfUser bdfUser;

    public UrlInfosJsonProperty(Collection<UrlInfo> infos, BdfUser bdfUser) {
        this.infos = infos;
        this.bdfUser = bdfUser;
    }

    @Override
    public String getName() {
        return "urlInfos";
    }

    @Override
    public void writeValue(JSONWriter jw) throws IOException {
        Map<String, FicheMeta> ficheMetaMap = new HashMap<String, FicheMeta>();
        Map<String, FieldInfo> fieldInfoMap = new HashMap<String, FieldInfo>();
        Lang workingLang = bdfUser.getWorkingLang();
        Locale formatLocale = bdfUser.getFormatLocale();
        jw.object();
        jw.key("array");
        {
            jw.array();
            for (UrlInfo urlInfo : infos) {
                jw.object();
                write(jw, urlInfo, ficheMetaMap, fieldInfoMap);
                jw.endObject();
            }
            jw.endArray();
        }
        if (!ficheMetaMap.isEmpty()) {
            jw.key("ficheMap");
            jw.object();
            for (Map.Entry<String, FicheMeta> entry : ficheMetaMap.entrySet()) {
                FicheMeta ficheMeta = entry.getValue();
                jw.key(entry.getKey());
                jw.object();
                {
                    jw.key("corpus")
                            .value(ficheMeta.getSubsetName());
                    jw.key("id")
                            .value(ficheMeta.getId());
                    jw.key("title")
                            .value(CorpusMetadataUtils.getFicheTitle(ficheMeta, workingLang, formatLocale));
                }
                jw.endObject();
            }
            jw.endObject();
            jw.key("fieldMap");
            jw.object();
            for (Map.Entry<String, FieldInfo> entry : fieldInfoMap.entrySet()) {
                jw.key(entry.getKey())
                        .value(entry.getValue().getTitle(workingLang));
            }
            jw.endObject();
        }
        jw.endObject();
    }

    private void write(JSONWriter jw, UrlInfo urlInfo, Map<String, FicheMeta> ficheMetaMap, Map<String, FieldInfo> fieldMap) throws IOException {
        UrlReport urlReport = urlInfo.getUrlReport();
        Map<String, UrlInfo.FicheInfo> ficheInfoMap = urlInfo.getFicheInfoMap();
        jw.key("url")
                .value(urlInfo.getUrl());
        if (urlReport != null) {
            jw.key("report");
            jw.object();
            write(jw, urlReport.getUrlStatus());
            jw.endObject();
        }
        if (!ficheInfoMap.isEmpty()) {
            jw.key("ficheArray");
            jw.array();
            for (Map.Entry<String, UrlInfo.FicheInfo> entry : ficheInfoMap.entrySet()) {
                String globalId = entry.getKey();
                UrlInfo.FicheInfo ficheInfo = entry.getValue();
                FicheMeta ficheMeta = ficheInfo.getFicheMeta();
                ficheMetaMap.put(globalId, ficheMeta);
                String corpusName = ficheMeta.getSubsetName();
                Set<FieldKey> fieldKeySet = ficheInfo.getFieldKeySet();
                jw.object();
                {
                    jw.key("key")
                            .value(globalId);
                    jw.key("fieldArray");
                    jw.array();
                    for (FieldKey fieldKey : fieldKeySet) {
                        String globalKey = corpusName + "/" + fieldKey.getKeyString();
                        if (!fieldMap.containsKey(globalKey)) {
                            CorpusField corpusField = ficheMeta.getCorpus().getCorpusMetadata().getCorpusField(fieldKey);
                            fieldMap.put(globalKey, new FieldInfo(globalKey, corpusField));
                        }
                        jw.value(fieldKey.getKeyString());
                    }
                    jw.endArray();
                }
                jw.endObject();
            }
            jw.endArray();
        }
    }

    private void write(JSONWriter jw, UrlStatus urlStatus) throws IOException {
        writeProperties(jw, urlStatus);
        RedirectionUrl redirectionUrl = urlStatus.getRedirectionUrl();
        if (redirectionUrl != null) {
            jw.key("redirectionArray");
            jw.array();
            writeRedirection(jw, redirectionUrl);
            jw.endArray();
        }
    }

    private void writeRedirection(JSONWriter jw, RedirectionUrl redirectionUrl) throws IOException {
        UrlStatus urlStatus = redirectionUrl.getUrlStatus();
        jw.object();
        {
            jw.key("url")
                    .value(redirectionUrl.getUrl());
            writeProperties(jw, urlStatus);
        }
        jw.endObject();
        RedirectionUrl nextRedirectionUrl = urlStatus.getRedirectionUrl();
        if (nextRedirectionUrl != null) {
            writeRedirection(jw, nextRedirectionUrl);
        }
    }

    private void writeProperties(JSONWriter jw, UrlStatus urlStatus) throws IOException {
        jw.key("state")
                .value(urlStatus.getState());
        if (urlStatus.hasResponse()) {
            jw.key("response");
            jw.object();
            {
                jw.key("code")
                        .value(urlStatus.getResponseCode());
                String message = urlStatus.getResponseMessage();
                if (!message.isEmpty()) {
                    jw.key("message")
                            .value(message);
                }
            }
            jw.endObject();
        }
    }


    private static class FieldInfo {

        private final String key;
        private final CorpusField corpusField;

        private FieldInfo(String key, CorpusField corpusField) {
            this.key = key;
            this.corpusField = corpusField;
        }

        public String getTitle(Lang lang) {
            if (corpusField != null) {
                return CorpusMetadataUtils.getFieldTitle(corpusField, lang);
            } else {
                return key;
            }
        }

    }

}
