#!/usr/bin/python3
# pylint: disable=consider-using-f-string
# pylint: disable=fixme
# TODO: check which imports could be removed in the future (time, re, json)?
# TODO: legacy (classic) has "Sites" instead of "Site" (angi) and "Hosts" (classic/legacy) instead of "Host" (angi) --> could we set that via json files?
"""
 SAPHanaSR-testCluster-multiNode
 Author:       Fabian Herschel, Mar 2023
 License:      GNU General Public License (GPL)
 Copyright:    (c) 2023 SUSE LLC
"""

# pylint: disable=unused-import
import time
import re
import json
# pylint: enable=unused-import
#import subprocess
import sys
import argparse
import random
sys.path.insert(1, '/usr/lib/SAPHanaSR-tester')
#pylint: disable=wrong-import-position
from saphana_sr_test import SaphanasrTest
#pylint: enable=wrong-import-position

# TODO: impement test sequences instead of "only" repeating the same test
test01 = SaphanasrTest(cmdparse=False)

parser = argparse.ArgumentParser()
parser.add_argument("--testFile", help="specify the test file")
parser.add_argument("--defaultsFile", help="specify the default checks file")
parser.add_argument("--properties", help="specify the properties file")
parser.add_argument("--remoteNodes", nargs="*", help="cluster nodes to use for ssh connection")
parser.add_argument("--simulate", help="only simulate, dont call actions",
                    action="store_true")
parser.add_argument("--repeat", help="how often to repeat the test")
parser.add_argument("--dumpFailures", help="print failed checks per loop",
                    action="store_true")
parser.add_argument("--logFile", help="log file to write the messages")
parser.add_argument("--printTestProperties", help="print test properties and exit",
                    action="store_true")
args = parser.parse_args()
if args.testFile:
    test01.message("PARAM: testFile: {}".format(args.testFile))
    test01.config['test_file'] = args.testFile
if args.defaultsFile:
    test01.message("PARAM: defaultsFile: {}".format(args.defaultsFile))
    test01.config['defaults_file'] = args.defaultsFile
if args.properties:
    test01.message("PARAM: properties: {}".format(args.properties))
    test01.config['properties_file'] = args.properties
if args.remoteNodes:
    test01.message("PARAM: remoteNodes: {}".format(args.remoteNodes))
    test01.config['remote_node'] = args.remoteNodes[0]
    test01.config['remote_nodes'] = args.remoteNodes
    #test01.message(f"dbg: len remote_hosts: {len(test01.config['remote_nodes'])}")
if args.repeat:
    test01.message("PARAM: repeat: {}".format(args.repeat))
    test01.config['repeat'] = int(args.repeat)
if args.dumpFailures:
    test01.message("PARAM: dumpFailures")
    test01.config['dump_failures'] = args.dumpFailures
if args.logFile:
    test01.message("PARAM: logFile: {}".format(args.logFile))
    test01.config['log_file'] = args.logFile
    # disable 'consider to use with ...' - I am pretty sure with does not match here
    # pylint: disable-next=R1732
    test01.run['log_file_handle'] = open(test01.config['log_file'], 'a', encoding="utf-8")
if args.printTestProperties:
    test01.config['printTestProperties'] = args.printTestProperties
    test01.message(f"PARAM: printTestProperties: {test01.config['printTestProperties']}")

while test01.run['count'] <= test01.config['repeat']:
    test01.run['r_id'] = random.randrange(10000,99999,1)
    test01.read_saphana_sr()
    l_top = test01.topolo
    l_top.update({'global': 'global'})
    # for angi-ScaleUp and classic ScaleOut:
    # pSite is the site with srr-attribute == "P"
    # sSite is the site with srr-attribute == "S"
    # pHost is the host with site-attribute == pSite
    # sHost is the host with site-attribute == sSite
    # TODO: for angi-ScaleOut and classic-ScaleOut we might need to differ msn-host, plain-worker (no mns-candidate) and standby node
    # TODO: classic-ScaleUp
    # TODO: allow 2 types of parameter set:
    #       1: --testFile=... --defaultsFile=... --properties=... [ --defaultPropertiesFile=... ]
    #       2: --testDir=...
    # pHost could be the host with roles-attr like [0-4]:P:*
    # sHost could be the host with roles-attr like [0-4]:S:*
    # pSite is referenced by pHost-site-attr
    # sSite is referenced by sHost-site-attr
    #
    l_top.update({'pSite': test01.get_area_object_by_key_val('Site', {'srr': 'P'})})
    l_top.update({'sSite': test01.get_area_object_by_key_val('Site', {'srr': 'S'})})
    # first try to use site-msn attribute to get the master name server
    # TODO: check, if msn could be 'misleading', if using 'virtual' SAP HANA host names
    l_top.update({'pHost': test01.get_value('Site', l_top['pSite'], 'mns')})
    l_top.update({'sHost': test01.get_value('Site', l_top['sSite'], 'mns')})

    # get first non master-nameserver worker node for primary and secondary site
    # TODO: check, if l_top pSite/sSite are already set correctly
    # TODO: check for roles must be sloppy, check for site must be strict - maybe sloppy=['roles'] ??
    l_top.update({'pWorker': test01.get_area_object_by_key_val('Host', {'site': l_top['pSite'], 'roles': ':worker:slave'}, sloppy=True)})
    l_top.update({'sWorker': test01.get_area_object_by_key_val('Host', {'site': l_top['sSite'], 'roles': ':worker:slave'}, sloppy=True)})

    if l_top['pHost'] is None:
        # if mns attributes do not work this is most likely a classic-ScaleUp we need to query by roles
        l_top.update({'pHost': test01.get_area_object_by_key_val('Host', {'roles': '[0-4]:P:'}, sloppy=True)})
        l_top.update({'sHost': test01.get_area_object_by_key_val('Host', {'roles': '[0-4]:S:'}, sloppy=True)})
        l_top.update({'pSite': test01.get_value('Host', l_top['pHost'], 'site')})
        l_top.update({'sSite': test01.get_value('Host', l_top['sHost'], 'site')})

    # TODO: do we need the old method as fallback, if msn is empty or misleading?
    #l_top.update({'pHost': test01.get_area_object_by_key_val('Host', 'site', l_top['pSite'])})
    #l_top.update({'sHost': test01.get_area_object_by_key_val('Host', 'site', l_top['sSite'])})
    l_msg = (
                f"TOPO: pSite={l_top['pSite']}"
                f" sSite={l_top['sSite']}"
                f" pHost={l_top['pHost']}"
                f" sHost={l_top['sHost']}"
                f" pWorker={l_top['pWorker']}"
                f" sWorker={l_top['sWorker']}"
            )
    test01.message(l_msg)

    test01.read_test_file()
    ### debug exit after printing test properties
    if test01.config['printTestProperties'] is True:
        p_msg = (
                    f"test_properties:" 
                    f" node01={l_top.get('pHost','node01')}"
                    f" node02={l_top.get('sHost','node02')}"
                    f" mstResource={test01.test_data.get('mstResource','')}"
                    f" clnResource={test01.test_data.get('clnResource','')}"
                    f" srMode=sync"
                    f" opMode=logreplay"
                    f" SID={test01.test_data.get('sid','C11')}"
                    f" instNr={test01.test_data.get('instNo','00')}"
                    f" sidadm={test01.test_data.get('sid','C11').lower()}adm"
                    f" userkey={test01.test_data.get('userKey','')}"
                )
        test01.message(p_msg)
        break
    test01.write_test_properties(l_top)

    my_test_id = test01.run['test_id']
    if test01.config['repeat'] != 1:
        test01.message("TEST: {} testNr={} ######".format(my_test_id, test01.run['count']))
    test01.run['test_rc'] = test01.process_test()
    MSG_TEMPL = "TEST: {} testNr={} {} successfully :) ######"
    if test01.run['test_rc'] == 0:
        test01.message(MSG_TEMPL.format(my_test_id, 'PASSED', test01.run['count']))
    else:
        test01.message(MSG_TEMPL.format(my_test_id, 'FAILED', test01.run['count']))
    test01.run['count'] += 1
if  test01.run['log_file_handle']:
    test01.run['log_file_handle'].close()
