# -*- coding:utf-8 -*-
"""
Function: reset_storage_controller.py moudle. This moudle mainly involves the
 clearing the RAID Configuration of a Specified Controller function.
Copyright Information: xFusion Digital Technologies Co.,
 Ltd. All Rights Reserved © 2020-2021
"""
import sys

from scripts.common_function import TIMEOUT_THIRTY
from scripts.common_function import UREST_STATUS_CODE_2
from scripts import common_function


def resetstoragecontroller_init(parser, parser_list):
    """
    Register sub commands for reseting default controller settings.
    :param parser: major command argparser
    :param parser_list: save subcommand parser list
    :return: 'resetraid'
    """
    sub_parser = parser.add_parser('resetraid',
                                   help='''reset RAID controller''')
    sub_parser.add_argument('-CI', dest='controllerid',
                            type=int, required=True,
                            help='''RAID controller ID''')
    sub_parser.add_argument('--force', required=False, action='store_true',
                            help='''silent deletion''')
    parser_list['resetraid'] = sub_parser

    return 'resetraid'


def resetstoragecontroller(client, args):
    """
    Delete all VD and restore the default controller settings.
    :param client: RedfishClient object
    :param parser: subcommand argparser.
                   Export error messages when parameters are incorrect.
    :param args: parameter list
    :return:
    """
    if "--force" not in sys.argv:
        strtemp = input('Are you sure you want to delete RAID card '
                            'configurations and restore default '
                            'configurations of the controller? '
                            '(y/n): ').strip()
        tmp = strtemp.strip()
        if tmp == 'n':
            print("The deletion is canceled.")
            sys.exit(0)
        elif tmp != 'y':
            print(
                "The entered value is incorrect and the deletion is canceled.")
            sys.exit(127)

    slot_id = client.get_slotid()
    if slot_id is None:
        return None

    # Obtain storage information
    storage_info = get_storage(client, args, slot_id)
    if storage_info is None or storage_info['status_code'] != 200:
        return storage_info

    # Delete all VD
    resp = del_volumes(client, storage_info)
    if resp is None or resp['status_code'] not in [200, 202]:
        return resp

    # Restore the default controller settings
    resp = restore_controller(client, args, slot_id)
    return resp


def get_storage(client, args, slot_id):
    """
    Obtain storage information.
    :param client: RedfishClient object
    :param args: parameter list
    :param slot_id: slot ID
    :return: resp
    """
    # Determine whether a storage system exists.
    systems = "/redfish/v1/Systems/" + slot_id
    resp = check_storages(client, systems)
    if resp is None:
        return None
    if resp['status_code'] != 200:
        return resp

    raid_storage = "/storages/raidstorage"
    url = systems + raid_storage + str(args.controllerid)

    return get_specify_contrl_info(client, url)


def get_specify_contrl_info(client, url):
    """
    Obtain specified controller information.
    :param client: RedfishClient object
    :param url: specified URL
    :return: resp
    """
    resp = get_controller_info(client, url)
    if resp is None:
        return resp
    if resp['status_code'] == 404:
        # No RAID controller exists in the environment.
        print("Failure: the value of -CI parameter is invalid")
        sys.exit(UREST_STATUS_CODE_2)

    return resp


def get_controller_info(client, controller_uri):
    """
    Get controller information.
    :param client: RedfishClient object
    :param controller_uri: controller URL
    :return: ctrl_resp
    """
    # Obtain the controller information.
    ctrl_resp = client.get_resource(controller_uri)
    # If the required information is not obtained successfully,
    # the returned value is None.
    if ctrl_resp is None or ctrl_resp['status_code'] != 200:
        return ctrl_resp

    return ctrl_resp


def del_volumes(client, ctrl_resp):
    """
    Delete all logical disks under the specified controller
    :param client: RedfishClient object
    :param ctrl_resp: Specify controller information
    :return: volumes_resp or error_resp
    """
    # Export logical disk information.
    volumes_uri = ctrl_resp['resource']['Volumes']['@odata.id']
    volumes_resp = client.get_resource(volumes_uri)
    if volumes_resp is None or volumes_resp['status_code'] != 200:
        return volumes_resp

    # try
    delete_flag = True
    error_resp = []
    try_time = 0
    while try_time < 3:
        try_time += 1

        if volumes_resp['resource']['Members']:
            volumes_length = len(volumes_resp['resource']['Members'])

            # Delete all volumes
            index = 0
            while index < volumes_length:
                volumes_index = volumes_resp['resource']['Members'][index]
                volumes_url = volumes_index['@odata.id']
                resp = del_logical_drive(client, volumes_url)
                if resp is None or resp['status_code'] != 200 \
                        or resp['status_code'] != 202:
                    delete_flag = False
                    error_resp.append(resp)
                index += 1
    if not delete_flag:
        return error_resp[0]
    return volumes_resp


def del_logical_drive(client, volumes_url):
    """
    Logical disk deletion subcommand processing functions.
    :param client: RedfishClient object
    :param volumes_url: Volumes resource URL
    :return: resp
    """
    resp = client.delete_resource(volumes_url)

    if resp is None:
        return None
    if resp['status_code'] == 202:
        task_uri = resp['message']['@odata.id']
        resp = client.get_resource(task_uri)
        if resp is None:
            return None

        if resp['status_code'] == 202:
            task_uri = resp['message']['@odata.id']
            resp = get_task_progress(client, task_uri)

        elif resp['status_code'] == 404:
            print("failure: " + volumes_url)

    return resp


def get_task_progress(client, task_uri):
    """
    Delete logical disks and query the task progress.
    :param client: RedfishClient object
    :param task_uri: Task resource uri
    :return: get_resp
    """
    get_resp = client.get_resource(task_uri)
    if get_resp is None:
        return None

    # Query the progress.
    task_resp = client.print_task_prog(get_resp)
    if task_resp is None:
        return None

    get_resp = client.get_resource(task_uri)
    if get_resp is None:
        return None

    if get_resp['status_code'] != 200:
        print('failure: ' + get_resp['resource']['Messages']['Message'])
        return get_resp

    if task_resp == 'Exception':
        print('failure: ' + get_resp['resource']['Messages']['Message'])
        sys.exit(144)
    return get_resp


def check_storages(client, systems):
    """
    Check before the configuration.
    :param client: RedfishClient object
    :param systems: URL
    :return: resp
    """
    url = systems + "/Storages"
    resp = client.get_resource(url)
    if resp is None:
        return None
    if resp['status_code'] != 200:
        if resp['status_code'] == 404:
            print('Failure: resource was not found')
    # Check whether the controller URL exists and
    # whether the version is an earlier version.
    else:
        flag = False
        if resp['resource']['Members@odata.count'] == 0:
            print('Failure: Storages resource was not found')
            sys.exit(148)
        for i in range(0, len(resp['resource']['Members'])):
            url = resp['resource']['Members'][i]['@odata.id']
            if url.find("RAIDStorage") > 0:
                flag = True
                break
        if not flag:
            print('Failure: RAID storage resource was not found')
            sys.exit(148)
    return resp


def restore_controller(client, args, slot_id):
    """
    Restore the default controller settings.
    :param client: RedfishClient object
    :param args: parameter list
    :param slot_id: slot ID
    :return: resp
    """
    # Determine whether a storage system exists.
    systems = "/redfish/v1/Systems/" + slot_id
    storage = "/Storages/RAIDStorage" + str(args.controllerid)
    resp = client.check_storages(systems, storage, '-CI')
    if resp is None:
        return None
    if resp['status_code'] != 200:
        return resp

    payload = {}
    act = "/Actions/Oem/%s/Storage.RestoreStorageControllerDefault" \
          "Settings" % common_function.COMMON_KEY
    url = systems + storage + act
    resp = client.create_resource(url, payload, timeout=TIMEOUT_THIRTY)
    if resp is None:
        return resp
    if resp['status_code'] == 200:
        print('Success: successfully completed request')
    elif resp['status_code'] == 400:
        error_info = "Failure: failed to operate storage controller," \
                     " because the current status does not support it"
        print(error_info)

    return resp
