import threading
import os
import re
import time

from scp import SCPClient
import dearpygui.dearpygui as dpg
import paramiko

from utils import show_status_text


HOST = 'geophyslab.srcc.msu.ru'
URBAN_LES_REPOS = (
    'git clone http://{username}:{password}@tesla.parallel.ru/emortikov/nselibx-common.git',
    'git clone http://{username}:{password}@tesla.parallel.ru/emortikov/nselibx-wstgrid.git',
    'git clone http://{username}:{password}@tesla.parallel.ru/emortikov/nse-gabls1-urban-les.git'
)

def build_model(server_username, server_password, gitlab_username, gitlab_password, repos=URBAN_LES_REPOS):
    try:
        ssh = paramiko.SSHClient()
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        ssh.connect(HOST, username=server_username, password=server_password)

        commands = [
            'mkdir run',
            'cd ./run'
        ]

        for repo in repos:
            commands.append(repo.format(username=gitlab_username, password=gitlab_password))
        
        commands += [
            'cd ./nse-gabls1-urban-les/nse-gabls1-urban-les/',
            'chmod +x cpall.sh',
            './cpall.sh ../../code',
            'cd ../../code',
            'make -B MACHINE=local COMPILER=gnu -j 23',
        ]

        commands = '; '.join(commands)

        show_status_text(f'building model')
        dpg.show_item('loading')
        x, y = dpg.get_item_pos('status_text')
        dpg.set_item_pos('loading', (x - 40, y))

        stdin, stdout, stderr = ssh.exec_command(commands)
        
        with open('log.txt', 'w') as file:
            file.write(stdout.read().decode())

        ssh.close()

        show_status_text('')
        dpg.hide_item('loading')
        
        show_status_text('model builded:) log written to log.txt.')
    
    except Exception as e:
        show_status_text(f'error: {str(e)}')

def make_run_command():
    command = f'mpirun -np {int(dpg.get_value('-np'))} ./nsenx'
    if dpg.get_value('-arch') != 'cpu':
        command += f' -arch {dpg.get_value('-arch')}'
    if dpg.get_value('use-udump'):
        command += f' -udump {dpg.get_value('-udump')}'
    if dpg.get_value('use-model-output'):
        command += f' -model-output {dpg.get_value('-model-output')}'
    return command

def run_on_lab_server(username, password):
    try:
        show_status_text('model running...')
        dpg.show_item('progress_bar')
        ssh = paramiko.SSHClient()
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        ssh.connect(HOST, username=username, password=password)
        
        scp = SCPClient(ssh.get_transport())
        
        scp.put('tmp.txt', 'run/code/config.txt')

        command = make_run_command()

        commands = [
            'cd ./run',
            'cd ./code',
            command
        ]

        commands = '; '.join(commands)

        log = ''

        stdin, stdout, stderr = ssh.exec_command(commands)

        while not stdout.channel.exit_status_ready():
            if stdout.channel.recv_ready():
                output = stdout.channel.recv(512).decode()
                update_progress(output)
                log += '\n\n' + output
            # time.sleep(1)

        output = stdout.read().decode()
        dpg.set_value('progress_bar', 1.)

        log += '\n\n' + output
        
        with open('log.txt', 'w') as file:
            file.write(log)
        
        scp.close()
        ssh.close()
        
        dpg.hide_item('progress_bar')
        show_status_text('success:) log written to log.txt.')
    
    except Exception as e:
        show_status_text(f'error: {str(e)}')

def update_progress_building_model():
    show_status_text(f'building model')
    dpg.show_item('loading')
    x, y = dpg.get_item_pos('status_text')
    dpg.set_item_pos('loading', (x - 40, y))

def update_progress(output):
    if not re.findall(r'([0-9]+)%', output):
        progress = 0.0
    else:
        progress = int(re.findall(r'([0-9]+)%', output)[-1]) / 100
    dpg.set_value('progress_bar', progress)

def start_remote_execution(server_username, server_password):
    threading.Thread(target=run_on_lab_server, args=(server_username, server_password)).start()

def start_model_build(server_username, server_password, gitlab_username, gitlab_password):
    threading.Thread(target=build_model, args=(server_username, server_password, gitlab_username, gitlab_password)).start()

def get_server_output_structure(username, password):
    try:
        ssh = paramiko.SSHClient()
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        ssh.connect(HOST, username=username, password=password)

        stdin, stdout, stderr = ssh.exec_command('cd ./run/code/output; find . -type f')

        output = stdout.read().decode()
        
        ssh.close()

        return output
    
    except Exception as e:
        show_status_text(f'error: {str(e)}')