package eu.eudat.models.data.datasetwizard;

import eu.eudat.data.entities.*;
import eu.eudat.elastic.entities.Tag;
import eu.eudat.models.DataModel;
import eu.eudat.models.data.dataset.DataRepository;
import eu.eudat.models.data.dataset.Registry;
import eu.eudat.models.data.dataset.Service;
import eu.eudat.models.data.datasetprofile.DatasetProfileOverviewModel;
import eu.eudat.models.data.dmp.DataManagementPlan;
import eu.eudat.models.data.externaldataset.ExternalDatasetListingModel;
import eu.eudat.models.data.user.composite.PagedDatasetProfile;
import net.minidev.json.JSONValue;

import java.util.*;
import java.util.stream.Collectors;


public class DatasetWizardModel implements DataModel<Dataset, DatasetWizardModel> {

    private UUID id;
    private String label;
    private String reference;
    private String uri;
    private String description;
    private short status;
    private Date created;
    private DataManagementPlan dmp;
    private PagedDatasetProfile datasetProfileDefinition;
    private List<Registry> registries;
    private List<Service> services;
    private List<DataRepository> dataRepositories;
    private List<Tag> tags;
    private List<ExternalDatasetListingModel> externalDatasets;
    private DatasetProfileOverviewModel profile;
    private Boolean isProfileLatestVersion;
    private Date modified;

    public UUID getId() {
        return id;
    }
    public void setId(UUID id) {
        this.id = id;
    }

    public String getLabel() {
        return label;
    }
    public void setLabel(String label) {
        this.label = label;
    }

    public String getReference() {
        return reference;
    }
    public void setReference(String reference) {
        this.reference = reference;
    }

    public String getUri() {
        return uri;
    }
    public void setUri(String uri) {
        this.uri = uri;
    }

    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }

    public short getStatus() {
        return status;
    }
    public void setStatus(short status) {
        this.status = status;
    }

    public Date getCreated() {
        return created;
    }
    public void setCreated(Date created) {
        this.created = created;
    }

    public DataManagementPlan getDmp() {
        return dmp;
    }
    public void setDmp(DataManagementPlan dmp) {
        this.dmp = dmp;
    }

    public PagedDatasetProfile getDatasetProfileDefinition() {
        return datasetProfileDefinition;
    }
    public void setDatasetProfileDefinition(PagedDatasetProfile datasetProfileDefinition) {
        this.datasetProfileDefinition = datasetProfileDefinition;
    }

    public List<Registry> getRegistries() {
        return registries;
    }
    public void setRegistries(List<Registry> registries) {
        this.registries = registries;
    }

    public List<Service> getServices() {
        return services;
    }
    public void setServices(List<Service> services) {
        this.services = services;
    }

    public List<DataRepository> getDataRepositories() {
        return dataRepositories;
    }
    public void setDataRepositories(List<DataRepository> dataRepositories) {
        this.dataRepositories = dataRepositories;
    }

    public DatasetProfileOverviewModel getProfile() {
        return profile;
    }

    public void setProfile(DatasetProfileOverviewModel profile) {
        this.profile = profile;
    }

    public List<ExternalDatasetListingModel> getExternalDatasets() {
        return externalDatasets;
    }
    public void setExternalDatasets(List<ExternalDatasetListingModel> externalDatasets) {
        this.externalDatasets = externalDatasets;
    }

    public List<Tag> getTags() {
        return tags;
    }
    public void setTags(List<Tag> tags) {
        this.tags = tags;
    }

    public Boolean getIsProfileLatestVersion() {
        return isProfileLatestVersion;
    }
    public void setIsProfileLatestVersion(Boolean profileLatestVersion) {
        isProfileLatestVersion = profileLatestVersion;
    }

    public Date getModified() {
        return modified;
    }
    public void setModified(Date modified) {
        this.modified = modified;
    }

    @Override
    public DatasetWizardModel fromDataModel(Dataset entity) {
        this.id = entity.getId();
        this.label = entity.getLabel();
        this.status = entity.getStatus();
        this.reference = entity.getReference();
        this.description = entity.getDescription();
        this.profile = new DatasetProfileOverviewModel();
        this.profile = this.profile.fromDataModel(entity.getProfile());
        this.uri = entity.getUri();
        this.registries = entity.getRegistries() != null ? entity.getRegistries().stream().map(item -> new Registry().fromDataModel(item)).collect(Collectors.toList()) : new ArrayList<>();
        this.dataRepositories = entity.getDatasetDataRepositories() != null ? entity.getDatasetDataRepositories().stream().map(item -> {
            DataRepository dataRepository = new DataRepository().fromDataModel(item.getDataRepository());
            if (item.getData() != null) {
                Map<String, Map<String, String>> data = (Map<String, Map<String, String>>) JSONValue.parse(item.getData());
                Map<String, String> values = data.get("data");
                dataRepository.setInfo(values.get("info"));
            }
            return dataRepository;
        }).collect(Collectors.toList()) : new ArrayList<>();
        this.services = entity.getServices() != null ? entity.getServices().stream().map(item -> new Service().fromDataModel(item.getService())).collect(Collectors.toList()) : new ArrayList<>();
        this.created = entity.getCreated();
        this.dmp = new DataManagementPlan().fromDataModelNoDatasets(entity.getDmp());
        this.externalDatasets = entity.getDatasetExternalDatasets() != null ? entity.getDatasetExternalDatasets().stream().map(item -> {
            ExternalDatasetListingModel externalDatasetListingModel = new ExternalDatasetListingModel().fromDataModel(item.getExternalDataset());
            if (item.getData() != null) {
                Map<String, Map<String, String>> data = (Map<String, Map<String, String>>) JSONValue.parse(item.getData());
                Map<String, String> values = data.get("data");
                externalDatasetListingModel.setInfo(values.get("info"));
                externalDatasetListingModel.setType(Integer.parseInt(values.get("type")));
            }
            return externalDatasetListingModel;
        }).collect(Collectors.toList()) : new ArrayList<>();
        this.modified = entity.getModified();
        return this;
    }

    public DatasetWizardModel fromDataModelNoDmp(Dataset entity) {
        this.id = entity.getId();
        this.label = entity.getLabel();
        this.status = entity.getStatus();
        this.reference = entity.getReference();
        this.description = entity.getDescription();
        this.profile = new DatasetProfileOverviewModel();
        this.profile = this.profile.fromDataModel(entity.getProfile());
        this.uri = entity.getUri();
        this.registries = entity.getRegistries() != null ? entity.getRegistries().stream().map(item -> new Registry().fromDataModel(item)).collect(Collectors.toList()) : new ArrayList<>();
        this.dataRepositories = entity.getDatasetDataRepositories() != null ? entity.getDatasetDataRepositories().stream().map(item -> {
            DataRepository dataRepository = new DataRepository().fromDataModel(item.getDataRepository());
            if (item.getData() != null) {
                Map<String, Map<String, String>> data = (Map<String, Map<String, String>>) JSONValue.parse(item.getData());
                Map<String, String> values = data.get("data");
                dataRepository.setInfo(values.get("info"));
            }
            return dataRepository;
        }).collect(Collectors.toList()) : new ArrayList<>();
        this.services = entity.getServices() != null ? entity.getServices().stream().map(item -> new Service().fromDataModel(item.getService())).collect(Collectors.toList()) : new ArrayList<>();
        this.created = entity.getCreated();
        this.externalDatasets = entity.getDatasetExternalDatasets() != null ? entity.getDatasetExternalDatasets().stream().map(item -> {
            ExternalDatasetListingModel externalDatasetListingModel = new ExternalDatasetListingModel().fromDataModel(item.getExternalDataset());
            if (item.getData() != null) {
                Map<String, Map<String, String>> data = (Map<String, Map<String, String>>) JSONValue.parse(item.getData());
                Map<String, String> values = data.get("data");
                externalDatasetListingModel.setInfo(values.get("info"));
                externalDatasetListingModel.setType(Integer.parseInt(values.get("type")));
            }
            return externalDatasetListingModel;
        }).collect(Collectors.toList()) : new ArrayList<>();
        this.modified = entity.getModified();
        return this;
    }

    @Override
    public Dataset toDataModel() throws Exception {
        eu.eudat.data.entities.Dataset entity = new eu.eudat.data.entities.Dataset();
        entity.setId(this.id);
        entity.setLabel(this.label);
        entity.setReference(this.reference);
        entity.setUri(this.uri);
        entity.setStatus(this.status);
        if (this.status == (int) Dataset.Status.FINALISED.getValue())
            entity.setFinalizedAt(new Date());
        DMP dmp = new DMP();
        dmp.setId(this.dmp.getId());
        entity.setDmp(dmp);
        entity.setDescription(this.description);
        entity.setCreated(this.created != null ? this.created : new Date());
        entity.setModified(new Date());
        DatasetProfile profile = new DatasetProfile();
        profile.setId(this.profile.getId());
        entity.setProfile(profile);
        if (this.registries != null && !this.registries.isEmpty()) {
            entity.setRegistries(new HashSet<>());
            for (Registry registry : this.registries) {
                entity.getRegistries().add(registry.toDataModel());
            }
        }

        if (this.dataRepositories != null && !this.dataRepositories.isEmpty()) {
            entity.setDatasetDataRepositories(new HashSet<>());
            for (DataRepository dataRepositoryModel : this.dataRepositories) {
                eu.eudat.data.entities.DataRepository dataRepository = dataRepositoryModel.toDataModel();
                DatasetDataRepository datasetDataRepository = new DatasetDataRepository();
                datasetDataRepository.setDataRepository(dataRepository);
                Map<String, Map<String, String>> data = new HashMap<>();
                Map<String, String> values = new HashMap<>();
                values.put("info", dataRepositoryModel.getInfo());
                data.put("data", values);
                datasetDataRepository.setData(JSONValue.toJSONString(data));
                entity.getDatasetDataRepositories().add(datasetDataRepository);
            }
        }

        if (this.services != null && !this.services.isEmpty()) {
            entity.setServices(new HashSet<>());
            for (Service serviceModel : this.services) {
                eu.eudat.data.entities.Service service = serviceModel.toDataModel();
                DatasetService datasetService = new DatasetService();
                datasetService.setService(service);
                entity.getServices().add(datasetService);
            }
        }

        if (this.externalDatasets != null && !this.externalDatasets.isEmpty()) {
            entity.setDatasetExternalDatasets(new HashSet<>());
            for (ExternalDatasetListingModel externalDataset : this.externalDatasets) {
                ExternalDataset externalDatasetEntity = externalDataset.toDataModel();
                DatasetExternalDataset datasetExternalDataset = new DatasetExternalDataset();
                datasetExternalDataset.setExternalDataset(externalDatasetEntity);
                Map<String,Map<String,String>> data = new HashMap<>();
                Map<String,String> values = new HashMap<>();
                values.put("info",externalDataset.getInfo());
                values.put("type",externalDataset.getType().toString());
                data.put("data",values);
                datasetExternalDataset.setData(JSONValue.toJSONString(data));
                entity.getDatasetExternalDatasets().add(datasetExternalDataset);
            }
        }
        return entity;
    }


    @Override
    public String getHint() {
        return "datasetWizardModel";
    }
}
