package org.wso2.carbon.device.mgt.ios.core.publisher;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.device.mgt.common.DeviceManagementException;
import org.wso2.carbon.device.mgt.common.Device;
import org.wso2.carbon.device.mgt.common.DeviceManagementConstants;
import org.wso2.carbon.device.mgt.common.EnrolmentInfo;
import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
import org.wso2.carbon.device.mgt.common.operation.mgt.Operation;
import org.wso2.carbon.device.mgt.common.operation.mgt.OperationManagementException;
import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService;
import org.wso2.carbon.device.mgt.ios.core.internal.IOSEnrollmentServiceHolder;
import org.wso2.carbon.device.mgt.ios.core.util.AppConfigurations;
import org.wso2.carbon.device.mgt.ios.payload.dto.DeviceProperties;

import java.util.ArrayList;
import java.util.List;

public class TokenPersistence {

    public static final String APNS_PUSH_TOKEN = "APNS_PUSH_TOKEN";
    public static final String MAGIC_TOKEN = "MAGIC_TOKEN";
    public static final String MDM_TOKEN = "MDM_TOKEN";
    public static final String UNLOCK_TOKEN = "UNLOCK_TOKEN";
    public static final String CHALLENGE_TOKEN = "CHALLENGE_TOKEN";
    public static final String DEVICE_INFO = "DEVICE_INFO";
    public static final String SERIAL = "SERIAL";
    public static final String PRODUCT = "PRODUCT";
    public static final String MAC_ADDRESS = "MAC_ADDRESS";
    public static final String DEVICE_NAME = "DEVICE_NAME";
    public static final String ICCID = "ICCID";
    public static final String VERSION = "VERSION";
    public static final String IMEI = "IMEI";
    public static final String LATITUDE = "LATITUDE";
    public static final String LONGITUDE = "LONGITUDE";

    private static final Log log = LogFactory.getLog(TokenPersistence.class);

    public void saveDeviceTokens(DeviceProperties deviceProperties) throws DeviceManagementException {
        DeviceManagementProviderService deviceManagementService =
                IOSEnrollmentServiceHolder.getInstance().getDeviceManagementService();

        String model;
        if (deviceProperties.getProduct() == null) {
            model = "";
        } else if (deviceProperties.getProduct().contains(AppConfigurations.I_PAD)) {
            model = AppConfigurations.I_PAD;
        } else if (deviceProperties.getProduct().contains(AppConfigurations.I_POD)) {
            model = AppConfigurations.I_POD;
        } else if (deviceProperties.getProduct().contains(AppConfigurations.I_PHONE)) {
            model = AppConfigurations.I_PHONE;
        } else {
            model = "";
        }

        List<Device.Property> propertyList = new ArrayList<Device.Property>();
        propertyList.add(getDeviceProperty(IMEI, deviceProperties.getIMEI()));
        propertyList.add(getDeviceProperty(PRODUCT, model));
        propertyList.add(getDeviceProperty(SERIAL, deviceProperties.getSerial()));
        propertyList.add(getDeviceProperty(CHALLENGE_TOKEN, deviceProperties.getChallenge()));
        propertyList.add(getDeviceProperty(VERSION, deviceProperties.getVersion()));
        propertyList.add(getDeviceProperty(MAC_ADDRESS, deviceProperties.getMacAddress()));
        propertyList.add(getDeviceProperty(DEVICE_NAME, deviceProperties.getDeviceName()));
        propertyList.add(getDeviceProperty(ICCID, deviceProperties.getDeviceName()));

        DeviceIdentifier deviceIdentifier = new DeviceIdentifier();
        deviceIdentifier.setId(deviceProperties.getDeviceIdentifier());
        deviceIdentifier.setType(DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_IOS);

        String username = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername();

        EnrolmentInfo enrolmentInfo = new EnrolmentInfo();
        enrolmentInfo.setOwner(username);
        enrolmentInfo.setOwnership(EnrolmentInfo.OwnerShip.BYOD);
        enrolmentInfo.setStatus(EnrolmentInfo.Status.ACTIVE);

        Device device = new Device();
        device.setType(DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_IOS);
        device.setName(deviceProperties.getProduct());
        device.setDeviceIdentifier(deviceProperties.getDeviceIdentifier());
        device.setProperties(propertyList);
        device.setEnrolmentInfo(enrolmentInfo);

        deviceManagementService.enrollDevice(device);

    }

    public void disEnrollDevice(String deviceID) throws DeviceManagementException {

        DeviceIdentifier deviceIdentifier = new DeviceIdentifier();
        deviceIdentifier.setId(deviceID);
        deviceIdentifier.setType(DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_IOS);

        DeviceManagementProviderService deviceManagementService =
                IOSEnrollmentServiceHolder.getInstance().getDeviceManagementService();

        deviceManagementService.disenrollDevice(deviceIdentifier);
    }

    private Device.Property getDeviceProperty(String name, String value) {
        Device.Property deviceProperty = new Device.Property();
        deviceProperty.setName(name);
        deviceProperty.setValue(value);

        return deviceProperty;
    }

    public String getPropertyValue(Device device, final String propertyName) {

        //TODO convert this to a proper map
        for (Device.Property property : device.getProperties()) {
            if (property.getName().equals(propertyName)) {
                return property.getValue();
            }
        }

        return "";
    }

    public void savePushTokens(DeviceProperties deviceProperties, String token, String magicToken, String unlockToken)
            throws DeviceManagementException {

        DeviceManagementProviderService deviceManagementService =
                IOSEnrollmentServiceHolder.getInstance().getDeviceManagementService();

        DeviceIdentifier deviceIdentifier = new DeviceIdentifier();
        deviceIdentifier.setId(deviceProperties.getDeviceIdentifier());
        deviceIdentifier.setType(DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_IOS);

        Device device = deviceManagementService.getDevice(deviceIdentifier);
        List<Device.Property> propertyList = new ArrayList<Device.Property>();
        if (device.getProperties() != null) {
            propertyList.addAll(device.getProperties());
        }

        updatePropertyValue(propertyList, MDM_TOKEN, token);
        updatePropertyValue(propertyList, MAGIC_TOKEN, magicToken);
        updatePropertyValue(propertyList, UNLOCK_TOKEN, unlockToken);
        updatePropertyValue(propertyList, CHALLENGE_TOKEN, deviceProperties.getChallenge());
        device.setProperties(propertyList);

        deviceManagementService.updateDeviceInfo(deviceIdentifier, device);
    }

    public void saveAPNSToken(DeviceIdentifier deviceIdentifier, String apnsToken)
            throws DeviceManagementException {

        DeviceManagementProviderService deviceManagementService =
                IOSEnrollmentServiceHolder.getInstance().getDeviceManagementService();

        Device device = deviceManagementService.getDevice(deviceIdentifier);
        List<Device.Property> propertyList = new ArrayList<Device.Property>();
        if (device.getProperties() != null) {
            propertyList.addAll(device.getProperties());
        }

        updatePropertyValue(propertyList, APNS_PUSH_TOKEN, apnsToken);
        device.setProperties(propertyList);

        deviceManagementService.updateDeviceInfo(deviceIdentifier, device);
    }

    public void saveDeviceLocation(DeviceIdentifier deviceIdentifier, float latitude, float longitude,
                                   String operationId)
            throws DeviceManagementException {

        DeviceManagementProviderService deviceManagementService =
                IOSEnrollmentServiceHolder.getInstance().getDeviceManagementService();

        Device device = deviceManagementService.getDevice(deviceIdentifier);
        List<Device.Property> propertyList = new ArrayList<Device.Property>();
        if (device.getProperties() != null) {
            propertyList.addAll(device.getProperties());
        }

        updatePropertyValueLocation(propertyList, LATITUDE, Float.valueOf(latitude).toString());
        updatePropertyValueLocation(propertyList, LONGITUDE, Float.valueOf(longitude).toString());

        device.setProperties(propertyList);

        deviceManagementService.updateDeviceInfo(deviceIdentifier, device);
        Operation operation = new Operation();
        operation.setStatus(Operation.Status.COMPLETED);
        operation.setId(Integer.parseInt(operationId));

        try {
            deviceManagementService.updateOperation(deviceIdentifier, operation);
        } catch (OperationManagementException e) {
            String msg = "Error while updating location for device id " + deviceIdentifier.getId() + "and operation "
                    + operationId;
            log.error(msg);
            throw new DeviceManagementException(msg);
        }
    }

    private void updatePropertyValueLocation(List<Device.Property> propertyList,
                                             String propertyName, String newValue) {
        for (int x = 0; x < propertyList.size(); x++) {
            if (propertyList.get(x).getName().equals(propertyName)) {
                propertyList.get(x).setValue(newValue);
            }
        }
    }

    public void saveDeviceInformation(DeviceIdentifier deviceIdentifier, String deviceInfo)
            throws DeviceManagementException {

        DeviceManagementProviderService deviceManagementService =
                IOSEnrollmentServiceHolder.getInstance().getDeviceManagementService();

        Device device = deviceManagementService.getDevice(deviceIdentifier);
        List<Device.Property> propertyList = new ArrayList<Device.Property>();
        if (device.getProperties() != null) {
            propertyList.addAll(device.getProperties());
        }

        updatePropertyValue(propertyList, DEVICE_INFO, deviceInfo);
        device.setProperties(propertyList);

        deviceManagementService.updateDeviceInfo(deviceIdentifier, device);
    }

    //TODO change the core - make the propertyList an Map
    private void updatePropertyValue(List<Device.Property> propertyList,
                                     String propertyName, String newValue) {
        for (Device.Property property : propertyList) {
            if (property.getName().equals(propertyName)) {
                property.setValue(newValue);
                break;
            }
        }
    }

    public static String getPropertyValue(List<Device.Property> propertyList, String propertyName) {
        for (Device.Property property : propertyList) {
            if (property.getName().equals(propertyName)) {
                return property.getValue();
            }
        }

        return null;
    }
}
