import datetime
import time
import json
from datetime import datetime
from py_dotenv import read_dotenv
import os
import paramiko
import paho.mqtt.client as mqtt
import subprocess

from gtts import gTTS
from pydub import AudioSegment
from pydub.playback import play

read_dotenv("/home/orangepi/opencv/.env")
idsystem       =os.getenv("id")
directory_path =os.getenv("path_captures")

sftp_host     = os.getenv("ssh_host")
sftp_port     = int(os.getenv("ssh_port"))
sftp_username = os.getenv("ssh_user")
sftp_password = os.getenv("ssh_pass")


mqtt_host     = str(os.getenv("mqtt_host"))
mqtt_port     = int(os.getenv("mqtt_port"))
mqtt_keepalive= int(os.getenv("mqtt_keepalive"))

branding      = os.getenv("branding")

remote_directory = os.getenv("ssh_folder_path")+idsystem
fecha_systema=datetime.now().strftime("%Y-%m-%d %H:%M:%S")


def playaudio(client,text):
    tts= gTTS(text,lang='es')
    tts.save("voicetmp.mp3")
    audio=AudioSegment.from_mp3("voicetmp.mp3")
    play(audio)


def list_directory_content(directory_path):

    heardbeat     =[]
    content_list  =[]

    if os.path.exists(directory_path) and os.path.isdir(directory_path):
        dir_content = os.listdir(directory_path)
        for item in dir_content:
            item_path = os.path.join(directory_path, item)
            if os.path.isfile(item_path):
                file_size = os.path.getsize(item_path)
                modification_time = os.path.getmtime(item_path)
                modification_time_str = datetime.fromtimestamp(modification_time).isoformat()

                content_list.append({
                    'type': 'file',
                    'name': item,
                    'size': file_size,
                    'modification_time': modification_time_str
                })
            elif os.path.isdir(item_path):
                content_list.append({
                    'idsystem': idsystem,
                    'type': 'directory',
                    'name': item,
                    'content': list_directory_content(item_path)  # Listar contenido recursivamente
                })
    return content_list


def transfer_file_content():

    try:

        transport = paramiko.Transport((sftp_host, sftp_port))
        transport.sock.settimeout(1)
        transport.connect(username=sftp_username, password=sftp_password)
        sftp = paramiko.SFTPClient.from_transport(transport)
        channel=sftp.get_channel()
        channel.settimeout(10)
        sftp.put("/home/orangepi/opencv/listadodirectorios.json", remote_directory+f"/listadodirectorios.json")
        sftp.close()

    except socket.timeout:
        print("time out...")
    except Exception as e:
        print("error")
    finally:
        print("ffinaly")

def transfer_streaming(client):

    try:

        ssh_client = paramiko.SSHClient()
        ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        ssh_client.connect(sftp_host, username=sftp_username, password=sftp_password,port=sftp_port)
        stdin, stdout, stderr = ssh_client.exec_command(f"mkdir -p {remote_directory}/cam1/last/")
        #stdin, stdout, stderr = ssh_client.exec_command(f"mkdir -p {remote_directory}/cam3/last/")
        stdin, stdout, stderr = ssh_client.exec_command(f"mkdir -p {remote_directory}/cam5/last/")
        stdin, stdout, stderr = ssh_client.exec_command(f"mkdir -p {remote_directory}/cam7/last/")
        
        ssh_client.close()

        try:
            transport = paramiko.Transport((sftp_host, sftp_port))
            transport.sock.settimeout(1)
            transport.connect(username=sftp_username, password=sftp_password)

            sftp = paramiko.SFTPClient.from_transport(transport)

            channel=sftp.get_channel()
            channel.settimeout(10)

            end_time = time.time() + 1  * 60

            while time.time()<end_time:

                sftp.put("/home/orangepi/opencv/captures/cam1/last/5.jpg", remote_directory+f"/cam1/last/last.jpg")
                sftp.put("/home/orangepi/opencv/captures/cam5/last/5.jpg", remote_directory+f"/cam5/last/last.jpg")
                sftp.put("/home/orangepi/opencv/captures/cam7/last/5.jpg", remote_directory+f"/cam7/last/last.jpg")

              
                #sftp.put("/home/orangepi/opencv/captures/cam5/last/last.jpg", remote_directory+"/cam5/last/last.jpg")

                time.sleep(1) #4fps

        except socket.timeout:
            print("time out...")
            client.publish("mqttnubbe/cameras/status",json.dumps({"idsystem":idsystem,"lbl":"Problemas al establecer conexion de  streaming (timeout)","id":103}))
        except Exception as e:
            print("error transferencia")
            client.publish("mqttnubbe/cameras/status",json.dumps({"idsystem":idsystem,"lbl":"Error durante streaming","id":102}))
        finally:
            print("ffinaly")
            client.publish("mqttnubbe/cameras/status",json.dumps({"idsystem":idsystem,"lbl":"Termina  streaming","id":101}))


    except Exception as e:
        sftp.close()


def ejecutar_comando(client,comando):

    client.publish("mqttnubbe/cameras/status",json.dumps({"idsystem":idsystem,"lbl":"Ejecutar comando remoto","id":200}))

    resultado = subprocess.run(comando, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
    client.publish("mqttnubbe/cameras/respuestas/cmd",json.dumps({"idsystem":idsystem,"resultado":resultado.stdout,"solicitud":comando}))
    print("Salida estándar:")
    print(resultado.stdout)
    print("Salida de error:")
    print(resultado.stderr)


def transfer_file(client,path_transfer_file):

    try:
        print(path_transfer_file)

        datefilename=datetime.now().strftime("%Y-%m-%d")

        nwName=path_transfer_file.split("/")
        ssh_client = paramiko.SSHClient()
        ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        ssh_client.connect(sftp_host, username=sftp_username, password=sftp_password,port=sftp_port)
        stdin, stdout, stderr = ssh_client.exec_command(f"mkdir -p {remote_directory}/{nwName[0]}/{nwName[1]}/{nwName[2]}")
        ssh_client.close()

        transport = paramiko.Transport((sftp_host, sftp_port))
        transport.connect(username=sftp_username, password=sftp_password)
        sftp = paramiko.SFTPClient.from_transport(transport)

        channel=sftp.get_channel()
        channel.settimeout(10)

        sftp.put("/home/orangepi/opencv/captures/"+path_transfer_file, remote_directory+"/"+path_transfer_file)

        sftp.close()
        transport.close()
    except Exception as e:
        client.publish("mqttnubbe/cameras/status",json.dumps({"idsystem":idsystem,"lbl":"Error durante la transferencia de archivo","id":401}))
        print("error al transferir...")



def on_message(client, userdata, msg):


    try:
        timelog=datetime.now().strftime("%Y-%m-%dT%H:%M:%S")
        print(msg.payload.decode())
        params = json.loads(msg.payload.decode())

        client.publish("mqttnubbe/cameras/status",json.dumps({"idsystem":idsystem,"lbl":params['cmd'],"id":500}))

        if params['cmd']=='get_list_dir':
            lsd=list_directory_content(directory_path)
            listado=json.dumps(lsd)
            with open("/home/orangepi/opencv/listadodirectorios.json","w")as archivo:
                archivo.write(listado)
            transfer_file_content()
            client.publish("mqttnubbe/cameras/respuestas/get_list_dir",json.dumps({"idsystem":idsystem}))

        if params['cmd']=='transfer_file':
            transfer_file(client,params['params']['path'])

        if params['cmd']=='streaming':
            transfer_streaming(client)

        if params['cmd']=='ejecutar':
            ejecutar_comando(client,params['params']['exec'])

        if params['cmd']=='texttovoice':
            playaudio(client,params['params']['text'])

    except Exception as e:
        print (e)


def on_connect(client, userdata, flags, rc):
    print("Conectado al broker con código resultante: " + str(rc))
    client.subscribe(f"mqttnubbe/cameras/comandos/{idsystem}")


def inicializacion():

    try:
        client = mqtt.Client()
        client.on_connect = on_connect
        client.on_message = on_message
        client.connect(mqtt_host,mqtt_port,mqtt_keepalive)
        client.loop_forever()
    except Exception as e:
        print("error mqtt inicializacion...")
        inicializacion()


if __name__ == "__main__":
    inicializacion()
