"""
The configuration file would look like this (sans those // comments):
{
    "authority": "https://login.microsoftonline.com/Enter_the_Tenant_Name_Here",
    "client_id": "your_client_id",
    "scope": ["https://graph.microsoft.com/.default"],
        // Specific to Client Credentials Grant i.e. acquire_token_for_client(),
        // you don't specify, in the code, the individual scopes you want to access.
        // Instead, you statically declared them when registering your application.
        // Therefore the only possible scope is "resource/.default"
        // (here "https://graph.microsoft.com/.default")
        // which means "the static permissions defined in the application".
    "secret": "The secret generated by AAD during your confidential app registration",
        // For information about generating client secret, refer:
        // https://github.com/AzureAD/microsoft-authentication-library-for-python/wiki/Client-Credentials#registering-client-secrets-using-the-application-registration-portal
    "endpoint": "https://graph.microsoft.com/v1.0/users"
        // For this resource to work, you need to visit Application Permissions
        // page in portal, declare scope User.Read.All, which needs admin consent
        // https://github.com/Azure-Samples/ms-identity-python-daemon/blob/master/1-Call-MsGraph-WithSecret/README.md
}
You can then run this sample with a JSON configuration file:
    python sample.py parameters.json
"""

import sys  # For simplicity, we'll read config file from 1st CLI param sys.argv[1]
import json
import logging
import requests
import msal
import pprint
import chilkat as chilkat


# parsing through the json to find attachments
def load_messages():
    with open('emails.json', 'r') as jsonfile:
        messages = []
        data = json.load(jsonfile)
        for id in data['value']:
            messages.append(id)
        return messages

# counts email items
def get_mail_idz():
    emailidz = []
    emails = load_messages()
    for email in emails:
        emailidz.append(email['id'])
    return emailidz              

def get_token():
# we start by getting a token, accessing the endpoint and saving the data to a file

    # Optional logging
    # logging.basicConfig(level=logging.DEBUG)  # Enable DEBUG log for entire script
    # logging.getLogger("msal").setLevel(logging.INFO)  # Optionally disable MSAL DEBUG logs

    with open("parameters.json", "r") as json_file:
        config = json.load(json_file)

    # Create a preferably long-lived app instance that maintains a token cache.
    app = msal.ConfidentialClientApplication(
        config["client_id"], authority=config["authority"],
        client_credential={"thumbprint": config["thumbprint"], "private_key": open(config['private_key_file']).read()},
        # token_cache=...  # Default cache is in memory only.
                           # You can learn how to use SerializableTokenCache from
                           # https://msal-python.rtfd.io/en/latest/#msal.SerializableTokenCache
        )

    # The pattern to acquire a token looks like this.
    result = None

    # First, the code looks up a token from the cache.
    # Because we're looking for a token for the current app, not for a user,
    # use None for the account parameter.
    result = app.acquire_token_silent(config["scope"], account=None)
    if not result:
        logging.info("No suitable token exists in cache. Let's get a new one from AAD.")
        result = app.acquire_token_for_client(scopes=config["scope"])

    if "access_token" in result:
        # Call a protected API with the access token.
        print('A successful ' + result["token_type"] + ' token obtained!')
    else:
        print(result.get("error"))
        print(result.get("error_description"))
        print(result.get("correlation_id"))  # You might need this when reporting a bug.
    return result    

def __main__():
    result = get_token()
    endpoint = 'https://graph.microsoft.com/v1.0/users/76311a37-4113-4d3e-add1-c4720aeecc6d/mailFolders/Inbox/messages?$search="hasAttachments=true and from:cristian.calinescu@cms-cmno.com"'

    params = {'hasAttachments': 'True'}
    http_headers = {'Authorization': 'Bearer ' + result['access_token'],
                    'Accept': 'application/json',
                    'Content-Type': 'application/json'
                    }
    data = requests.get(endpoint, headers=http_headers, params=params, stream=False).json()
    # save emails to json file
    with open('emails.json', 'w') as jsonfile:
        json.dump(data, jsonfile)

if __name__ == "__main__":
    __main__()
# The Chilkat API can be unlocked for a fully-functional 30-day trial by passing any
# string to the UnlockBundle method.  A program can unlock once at the start. Once unlocked,
# all subsequently instantiated objects are created in the unlocked state. 
# 
# After licensing Chilkat, replace the "Anything for 30-day trial" with the purchased unlock code.
# To verify the purchased unlock code was recognized, examine the contents of the LastErrorText
# property after unlocking.  For example:
glob = chilkat.CkGlobal()
success = glob.UnlockBundle("Anything for 30-day trial")
if (success != True):
    print(glob.lastErrorText())
    sys.exit()

status = glob.get_UnlockStatus()
if (status == 2):
    print("Unlocked using purchased unlock code.")
else:
    print("Unlocked in trial mode.")

# The LastErrorText can be examined in the success case to see if it was unlocked in
# trial more, or with a purchased unlock code.
print(glob.lastErrorText())

http = chilkat.CkHttp()
# we first get the token to authenticate to MS Graph
token = get_token()
token_id = token['access_token']
# then we use the token to issue chilkat requests
http.put_AuthToken(token_id)
# Sends:  GET /users/{user_id | userPrincipalName}/messages/{message_id}/attachments
# Note: It is also possible to use the literal string "me" for the current logged-on user.
# For example: GET /me/messages/{message_id}/attachments
sbResponse = chilkat.CkStringBuilder()
http.ClearUrlVars()
http.SetUrlVar("userPrincipalName","cpsa@cmck.com")
#we've gathered the email id's into the function below
message_ids = get_mail_idz()
# Send the request to download the attachments for each of the emails
for messageid in message_ids:
    http.SetUrlVar("message_id", messageid)
    success = http.QuickGetSb("https://graph.microsoft.com/v1.0/users/{$userPrincipalName}/messages/{$message_id}/attachments", sbResponse)
    if ((success != True) and (http.get_LastStatus() == 0)):
        print(http.lastErrorText())
        sys.exit()

    # The attachment data is contained within the JSON response.
    json = chilkat.CkJsonObject()
    json.LoadSb(sbResponse)
    json.put_EmitCompact(False)
    print("Status code = " + str(http.get_LastStatus()))
    if (http.get_LastStatus() != 200):
        print(json.emit())
        print("Failed.")
    sbSavePath = chilkat.CkStringBuilder()
    attachData = chilkat.CkBinData()
    lastMod = chilkat.CkDateTime()
    fac = chilkat.CkFileAccess()

    i = 0
    numMessages = json.SizeOfArray("value")
    while i < numMessages :
        json.put_I(i)

        print("name: " + json.stringOf("value[i].name"))
        print("contentType: " + json.stringOf("value[i].contentType"))
        sizeInBytes = json.IntOf("value[i].size")
        print("size: " + str(sizeInBytes))

        # Extract the data and save to a file.
        sbSavePath.SetString("C:\\temp\\attachments\\")
        sbSavePath.Append(json.stringOf("value[i].name"))

        attachData.Clear()
        attachData.AppendEncoded(json.stringOf("value[i].contentBytes"),"base64")
        attachData.WriteFile(sbSavePath.getAsString())

        # Get the last-modified date/time and set the output file's last-mod date/time..
        lastMod.SetFromTimestamp(json.stringOf("value[i].lastModifiedDateTime"))
        fac.SetLastModified(sbSavePath.getAsString(),lastMod)

        print("----")

        i = i + 1        