import sys
import time
import re
# import subprocess
# import os
from telnetlib import Telnet
from . import messages

class Mapper:
    ''' Always assume a function leaves the dorado telnet client at
        a prompt.'''

    def __init__(self, host) -> None:
        self.host = host
        self.tn = None
        self.userpass = b'dorado1'
        self.timeout = 10
        self.logged_in = False

    def __enter__(self):
        try:
            self.login()
        except Exception as err:
            print(f'Login failure: {err}')
            self.logged_in = False
            return None

        self.logged_in = True
        return self

    def __exit__(self, type, value, tb):
        if self.logged_in:
           self.logout()

    def send_break(self):
        self.tn.write(b'\x03')

    def wait_for_prompt(self):
        return self.tn.read_until(b"~$ ", self.timeout)

    def print_response(self, response:bytes, test:str='MVC'):
        print(f"[{test}]\t" + response.decode('ascii'))

    def print_info(self, info:str):
        print(f'\t\t\t[INFO]\t{info.upper()}')

    def login(self):
        ''' login to the target machine '''
        self.tn = Telnet(self.host, timeout=1)
        self.tn.read_until(b'login:', self.timeout)
        self.tn.write(self.userpass + b'\r\n')


        self.tn.read_until(b"password:", self.timeout)
        self.tn.write(self.userpass + b'\r\n')

        self.wait_for_prompt()
        self.print_info(f"Logged into {self.host} as {self.userpass.decode('ascii')}")


    def logout(self):
        ''' Logout of session and close the socket. '''
        self.tn.write(b'\x03')
        self.wait_for_prompt()

        self.print_info(f"Logging out from {self.host}")
        self.tn.write(b"exit\n")

        self.tn.read_all()
        self.tn.close()

    def check_date(self):
        ''' Check and read the date '''
        self.print_info('Checking Date')
        self.tn.write(b'date\n')
        date_resp= self.wait_for_prompt().split(b'\r\n')[0]
        self.print_response(date_resp, "DATE")
        return [date_resp]

    def check_ntp(self):
        ''' tail the last message in the xntp server '''
        self.print_info('Checking NTP')
        self.tn.write(b'tail /tmp/xntpd.log\r\n')
        resp = self.wait_for_prompt()
        last_line = resp.split(b'\r\n')
        last_line = last_line[len(last_line)-2]
        self.print_response(last_line, "NTP")
        return [last_line]

    def check_fan_card(self):
        ''' run fanTest and parse humidity/temp '''
        self.tn.write(b'fanTest\r\n')
        self.tn.read_until(b'fanTest>', self.timeout)
        self.tn.write(b'r\r\n')
        sleep_period = 15
        self.print_info(f"fan card test, sleeping for {sleep_period} seconds...")
        time.sleep(sleep_period)

        self.tn.write(b'q\r\nq\r\n')
        resp= self.wait_for_prompt().split(b'\r\n')


        last_resp = []
        for item in messages.fan:
            line = self.search_byte_response(resp, item)
            if line != None: last_resp.append(line)

        for line in last_resp:
            self.print_response(line, "FAN")

        return last_resp

    def check_kearfott(self):
        ''' run check_kearfott and parse ins & gps positions, mode,
            & monitor '''
        self.tn.write(b'check-kearfott\r\n')
        sleep_period = 10
        self.print_info(f"kearfott test, sleeping for {sleep_period} seconds...")
        time.sleep(sleep_period)

        self.tn.write(b'\x03')
        resp = self.wait_for_prompt().split(b'\r\n')
        last_resp = []

        for key, item in messages.kearfott.items():
            line = self.search_byte_response(resp, item)
            if line != None: last_resp.append(line)

        for line in last_resp: self.print_response(line, 'INS')

        return last_resp

    def check_parosci(self):
        ''' run td parosci and parse pressure '''
        self.tn.write(b'td parosci\r\n')
        sleep_period = 30
        self.print_info(f"parosci test, sleeping for {sleep_period} seconds...")
        time.sleep(sleep_period)
        self.tn.write(b'\x03')
        resp= self.wait_for_prompt().split(b'\r\n')
        line = self.search_byte_response(resp, "^Depth:")
        if line != None: self.print_response(line, "PARO")
        return [line]

    def check_fastcat(self):
        ''' run td fastcat and parse messages '''
        self.tn.write(b'td fastcat\r\n')
        sleep_period = 5
        self.print_info(f"fastcat test, sleeping for {sleep_period} seconds...")
        time.sleep(sleep_period)

        self.tn.write(b'\x03')
        resp = self.wait_for_prompt().split(b'\r\n')

        last_resp = []


        for item in messages.fastcat_ctd:
            line = self.search_byte_response(resp, item )
            if line != None: last_resp.append(line)
        for line in last_resp: self.print_response(line, "CTD")

        return last_resp

    def search_byte_response(self, resp:list, reg:str):
        ''' search backwards in a byte response (already split) '''
        rev = resp.copy()
        rev.reverse()
        for line in rev:
            if re.search(reg, line.decode('ascii')) is not None:
                return line
        return None

    def check_benthos_modem(self):
        ''' run a check_modem and issue the +++, ATS?, ATO '''
        self.tn.write(b'check-acomms\r\n')
        self.print_info('Checking benthos modem, ensure magnet removed...')
        time.sleep(1)
        resp = self.tn.read_some()
        for i in range(3):
            self.tn.write(b'+')
            time.sleep(.05)
        resp = self.tn.read_until(b'>', self.timeout)
        if resp == b'':
            self.print_info('No response from modem, check the magnet...')
            self.exit_qtalk()
            self.wait_for_prompt()
            self.print_response(b'ERROR NO RESPONSE','ACOMM')
            return

        self.tn.write(b'ATS?\r\n')
        time.sleep(2)
        self.tn.write(b'ATO\r\n')
        time.sleep(.5)
        resp = self.tn.read_until(b'MGP', self.timeout).split(b'\r\n')
        for line in resp:
            self.print_response(line, f'ACOMM')
        self.exit_qtalk()
        self.wait_for_prompt()
        return resp

    def exit_qtalk(self):
        time.sleep(.1)
        self.tn.write(b'\x01')
        time.sleep(.1)
        self.tn.write(b'q')

    def check_beacon(self):
        ''' run a check_avtrak and issue the CS '''
        self.print_info("Checking Avtrak Beacon...")
        self.tn.write(b'check-avtrak\r\n')
        time.sleep(1.5)
        self.tn.write(b'CS\r\n')
        time.sleep(1.5)
        self.exit_qtalk()
        resp = self.wait_for_prompt().split(b"\r\n")
        resp = self.search_byte_response(resp, '^>CS:')
        self.print_response(resp, 'USBL')
        return [resp]

    def check_reson_ping(self):
        ''' just ping the reson on platform '''

        pass

    def check_edgetech_ping(self):
        ''' just ping the edgetech on platform '''
        pass

    def check_svp(self):
        ''' telnet to the svp port on the battery '''
        self.print_info("checking SVP...")
        self.tn.write(b'check-svp\r\n')
        time.sleep(1)
        self.tn.write(b'~')
        time.sleep(.1)
        self.tn.write(b'quit\r\n')
        resp = self.wait_for_prompt().split(b"\r\n")
        resp = resp[len(resp)-4] #last line prior to tilde
        self.print_response(resp, 'SVP')
        return [resp]

    def check_aft_battery(self):
        ''' telnet to the battery and issue a STATS '''
        return self.check_battery(position='aft')

    def check_fwd_battery(self):
        ''' telnet to the fwd battery and issue a STATS '''
        return self.check_battery(position='fwd')

    def check_battery(self, position:str='aft'):
        ''' telnet to the fwd battery and issue a STATS '''
        try:
            if position == 'aft':
                self.tn.write(b'check-aft-battery\r\n')
            elif position == 'fwd':
                self.tn.write(b'check-fwd-battery\r\n')
            else: return

            self.print_info(f"{position} battery test...")

            # now we're waiting for the battery telnet
            self.tn.read_until(b'battery>', self.timeout)
            time.sleep(.2)
            self.tn.write(b'STATS\r\n')
            time.sleep(.2)
            resp = self.tn.read_until(b'battery>', self.timeout).split(b'\r\n')
            for line in resp:
                self.print_response(line, f'{position.upper()}BT')
            time.sleep(.5)
            # attempt @99RQ request as well
            self.tn.write(b'@99RQ\r\n')
            time.sleep(.2)
            resp = self.tn.read_until(b'battery>', self.timeout).split(b'\r\n')
            chg_state = resp[len(resp)-3] # line that shows charge / discharge status
            self.print_response(chg_state, f'{position.upper()}BT')

        except: pass
        finally: self.tn.write(b'exit\r\n')

        self.wait_for_prompt()
        return resp


    def check_gps(self):
        ''' run td gps and return the stream '''
        self.tn.write(b'td gps\r\n')
        sleep_period = 5
        self.print_info(f"gps test, sleeping for {sleep_period} seconds...")
        time.sleep(sleep_period)

        self.tn.write(b'\x03')
        resp = self.wait_for_prompt().split(b'\r\n')

        last_resp = []
        for key, item in messages.gps.items():
            line = self.search_byte_response(resp,item)
            if line != None: last_resp.append(line)

        for line in last_resp: self.print_response(line, "GPS")

        return last_resp
