#!/usr/bin/python3
#
# SPDX-License-Identifier: Apache-2.0
#

"""
This module provides functionality to send files and directories to remote servers using the
rsync and paramiko libraries.
"""

import getpass
import os
import time
import paramiko
from helper.install_lab import exec_cmd
from utils.install_log import LOG


def sftp_send(source, destination, client_dict):
    """
    Send files to remote server
    """

    remote_host = client_dict["remote_host"]
    username = client_dict["username"]
    sftp_client = None

    LOG.info("Connecting to server %s with username %s", remote_host, username)

    ssh_client = paramiko.SSHClient()
    ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())

    # TODO(WEI): need to make this timeout handling better
    retry = 0
    while retry < 8:
        try:
            ssh_client.connect(
                remote_host,
                port=client_dict["remote_port"],
                username=username,
                password=client_dict["password"],
                look_for_keys=False,
                allow_agent=False
            )
            sftp_client = ssh_client.open_sftp()
            retry = 8
        except Exception:  # pylint: disable=W0703
            LOG.warning("******* try again")
            retry += 1
            LOG.info("Waiting 10s")
            time.sleep(10)

    LOG.info("Sending file from %s to %s", source, destination)
    if sftp_client:
        sftp_client.put(source, destination)
        LOG.info("Done")
        sftp_client.close()
    ssh_client.close()


# pylint: disable=R0801
def send_dir(params_dict):
    """
    Send directory `source` to remote host `remote_host` at port `remote_port` and destination
    `destination` using `rsync` over `ssh`.

    Args:
        params_dict (dict): A dictionary containing the following keys:
            - source (str): The local directory to be sent.
            - remote_host (str): The IP address or domain name of the remote host.
            - remote_port (int): The port number of the remote host to connect to.
            - destination (str): The remote directory to copy `source` into.
            - username (str): The username for the SSH connection.
            - password (str): The password for the SSH connection.
            - follow_links (bool, optional): Whether to follow symbolic links when
                copying files. Default is True.
            - clear_known_hosts (bool, optional): Whether to clear the known_hosts file
                before making the SSH connection. Default is True.

    Raises:
        Exception: If there is an error in `rsync`, raises an exception with the return code.

    Note:
        This method only works from a Linux environment.
    """

    source = params_dict['source']
    remote_host = params_dict['remote_host']
    remote_port = params_dict['remote_port']
    destination = params_dict['destination']
    username = params_dict['username']
    password = params_dict['password']
    follow_links = params_dict.get('follow_links', True)
    clear_known_hosts = params_dict.get('clear_known_hosts', True)

    # Only works from linux for now
    if not source.endswith('/') or not source.endswith('\\'):
        source = source + '/'

    follow_links = "L" if follow_links else ""
    if clear_known_hosts:
        if remote_host == '127.0.0.1':
            keygen_arg = f"[127.0.0.1]:{remote_port}"
        else:
            keygen_arg = remote_host
        cmd = f'ssh-keygen -f \
                    "/home/{getpass.getuser()}/.ssh/known_hosts" -R {keygen_arg} 2>/dev/null'
        exec_cmd(cmd)

    LOG.info('#### Running rsync of dir: %s -> %s@%s:%s', source, username, remote_host, destination)
    cmd = (f'rsync -av{follow_links} --rsh="/usr/bin/sshpass -p {password} '
           f'ssh -p {remote_port} -o StrictHostKeyChecking=no -l {username}" '
           f'{source}* {username}@{remote_host}:{destination}')
    exec_cmd(cmd)


def send_dir_fallback(source, remote_host, destination, username, password):
    """
    Send directory contents to remote server, usually controller-0
    Note: does not send nested directories only files.
    args:
    - source: full path to directory
    e.g. /localhost/loadbuild/jenkins/latest_build/
    - Remote host: name of host to log into, controller-0 by default
    e.g. myhost.com
    - destination: where to store the file on host: /home/myuser/
    """

    LOG.info("Connecting to server %s with username %s", remote_host, username)
    ssh_client = paramiko.SSHClient()
    ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    ssh_client.connect(
        remote_host,
        username=username,
        password=password,
        look_for_keys=False,
        allow_agent=False
    )
    sftp_client = ssh_client.open_sftp()
    send_img = False
    for items in os.listdir(source):
        path = source + items
        if os.path.isfile(path):
            if items.endswith('.img'):
                remote_path = destination + 'images/' + items
                LOG.info("Sending file from %s to %s", path, remote_path)
                sftp_client.put(path, remote_path)
                send_img = True
            elif items.endswith('.iso'):
                pass
            else:
                remote_path = destination + items
                LOG.info("Sending file from %s to %s", path, remote_path)
                sftp_client.put(path, remote_path)
    LOG.info("Done")
    sftp_client.close()
    ssh_client.close()
    if send_img:
        LOG.info("Waiting 10s")
        time.sleep(10)