#!/usr/bin/env python
# coding: utf-8
# Copyright (c) 2024 Huawei Technologies Co., Ltd.
# openUBMC is licensed under Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
#         http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
# See the Mulan PSL v2 for more details.

from . import schema_utils as su
from .uri_constraint_checker import UriConstraintChecker
from .rspbody_constraint_checker import RspBodyConstraintChecker
from .reqbody_constraint_checker import ReqBodyConstraintChecker


class ConstraintChecker:
    def __init__(self, target_json, target_path, schema_dir):
        self.rscs = target_json['Resources']
        self.target_path = target_path
        self.schema_dir = schema_dir
        # 过滤动态schema的uri
        self.filter_uri = [
            '/redfish/v1/RegistryStore/Messages/en/Base.v1_0_0.json',
            '/redfish/v1/RegistryStore/Messages/en/{{SoftwareName}}.v1_0_0.json',
            '/redfish/v1/RegistryStore/Messages/en/{{SoftwareName}}Events.:id',
            '/redfish/v1/$metadata',
            '/redfish/v1/odata',
            '/redfish/v1/Managers/:managerid/SPService/Plugins',
            '/redfish/v1/Managers/:managerid/SPService/Plugins/:memberid',
            '/redfish/v1/Managers/:managerid/Certificates/:id',
            '/redfish/v1/Managers/:managerid/SPService/SPDiagnose/:memberid',
            '/redfish/v1/Managers/:managerid/SPService/SPCfg/:memberid',
            '/redfish/v1/Managers/:managerid/SPService/SPRAID/:memberid',
            '/redfish/v1/Managers/:managerid/SPService/SPOSInstallPara/:memberid',
            '/redfish/v1/Managers/:managerid/SPService/DeviceInfo',
            '/redfish/v1/Managers/:managerid/SPService/SPRAIDCurrentConfigurations/:memberid',
            '/redfish/v1/Managers/:managerid/SPService/SPDriveErase/:memberid',
            '/redfish/v1/Managers/:managerid/SPService/SystemErase/:memberid',
            '/redfish/v1/Managers/:managerid/SPService/SPResult/:memberid',
            '/redfish/v1/EventService/Subscriptions/:id',
            '/redfish/v1/Chassis/:chassisid/PCIeDevices/:id/PCIeFunctions/:funcid'
        ]

    def check(self):
        cons_success = True
        # 遍历Resources下的Uri/Interfaces
        for i in range(len(self.rscs)):
            # 非对外接口，不需要检查
            ucc = UriConstraintChecker(self.target_path, self.schema_dir)
            uri = self.rscs[i]['Uri']
            if ('ActionInfo' in uri or '/Actions/' in uri or
                uri in self.filter_uri):
                continue
            intfs = self.rscs[i]['Interfaces']
            if not ucc.is_extern_intf(uri):
                continue
            # 校验Uri定义完整性
            # 校验资源方法有效性
            cons_success = ucc.check(uri, intfs) and cons_success
            odata_type = ucc.get_odata_type()
            if odata_type is None:
                cons_success = False
                continue
            elif odata_type.startswith('${Statements'): # 规避动态@odata.type字段解析
                continue
            rsc_name, prop_name = su.get_schema_from_odata_type(odata_type)
            for intf in intfs:
                if 'RspBody' in intf:
                    # 校验GET请求的required约束
                    # 校验属性定义的完整性
                    rspcc = RspBodyConstraintChecker(self.target_path, uri, self.schema_dir,
                                                     rsc_name, prop_name, intf['Type'])
                    cons_success = rspcc.check(intf['RspBody']) and cons_success
                elif 'ReqBody' in intf:
                    # 校验POST请求的requiredOnCreate约束
                    # 校验资源方法请求体的additionalProperties约束
                    # 校验PATCH请求的readonly约束
                    # 校验资源属性类型定义的一致性
                    reqcc = ReqBodyConstraintChecker(self.target_path, uri, self.schema_dir,
                                                     rsc_name, prop_name, intf['Type'])
                    cons_success = reqcc.check(intf['ReqBody']) and cons_success
        return cons_success