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

import org.wso2.carbon.device.mgt.ios.payload.plist.PListGenerator;
import org.wso2.carbon.device.mgt.ios.payload.util.EnrollmentUtils;
import org.wso2.carbon.device.mgt.ios.payload.dto.CertificateAttributes;
import org.wso2.carbon.device.mgt.ios.payload.exception.PListException;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

public class EnrollmentPayloadGenerator {

    private Map<String, Object> generateCommonElements(String tenantName, PayloadType payloadType) {
        Map<String, Object> generalMap = new HashMap<String, Object>();
        generalMap.put(EnrollmentConstants.PAYLOAD_VERSION, EnrollmentConstants.PAYLOAD_VERSION_VALUE);
        generalMap.put(EnrollmentConstants.PAYLOAD_UUID, UUID.randomUUID().toString());
        generalMap.put(EnrollmentConstants.PAYLOAD_ORGANIZATION, tenantName);
        generalMap.put(EnrollmentConstants.PAYLOAD_TYPE, payloadType.getPayloadType());
        generalMap.put(EnrollmentConstants.PAYLOAD_IDENTIFIER, payloadType.getPayloadIdentifier());

        return generalMap;
    }

    public String generateMobileConfigurations(
            String challengeToken, String tenantName, String profileURL) throws PListException {

        Map<String, Object> itemMap = generateCommonElements(tenantName, PayloadType.PROFILE_SERVICE);
        itemMap.put(EnrollmentConstants.PAYLOAD_DISPLAY_NAME,
                String.format(EnrollmentConstants.MOBILE_CONFIGURATION_PAYLOAD_DISPLAY_NAME, tenantName));
        itemMap.put(EnrollmentConstants.PAYLOAD_DESCRIPTION,
                String.format(EnrollmentConstants.MOBILE_CONFIGURATION_PAYLOAD_DESCRIPTION, tenantName));

        Map<String, Object> innerMap = new HashMap<String, Object>();
        innerMap.put(EnrollmentConstants.DEVICE_ATTRIBUTES, EnrollmentUtils.getDeviceAttributes());
        innerMap.put(EnrollmentConstants.CHALLENGE, challengeToken);
        innerMap.put(EnrollmentConstants.URL, profileURL);

        itemMap.put(EnrollmentConstants.PAYLOAD_CONTENT, innerMap);

        PListGenerator pListGenerator = new PListGenerator();

        return pListGenerator.generatePayload(itemMap);
    }

    public String generateMDMConfigurationPayload(String challenge,
                                                  String tenantName, String topicId,
                                                  CertificateAttributes certAttributes,
                                                  String checkInURL, String serverURL, String enrollURL)
            throws PListException {

        Map<String, Object> itemMap = generateCommonElements(tenantName, PayloadType.MDM);
        itemMap.put(EnrollmentConstants.PAYLOAD_DISPLAY_NAME,
                String.format(EnrollmentConstants.CONFIGURATION_PAYLOAD_DISPLAY_NAME, tenantName));
        itemMap.put(EnrollmentConstants.PAYLOAD_DESCRIPTION,
                String.format(EnrollmentConstants.CONFIGURATION_PAYLOAD_DESCRIPTION, tenantName));
        itemMap.put(EnrollmentConstants.TOPIC, topicId);
        itemMap.put(EnrollmentConstants.CHECK_IN_URL, checkInURL);
        itemMap.put(EnrollmentConstants.CHECKOUT_WHEN_REMOVED, true);
        itemMap.put(EnrollmentConstants.SERVER_URL, serverURL);
        itemMap.put(EnrollmentConstants.SIGN_MESSAGE, true);
        itemMap.put(EnrollmentConstants.IS_REMOVABLE, false);
        itemMap.put(EnrollmentConstants.IDENTIFIER, EnrollmentConstants.EMPTY_STRING);
        itemMap.put(EnrollmentConstants.SECRET, EnrollmentConstants.EMPTY_STRING);
        itemMap.put(EnrollmentConstants.PAYLOAD_REMOVAL_DISALLOWED, false);
        itemMap.put(EnrollmentConstants.ACCESS_RIGHTS, EnrollmentConstants.ACCESS_RIGHT_VALUE);

        String identityCertificateUUID = UUID.randomUUID().toString();
        itemMap.put(EnrollmentConstants.IDENTITY_CERTIFICATE_UUID,
                identityCertificateUUID);

        List<Object> compositePayload = new ArrayList<Object>();
        compositePayload.add(generateSCEPPayload(challenge, EnrollmentConstants.MDM, tenantName,
                certAttributes, enrollURL, identityCertificateUUID));
        compositePayload.add(itemMap);

        PListGenerator pListGenerator = new PListGenerator();

        return pListGenerator.generatePayload(compositePayload);
    }

    public String generateEncryptedConfigurationPayload(
            String encryptedContent, String tenantName)  throws PListException {

        Map<String, Object> itemMap = generateCommonElements(tenantName, PayloadType.CONFIGURATION);

        itemMap.put(EnrollmentConstants.PAYLOAD_DISPLAY_NAME,
                String.format(EnrollmentConstants.ENCRYPTED_CONFIGURATION_PAYLOAD_DISPLAY_NAME, tenantName));
        itemMap.put(EnrollmentConstants.PAYLOAD_DESCRIPTION,
                String.format(EnrollmentConstants.ENCRYPTED_CONFIGURATION_PAYLOAD_DESCRIPTION, tenantName));

        EnrollmentUtils enrollmentUtils = new EnrollmentUtils();
        itemMap.put(EnrollmentConstants.PAYLOAD_EXPIRATION_DATE, enrollmentUtils.getCertificateExpirationDate());
        itemMap.put(EnrollmentConstants.ENCRYPTED_PAYLOAD_CONTENT, encryptedContent.getBytes());

        // format should be 2013-09-28T00:00:00Z
        SimpleDateFormat dateFormat = new SimpleDateFormat(EnrollmentConstants.PAYLOAD_DATE_FORMAT);
        PListGenerator pListGenerator = new PListGenerator(dateFormat);

        return pListGenerator.generatePayload(itemMap);
    }

    public String generateEncryptedCertificatePayload(String challenge,
                                                      String tenantName,
                                                      CertificateAttributes certAttributes, String enrollURL)
            throws PListException {

        Map<String, Object> itemMap = generateCommonElements(tenantName, PayloadType.CONFIGURATION);
        itemMap.put(EnrollmentConstants.PAYLOAD_DISPLAY_NAME,
                String.format(EnrollmentConstants.ENCRYPTED_CERTIFICATE_PAYLOAD_DISPLAY_NAME, tenantName));
        itemMap.put(EnrollmentConstants.PAYLOAD_DESCRIPTION,
                EnrollmentConstants.ENCRYPTED_CERTIFICATE_PAYLOAD_DESCRIPTION);

        String identityCertificateUUID = UUID.randomUUID().toString();
        List<Object> scepPayload = new ArrayList<Object>();
        scepPayload.add(generateSCEPPayload(challenge, EnrollmentConstants.PROFILE_SERVICE,
                tenantName, certAttributes, enrollURL, identityCertificateUUID));
        itemMap.put(EnrollmentConstants.PAYLOAD_CONTENT, scepPayload);

        PListGenerator pListGenerator = new PListGenerator();

        return pListGenerator.generatePayload(itemMap);
    }

    Map<String, Object> generateSCEPPayload(String challengeToken,
                                                   String purpose, String tenantName,
                                                   CertificateAttributes certAttributes, String enrollURL,
                                                   String identityCertificateUUID) {

        Map<String, Object> itemMap = generateCommonElements(tenantName, PayloadType.SCEP);
        itemMap.put(EnrollmentConstants.PAYLOAD_UUID, identityCertificateUUID);
        itemMap.put(EnrollmentConstants.PAYLOAD_DISPLAY_NAME,
                String.format(EnrollmentConstants.SCEP_PAYLOAD_DISPLAY_NAME, tenantName));
        itemMap.put(EnrollmentConstants.PAYLOAD_DESCRIPTION, EnrollmentConstants.SCEP_PAYLOAD_DESCRIPTION);

        Map<String, Object> innerMap = new HashMap<String, Object>();
        innerMap.put(EnrollmentConstants.URL, enrollURL);

        // MS SCEP servers need Name property
        innerMap.put(EnrollmentConstants.NAME, EnrollmentConstants.ENROLLMENT_CA_INSTANCE);

        EnrollmentUtils enrollmentUtils = new EnrollmentUtils();
        innerMap.put(EnrollmentConstants.SUBJECT, enrollmentUtils.getSubjectList(certAttributes, purpose));

        innerMap.put(EnrollmentConstants.CHALLENGE, challengeToken);
        innerMap.put(EnrollmentConstants.KEY_SIZE, EnrollmentConstants.RSA_KEY_LENGTH);
        innerMap.put(EnrollmentConstants.KEY_TYPE, EnrollmentConstants.RSA);
        innerMap.put(EnrollmentConstants.KEY_USAGE, EnrollmentConstants.KEY_USAGE_VALUE);
        // innnerMap.put("CAFingerprint", "");

        itemMap.put(EnrollmentConstants.PAYLOAD_CONTENT, innerMap);

        return itemMap;
    }

}
