package org.wso2.carbon.device.mgt.ios.payload.operation;

import org.apache.commons.beanutils.PropertyUtils;
import org.wso2.carbon.device.mgt.ios.payload.beans.PayloadOperation;
import org.wso2.carbon.device.mgt.ios.payload.beans.Restriction;
import org.wso2.carbon.device.mgt.ios.payload.dto.PayloadOperationWrapper;
import org.wso2.carbon.device.mgt.ios.payload.dto.PayloadProperties;
import org.wso2.carbon.device.mgt.ios.payload.exception.PListException;
import org.wso2.carbon.device.mgt.ios.payload.exception.ProfileConfigurationException;
import org.wso2.carbon.device.mgt.ios.payload.util.OperationUtils;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class RestrictionOperations {

    private static final String PAYLOAD_DISPLAY_NAME = "Restriction Configurations";
    private static final String PAYLOAD_DESCRIPTION = "Restriction Configurations for %s";
    public static final String RESTRICTION_PAYLOAD_UUID = "RestrictionOperationUUID";

    public PayloadOperationWrapper createRestrictionPayload(Restriction restriction) throws PListException,
            ProfileConfigurationException {

        PayloadProperties payloadProperties = generateCommonElements(restriction,
                OperationUtils.getTenantNameFromOperationID(), OperationUtils.isPayloadRemoveDisallowedForTenant());

        restriction.validateRequest();

        Map<String, Object> restrictionMap = restriction.getCommandMap();

        Field arrField[] = restriction.getClass().getDeclaredFields();

        for (Field field : arrField) {
            try {
                if (!skipFields(restriction, field.getName())) {
                    restrictionMap.put(field.getName(), PropertyUtils.getProperty(restriction,
                            field.getName()));
                }
            } catch (NoSuchMethodException e) {
                throw new PListException("Error generating PList for restriction payload", e);
            } catch (InvocationTargetException e) {
                throw new PListException("Error generating PList for restriction payload", e);
            } catch (IllegalAccessException e) {
                throw new PListException("Error generating PList for restriction payload", e);
            }
        }

        List<Object> payloadContent = new ArrayList<Object>();
        payloadContent.add(restrictionMap);

        PayloadOperationWrapper payloadOperationWrapper = new PayloadOperationWrapper();
        payloadOperationWrapper.setPayload(payloadContent);
        payloadOperationWrapper.setPayloadProperties(payloadProperties);

        return payloadOperationWrapper;
    }

    /**
     * Some fields in the restrictions profile are arrays and when no element is present, there
     * is no point in sending them to the device which can lead to unexpected behaviours. There
     * will be more restrictions arrays with DEP.
     *
     * @param restriction Restriction set that is being enforced.
     * @param fieldName   Name of the field that needs to be skipped.
     * @return true/false, If true, the field will be skipped.
     */
    private boolean skipFields(Restriction restriction, String fieldName)
            throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {

        boolean skip = false;
        if (fieldName.equalsIgnoreCase("autonomousSingleAppModePermittedAppIDs")) {
            List<String> autonomousSingleAppModePermittedAppIDs = (List<String>) PropertyUtils
                    .getProperty(restriction, fieldName);
            if (autonomousSingleAppModePermittedAppIDs == null ||
                    autonomousSingleAppModePermittedAppIDs.size() <= 0) {
                skip = true;
            }
        }

        return skip;
    }

    private PayloadProperties generateCommonElements(Restriction restriction, String tenantName,
                                        boolean payloadRemoveDisallowed) {

        PayloadProperties payloadProperties = new PayloadProperties();
        payloadProperties.setTenantName(tenantName);
        payloadProperties.setPayloadType(PayloadOperation.PayloadType.RESTRICTION.getPayloadType());
        payloadProperties.setPayloadIdentifier(RESTRICTION_PAYLOAD_UUID);
        payloadProperties.setPayloadDisplayName(PAYLOAD_DISPLAY_NAME);
        payloadProperties.setPayloadDescription(String.format(PAYLOAD_DESCRIPTION, tenantName));
        payloadProperties.setPayloadRemoveDisallowed(payloadRemoveDisallowed);

        restriction.populateCommandPayloadElements(payloadProperties);

        return payloadProperties;
    }

}
