#!/usr/bin/env python3
import json
import os
import requests
import sys
import time

from runbookpy import agent, utils
from requests.packages.urllib3.exceptions import InsecureRequestWarning

# Ignore bad HTTPS certs
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)


# Call the API
def call_api(sid, system, api_version, path):
    url = f'https://{system}/api/{api_version}/{path}'

    headers = {'Authorization': f'Token {sid}'}

    r = requests.get(url, headers=headers, verify=False)

    return json.loads(r.text)

import json

def get_session_id(system, password):
    url = f'https://{system}/api/v1/sessions/'
    data = {'username': 'root', 'password': password}

    try:
        r = requests.post(url, verify=False, data=json.dumps(data))
        r.raise_for_status()  # Raise an HTTPError for bad responses (4xx and 5xx)

        session_data = json.loads(r.text)
        if session_data['state'] == "authenticated":
            sid = session_data['session']
        else:
            final_return(False, "Failed to get SID")
    except requests.exceptions.ConnectionError as e:
        if 'No route to host' in str(e):
            print("No route to host")
            exit(1)
        else:
            print(f"Connection error: {e}")
            exit(2)
    return sid

# Get the API version
def get_api_version(sid, system):
    url = f'https://{system}/api/v1.3/system/version'

    headers = {'Authorization': f'Token {sid}'}

    r = requests.get(url, headers=headers, verify=False)

    version_data = json.loads(r.text)

    api_version = version_data['system_version']['rest_api_version']

    return api_version

# Return 
def final_return(state, message):
    if state:
        print(json.dumps({'message': message, 'status': 'Success'}))
        sys.exit(0)
    else:
        print(json.dumps({'message': message, 'status': 'Failed'}))
        sys.exit(1)

# Get node description
def get_node_description(sid, hostname, api_version):
    utc_ms = int(time.time()*1000)
    node_description = call_api(sid, hostname, api_version, "nodeDescription")

    node_description = [node_description['hostname'], node_description['interfaces'][0]['ipv4_addresses'][0],node_description['interfaces'][0]['ipv6_addresses'][0], node_description['serial_number'], node_description['model_number'], node_description['mac_address'], node_description['firmware_version']]

    node_desc_tsv = utils.list_to_tsv([node_description])

    end_time = int(time.time()*1000)
    duration_ms = end_time - utc_ms

    print(agent.make_tsv("cmd", "opengear-get-description", utc_ms, srcname="opengear-api", content=node_desc_tsv, duration_ms=duration_ms, parserok="on", method="opengear-monitor", colnames="hostname,ipv4,ipv6,serialnumber,modelnumber,macaddress,firmwareversion"))

# Get serial ports
def get_serial_ports(sid, hostname, api_version):
    utc_ms = int(time.time()*1000)
    serial_ports = call_api(sid, hostname, api_version, "serialPorts")

    serial_port_tsv = []

    for sp in serial_ports['serialports']:
        if "consoleServer" in sp['modeSettings']:
            serial_port_tsv.append([sp['label'], sp['id'], str(sp['modeSettings']['consoleServer']['ssh']['enabled']), str(sp['modeSettings']['consoleServer']['telnet']['enabled']), sp['hardwareSettings']['uart']['baud']])
        else:
            serial_port_tsv.append([sp['label'], sp['id'], "unknown", "unknown", sp['hardwareSettings']['uart']['baud']])

    serial_port_tsv = utils.list_to_tsv(serial_port_tsv)
    
    end_time = int(time.time()*1000)
    duration_ms = end_time - utc_ms

    print(agent.make_tsv("cmd", "opengear-serial-port", utc_ms, srcname="opengear-api", content=serial_port_tsv, duration_ms=duration_ms, parserok="on", method="opengear-monitor", colnames="label,id,ssh,telnet,baud"))

if __name__ == "__main__":
    if len(sys.argv) < 4:
        final_return(False, "Missing CLI Arguments.")

    # Define system
    ip      = sys.argv[1]
    user    = sys.argv[2]
    command = sys.argv[3]

    if len(sys.argv) > 4:
        command = sys.argv[3:]
        command = " ".join(command)
    else:
        command = sys.argv[3]

    # Get password from env variable
    password = os.getenv("OPENGEAR_PASSWORD")

    if password == '':
        final_return(False, "Password in correct.")

    # Check if IP address is IPv6, if so, add some [] for HTTP routing
    if ':' in ip:
        ip = f"[{ip}]"
    else:
        ip = ip

    # try:
    # Get Session ID
    sid = get_session_id(ip, password)

    # Get API Version, so we can always use the latest API
    api_version = get_api_version(sid, ip)

    # Check commands
    if command == "get description":
        get_node_description(sid, ip, api_version)

    elif command == "get serial ports":
        get_serial_ports(sid, ip, api_version)
    # except:
    #     final_return(False, "API failure")
