import json, boto3, os
from boto3.dynamodb.conditions import Key, Attr
from datetime import datetime, timedelta
from decimal import Decimal

client = boto3.client('dynamodb')
connect = boto3.client('connect')
dynamodb = boto3.resource('dynamodb')

def lambda_handler(event, context):

    ma = os.environ['maxAttempts']
    minbc = int(os.environ['minutesBetweenCalls'])
    Q = os.environ['queue']
    minFA = os.environ['minFreeAgents']
    cFlowID = os.environ['cFlowID']
    cID = os.environ['instance']
    sNum = os.environ['sourcePhoneNumber']
    dtbl = os.environ['dynamoTable']
    index = os.environ['index']
    minbs = int(os.environ['minutesBetweenSuccesses'])

    #aAgents = GetConnectMetric(Q, cID)
    aAgents = 1 # hard coded for now...
    result = 'none'
    if (aAgents >= int(minFA)):
        print("Ready!  available agents: " + str(aAgents))

        result = queryDDB(dtbl, index, minbc, ma, minbs)
        print(result)
        if(result['Count'] > 0):
            callOutbound(result['Items'], cFlowID, cID, sNum, dtbl) 
        else:
            print('No numbers ready')
    else:
        print("no avail agents: " + str(aAgents))

    # reset if attempts is eq maxAttempts, reset if attempt time is older than (minutesBetweenSuccesses) 24 hours
    resetMaxAttempts(dtbl, index, ma, minbs)
    
    return {
        'statusCode': 200,
        'body': json.dumps(result, default=decimaldefault)
    }


def queryDDB(table, index, minInterval, maxAttempts, successInterval):

    table = dynamodb.Table(table)

    lastSuccessThreshold = Decimal((datetime.now() - timedelta(minutes=successInterval)).timestamp())
    print(lastSuccessThreshold)
    lastAttemptThreshold = Decimal((datetime.now() - timedelta(minutes=minInterval)).timestamp())
    print(lastAttemptThreshold)

    response = table.query(
        IndexName='Enabled-lastSuccess-index',
        KeyConditionExpression=Key('Enabled').eq('1') & Key('lastSuccess').lt(lastSuccessThreshold),
        FilterExpression=Attr('lastAttempt').lt(lastAttemptThreshold) & Attr('contactAttempts').lt(str(maxAttempts))
    )
    
    #response = table.query(
    #    IndexName=index,
    #    KeyConditionExpression=Key('SuccessfulConnection').eq('0'),
    #    FilterExpression=Attr('lastAttempt').lt(lastAttemptDate)&Attr('contactAttempts').lt(str(maxAttempts))
    #)

    print('Query Results: ' + str(response['Count']))
    return response


def callOutbound(phoneNumbers, cFlowID, cID, sNum, table):
    # Start outbound call for each entry and update entry in DB

    for item in phoneNumbers:
        formatted = item['TelephoneNumber']
        print('Attempting Call:  ' + formatted)

        try:
            response = connect.start_outbound_voice_contact(
                DestinationPhoneNumber=formatted,
                ContactFlowId=cFlowID,
                InstanceId=cID,
                SourcePhoneNumber=sNum
            )
            print('Call success for: ' + formatted)
        except Exception as inst:
            print('Error: ', inst )

        CA = client.get_item(
            TableName=table,
            Key={
                'TelephoneNumber': {
                    'S': item["TelephoneNumber"]
                }
            },
            AttributesToGet=['contactAttempts']
        )
        print('Existing attempts for ' + formatted + ':  ' + str(CA['Item']['contactAttempts']['S']))
        counter = int(CA['Item']['contactAttempts']['S'])
        counter += 1

        #publishCWMetric()

        client.update_item(
            TableName=table,
            Key={
                'TelephoneNumber': {
                    'S': item["TelephoneNumber"]
                }
            },
            UpdateExpression="set contactAttempts =:attempts, lastAttempt=:time, lastAttemptDateTime=:dttime",
            ExpressionAttributeValues={
                ':attempts': {'S': str(counter)},':time':{'N': str(datetime.now().timestamp())}, ':dttime':{'S':datetime.now().isoformat()}
            },
        )


def GetConnectMetric(Q, cID):
    response = connect.get_current_metric_data(
        InstanceId=cID,
        Filters={
            'Queues': [
                Q,
            ],
            'Channels': [
                'VOICE',
            ]
        },
        Groupings=[
            'QUEUE',
        ],
        CurrentMetrics=[
            {
                'Name': 'AGENTS_AVAILABLE',
                'Unit': 'COUNT'
            },
        ]
    )

    if not response["MetricResults"]:
        return 0
    else:
        return response["MetricResults"][0]["Collections"][0]["Value"]

def decimaldefault(obj):
    if isinstance(obj, Decimal):
        return float(obj)
    raise TypeError


## Function to reset if attempts is eq maxAttempts, reset if attempt time is older than (minutesBetweenSuccesses) 24 hours
def resetMaxAttempts(table, index, maxAttempts, successInterval):

    table = dynamodb.Table(table)

    lastSuccessThreshold = Decimal((datetime.now() - timedelta(minutes=successInterval)).timestamp())
    print(lastSuccessThreshold)

    response = table.query(
        IndexName='Enabled-lastSuccess-index',
        KeyConditionExpression=Key('Enabled').eq('1') & Key('lastSuccess').lt(lastSuccessThreshold),
        FilterExpression=Attr('lastAttempt').lt(lastSuccessThreshold)&Attr('contactAttempts').gte(str(maxAttempts))
    )
    
    for item in response['Items']:
        phnum = item['TelephoneNumber']
        print("phnum: " + phnum)
        
        updateresponse = client.update_item(
            TableName=table.name,
            Key={
                'TelephoneNumber':{
                    'S': phnum
                }
            },
            UpdateExpression="set contactAttempts =:attempts",
            ExpressionAttributeValues={
                ':attempts': {'S': '0'}
            },
        )
    return response