/*-
 * ~~~~~~licensing~~~~~~
 * system-management-api
 * ==========
 * 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.esb.system.management.mapper;

import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.Named;
import ru.entaxy.esb.system.core.template.Template;
import ru.entaxy.esb.system.management.bridge.profile.manager.dto.BridgeProfileDto;
import ru.entaxy.esb.system.management.connector.manager.dto.ConnectorDto;
import ru.entaxy.esb.system.management.permission.manager.dto.PermissionDto;
import ru.entaxy.esb.system.management.profile.manager.dto.ProfileDto;
import ru.entaxy.esb.system.management.soap.*;

import javax.xml.bind.JAXBElement;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;
import java.util.*;

@org.mapstruct.Mapper
public interface Mapper {

    @Mappings({
            @Mapping(source = "objectUuid", target = "objectId"),
            @Mapping(source = "subjectUuid", target = "subjectId"),
    })
    PermissionDto toPermissionDto(PermissionType permissionType);

    @Mappings({
            @Mapping(source = "profileName", target = "name"),
            @Mapping(source = "description", target = "description", qualifiedByName = "toJAXBElementDescription")
    })
    ProfileDto toProfileDto(CreateProfileType createProfileType);

    @Named("toJAXBElementDescription")
    default String toJAXBElementDescription(JAXBElement<String> description) {
        return description.getValue();
    }

    @Mappings({
            @Mapping(source = "name", target = "profileName"),
            @Mapping(source = "connectors", target = "connectorList.connector"),
            @Mapping(source = "exportAllowed", target = "esbNames.esbName"),
            @Mapping(source = "editDate", target = "editDate", qualifiedByName = "toEditDate"),
            @Mapping(source = "editedBy", target = "editedBy", qualifiedByName = "toEditedBy"),
            @Mapping(source = "description", target = "description", qualifiedByName = "toDescription")
    })
    FullProfileType toFullProfileType(ProfileDto profileDto);

    @Mappings({
            @Mapping(source = "uuid", target = "uuid"),
    })
    ProfileDto toProfileDto(ProfileType profileType);

    @Mappings({
            @Mapping(source = "uuid", target = "uuid"),
    })
    ProfileType toProfileType(ProfileDto profileType);

    @Mappings({
            @Mapping(source = "profileUuid", target = "systemUuid"),
            @Mapping(source = "paramList", target = "connectorParams", qualifiedByName = "toMapParam")
    })
    ConnectorDto toConnectorDto(CreateConnectorType createConnectorType);

    @Mappings({
            @Mapping(source = "profileUuid", target = "systemUuid"),
    })
    ConnectorDto toConnectorDto(GetConnectorType getConnectorType);

    BridgeProfileDto toBridgeProfileDto(BridgeProfileType bridgeProfileType);

    @Mappings({
            @Mapping(target = "name", expression = "java(connectorDto.getName())"),
            @Mapping(source = "connectorParams", target = "paramList", qualifiedByName = "toParamListType"),
    })
    ConnectorType toConnectorType(ConnectorDto connectorDto);

    @Mapping(source = "params", target = "paramList", qualifiedByName = "toParamListType")
    TemplateType toTemplateType(Template template);

    @Named("toParamListType")
    default ParamListType toParamListType(Map<String, String> params) {
        ParamListType paramListType = new ParamListType();
        if (params != null) {
            for (Map.Entry<String, String> entry : params.entrySet()) {
                ParamType paramType = new ParamType();
                paramType.setName(entry.getKey());
                paramType.setValue(entry.getValue());
                paramListType.getParam().add(paramType);
            }
        }
        return paramListType;
    }

    @Named("toMapParam")
    default Map<String, String> toMapParam(ParamListType paramListType) {
        Map<String, String> params = new HashMap<>();
        if (paramListType != null) {
            for (ParamType paramType : paramListType.getParam()) {
                params.put(paramType.getName(), paramType.getValue());
            }
        }
        return params;
    }

    @Named("toListFullProfileType")
    default ListFullProfileType toListFullProfileType(List<ProfileDto> profileDtos) {
        ListFullProfileType listFullProfileType = new ListFullProfileType();
        for (ProfileDto profileDto : profileDtos) {
            listFullProfileType.getFullProfileType().add(toFullProfileType(profileDto));
        }
        return listFullProfileType;
    }

    @Named("toListProfileType")
    default ListProfileType toListProfileType(List<ProfileDto> profileDtos) {
        ListProfileType listProfileType = new ListProfileType();
        for (ProfileDto profileDto : profileDtos) {
            listProfileType.getProfileType().add(toProfileType(profileDto));
        }
        return listProfileType;
    }

    default ListConnectorType toListConnectorType(List<ConnectorDto> connectorDtos) {
        ListConnectorType listConnectorType = new ListConnectorType();
        for (ConnectorDto connectorDto : connectorDtos) {
            listConnectorType.getConnector().add(toConnectorType(connectorDto));
        }
        return listConnectorType;
    }

    default ListBridgeProfileType toListBridgeProfileType(List<ru.entaxy.esb.system.management.bridge.profile.manager.sender.BridgeProfileType> bridgeProfileDtos) {
        ListBridgeProfileType listBridgeProfileType = new ListBridgeProfileType();
        for (ru.entaxy.esb.system.management.bridge.profile.manager.sender.BridgeProfileType bridgeProfileType : bridgeProfileDtos) {
            listBridgeProfileType.getFullBridgeProfileType().add(toFullBridgeProfileType(bridgeProfileType));
        }
        return listBridgeProfileType;
    }

    default JAXBElement<XMLGregorianCalendar> toEditDate(Date editDate) throws DatatypeConfigurationException {
        if (editDate != null) {
            ObjectFactory factory = new ObjectFactory();
            GregorianCalendar calendar = new GregorianCalendar();
            calendar.setTime(editDate);
            return factory.createFullProfileTypeEditDate(DatatypeFactory.newInstance()
                    .newXMLGregorianCalendar(calendar));
        } else
            return null;
    }

    @Named("toEditedBy")
    default JAXBElement<String> toEditedBy(String editedBy) {
        if (editedBy != null) {
            ObjectFactory factory = new ObjectFactory();
            return factory.createFullProfileTypeEditedBy(editedBy);
        } else
            return null;
    }

    @Named("toDescription")
    default JAXBElement<String> toDescription(String description) {
        if (description != null) {
            ObjectFactory factory = new ObjectFactory();
            return factory.createFullProfileTypeDescription(description);
        } else
            return null;
    }

    @Mappings({
            @Mapping(source = "origin", target = "esbName")
    })
    FullBridgeProfileType toFullBridgeProfileType(ru.entaxy.esb.system.management.bridge.profile.manager.sender.BridgeProfileType bridgeProfileType);


}
