import time
from tr069_request import AcsRequest
from datetime import datetime

acs = AcsRequest()

def calculate_test_speed(bom_time, eom_time, test_bytes_received):
    bom_datetime = datetime.fromisoformat(bom_time[:-1])
    eom_datetime = datetime.fromisoformat(eom_time[:-1])

    time_taken = (eom_datetime - bom_datetime).total_seconds()
    download_speed_bps = test_bytes_received / time_taken

    download_speed_mbps = download_speed_bps * 8 / 1024 / 1024

    return download_speed_mbps

#Faz o refresh do objeto para forçar a cpe a atualizar
ret = acs.send_request({"name": "refreshObject", "objectName": "Device.IP.Diagnostics.DownloadDiagnostics.DiagnosticsState"})
if ret.status_code != 200:
    print("Erro ao fazer o refresh do objeto: ", str(ret.status_code))

#Seta a URL de download
parameter_values = ["Device.IP.Diagnostics.DownloadDiagnostics.DownloadURL","http://tr143.venko.local/download/speed_test", "xsd:string"]
ret = acs.send_request({"name": "setParameterValues", "parameterValues": [parameter_values]})
if ret.status_code != 200:
    print("Erro ao alterar a URL de download:", str(ret.status_code))

#Seta a quantidade de conexões simultâneas com o server http
parameter_values = ["Device.IP.Diagnostics.DownloadDiagnostics.NumberOfConnections","1", "xsd:unsignedInt"]
ret = acs.send_request({"name": "setParameterValues", "parameterValues": [parameter_values]})
if ret.status_code != 200:
    print("Erro ao alterar a quantidade de conexões simultâneas para download:", str(ret.status_code))

time.sleep(5)

#Solicita o download
parameter_values = ["Device.IP.Diagnostics.DownloadDiagnostics.DiagnosticsState", "Requested", "xsd:string"]
ret = acs.send_request({"name": "setParameterValues", "parameterValues": [parameter_values]})
if ret.status_code != 200:
    print("Erro ao solicitar o download:", str(ret.status_code))

count = 0
while count < 120:

    ret = acs.send_request({"name": "refreshObject", "objectName": "Device.IP.Diagnostics.DownloadDiagnostics"})

    if ret.status_code != 200:
        print("Erro ao fazer o refresh do objeto: ", str(ret.status_code))
        break
    elif ret.status_code == 202:
        print("Download em progresso.")
    elif ret.status_code == 200:
        ret_query = acs.get_value_from_task()
        json_data = ret_query.json()[0]
        download_diagnostics = json_data.get('Device', {}).get('IP', {}).get('Diagnostics', {}).get('DownloadDiagnostics', {})
        downloadState = download_diagnostics.get('DiagnosticsState', {}).get('_value', '')

        if downloadState == 'Completed':
            print("Download completo.")
            bom_time = json_data['Device']['IP']['Diagnostics']['DownloadDiagnostics']['BOMTime']['_value']
            eom_time = json_data['Device']['IP']['Diagnostics']['DownloadDiagnostics']['EOMTime']['_value']
            test_bytes_received = json_data['Device']['IP']['Diagnostics']['DownloadDiagnostics']['TestBytesReceived']['_value']
            download_speed = calculate_test_speed(bom_time, eom_time, test_bytes_received)
            print(f"Download Speed: {download_speed:.2f} Mbps")
            break
    else:
        print("Status do download desconhecido: ", str(ret.status_code))

    time.sleep(1)
    count += 1

#UPLOAD
#Faz o refresh do objeto para forçar a cpe a atualizar
ret = acs.send_request({"name": "refreshObject", "objectName": "Device.IP.Diagnostics.UploadDiagnostics.DiagnosticsState"})
if ret.status_code != 200:
    print("Erro ao fazer o refresh do objeto: ", str(ret.status_code))

#Seta a URL de Upload do teste
parameter_values = ["Device.IP.Diagnostics.UploadDiagnostics.UploadURL","http://tr143.venko.local/upload/", "xsd:string"]
ret = acs.send_request({"name": "setParameterValues", "parameterValues": [parameter_values]})
if ret.status_code != 200:
    print("Erro ao alterar a URL de upload:", str(ret.status_code))

#Seta o tamanho do upload
parameter_values = ["Device.IP.Diagnostics.UploadDiagnostics.TestFileLength","304557665", "xsd:unsignedInt"]
ret = acs.send_request({"name": "setParameterValues", "parameterValues": [parameter_values]})
if ret.status_code != 200:
    print("Erro ao alterar o tamanho do arquivo de upload:", str(ret.status_code))

#Seta a quantidade de conexões simultâneas com o server http
parameter_values = ["Device.IP.Diagnostics.UploadDiagnostics.NumberOfConnections","1", "xsd:unsignedInt"]
ret = acs.send_request({"name": "setParameterValues", "parameterValues": [parameter_values]})
if ret.status_code != 200:
    print("Erro ao alterar a quantidade de conexões simultâneas para o upload:", str(ret.status_code))

time.sleep(5)

#Solicita o teste de upload para a CPE
parameter_values = ["Device.IP.Diagnostics.UploadDiagnostics.DiagnosticsState", "Requested", "xsd:string"]
ret = acs.send_request({"name": "setParameterValues", "parameterValues": [parameter_values]})
if ret.status_code != 200:
    print("Erro ao solicitar o upload:", str(ret.status_code))


count = 0
while count < 50:

    ret = acs.send_request({"name": "refreshObject", "objectName": "Device.IP.Diagnostics.UploadDiagnostics"})

    if ret.status_code != 200:
        print("Erro ao fazer o refresh do objeto: ", str(ret.status_code))
        break
    elif ret.status_code == 202:
        print("Upload em progresso.")
    elif ret.status_code == 200:
        ret_query = acs.get_value_from_task()
        json_data = ret_query.json()[0]
        upload_diagnostics = json_data.get('Device', {}).get('IP', {}).get('Diagnostics', {}).get('UploadDiagnostics', {})
        uploadState = upload_diagnostics.get('DiagnosticsState', {}).get('_value', '')

        if uploadState == 'Completed':
            print("Upload completo.")
            bom_time = json_data['Device']['IP']['Diagnostics']['UploadDiagnostics']['BOMTime']['_value']
            eom_time = json_data['Device']['IP']['Diagnostics']['UploadDiagnostics']['EOMTime']['_value']
            test_bytes_sent = json_data['Device']['IP']['Diagnostics']['UploadDiagnostics']['TestBytesSent']['_value']
            upload_speed = calculate_test_speed(bom_time, eom_time, test_bytes_sent)
            print(f"Upload Speed: {upload_speed:.2f} Mbps")
            break
    else:
        print("Status do upload desconhecido: ", str(ret.status_code))

    time.sleep(1)
    count += 1

#ICMP
#Faz o refresh do objeto para forçar a cpe a atualizar
ret = acs.send_request({"name": "refreshObject", "objectName":"Device.IP.Diagnostics.IPPing"})
if ret.status_code != 200:
    print("Erro ao solcitar o refresh da solcitação: ". str(ret))

#Seta o host de destino do teste de PING
parameter_values = ["Device.IP.Diagnostics.IPPing.Host", "10.5.9.159", "xsd:string"]
ret = acs.send_request({"name": "setParameterValues", "parameterValues": [parameter_values]})
if ret.status_code != 200:
    print("Erro ao alterar o host de destino:", str(ret))

parameter_values = ["Device.IP.Diagnostics.IPPing.NumberOfRepetitions", "10", "xsd:unsignedInt"]
ret = acs.send_request({"name": "setParameterValues", "parameterValues": [parameter_values]})
if ret.status_code != 200:
    print("Erro ao alterar a quantidade de requisições:", str(ret))

time.sleep(5)

#Faz a solicitação para envio do PING
parameter_values = ["Device.IP.Diagnostics.IPPing.DiagnosticsState", "Requested", "xsd:string"]
ret = acs.send_request({"name": "setParameterValues", "parameterValues": [parameter_values]})
if ret.status_code != 200:
    print("Erro na solicitação do ping: ", str(ret))

count = 0
while count < 120:

    ret = acs.send_request({"name": "refreshObject", "objectName": "Device.IP.Diagnostics.IPPing"})

    if ret.status_code != 200:
        print("Erro ao fazer o refresh do objeto: ", str(ret.status_code))
        break
    elif ret.status_code == 202:
        print("Ping em progresso.")
    elif ret.status_code == 200:
        ret_query = acs.get_value_from_task()
        json_data = ret_query.json()[0]
        ping_diagnostics = json_data.get('Device', {}).get('IP', {}).get('Diagnostics', {}).get('IPPing', {})
        pingState = ping_diagnostics.get('DiagnosticsState', {}).get('_value', '')

        if pingState == 'Complete':
            print("Ping completo.")
            averageResponseTime = json_data['Device']['IP']['Diagnostics']['IPPing']['AverageResponseTimeDetailed']['_value']
            maximumResponseTime = json_data['Device']['IP']['Diagnostics']['IPPing']['MaximumResponseTimeDetailed']['_value']
            minimumResponseTime = json_data['Device']['IP']['Diagnostics']['IPPing']['MinimumResponseTimeDetailed']['_value']
            numberOfRepetitions = json_data['Device']['IP']['Diagnostics']['IPPing']['NumberOfRepetitions']['_value']
            successCount = json_data['Device']['IP']['Diagnostics']['IPPing']['SuccessCount']['_value']
            #Converte de microsegundos para milissegundos
            averageResponseTime = averageResponseTime / 1000
            maximumResponseTime = maximumResponseTime / 1000
            minimumResponseTime = minimumResponseTime / 1000
            #Porcentagem de perda do ping
            packet_loss_percentage = ((numberOfRepetitions - successCount) / numberOfRepetitions) * 100
            #imprime os resultados
            print(f'{numberOfRepetitions} pacotes enviados, {successCount} recebidos, {packet_loss_percentage:.2f}% de perda de pacotes.')
            print(f'rtt min/avg/max = {minimumResponseTime}/{averageResponseTime}/{maximumResponseTime}' ' ms')
            break
    else:
        print("Status do ping desconhecido: ", str(ret.status_code))

    time.sleep(1)
    count += 1