# Copyright (c) 2025 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.

import os
import shutil
import json
import re

PRIVILEGE_MAP_PATH = "interface_config/redfish/mapping_config/AccountService/PrivilegeMap/PrivilegeMap.json"


class Base:
    def __init__(self):
        self._init_config()

    def init_temp_file(self, path):
        temp_file = os.path.join(self.temp_path, path)
        if os.path.exists(temp_file):
            shutil.rmtree(temp_file)
        os.makedirs(temp_file)
        return temp_file

    def _init_config(self):
        self.root_path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
        self.temp_path = os.path.join(self.root_path, "temp")


class RedfishConfigParser(Base):
    def __init__(self, config_dir="interface_config/redfish/mapping_config"):
        """
        Redfish配置解析器
        """
        super().__init__()
        self.config_dir = os.path.join(self.root_path, config_dir)
        self._uri_mapper = {}

    def parse_all_configs(self):
        """
        解析配置目录中的所有JSON文件
        """
        files = self._get_all_config_files()
        for file in files:
            if not file.lower().endswith('.json'):
                # 跳过非json文件
                continue
            with open(file, 'r', encoding='utf-8') as f:
                data = json.load(f)

            if isinstance(data, dict):
                self._process_resources(data)

    def save_uri_mapper(self, output_path):
        """
        以文件形式输出解析后的配置
        """
        with open(output_path, 'w', encoding='utf-8') as file:
            json.dump(self._uri_mapper, file, indent=4, ensure_ascii=False)

    def _get_all_config_files(self):
        """
        获取所有接口配置文件
        """
        if not os.path.exists(self.config_dir):
            raise FileNotFoundError(f"错误: 目录 '{self.config_dir}' 不存在")
        
        if not os.path.isdir(self.config_dir):
            raise FileNotFoundError(f"错误: '{self.config_dir}' 不是有效目录")
        
        all_files = []
        for root, _, files in os.walk(self.config_dir):
            for file in files:
                file_path = os.path.join(root, file)
                all_files.append(file_path)
        return all_files

    def _process_resources(self, data):
        """
        获取文件中uri-资源
        """
        if not isinstance(data, dict) or "Resources" not in data or not isinstance(data["Resources"], list):
            print("配置文件内容存在错误")
            return

        # 处理每个Resource项
        for resource in data["Resources"]:
            if not isinstance(resource, dict):
                continue
            
            uri = resource.get("Uri")
            interfaces = resource.get("Interfaces")
            if uri is not None and interfaces is not None:
                # 将uri中的槽位号替换为{id}
                normalized_uri = re.sub(r'(^|/):[^/]+', r'\1{id}', uri)
                self._uri_mapper[normalized_uri] = interfaces


class UriClassifier(Base):
    def __init__(self, input_file):
        """
        Redfish接口分类器
        """
        super().__init__()
        self.input_file = input_file
        self.dir_path = os.path.dirname(input_file)

        self._raw_data = None

        # 分类数据容器
        self._post_only = {}       # 仅包含POST，是Action接口
        self._resource_uri = {}    # 资源的uri，有GET方法
        self._other_data = {}      # 其他数据
        self.filepath = {}
        self.filenames = [
            (self._post_only, 'post_only'),
            (self._resource_uri, 'resource_uri'),
            (self._other_data, 'other_data')
        ]

    def load_data(self):
        """
        加载原始数据
        """
        with open(self.input_file, 'r', encoding='utf-8') as f:
            self._raw_data = json.load(f)
        if not isinstance(self._raw_data, dict):
            raise ValueError("JSON根元素必须是字典类型")

    def classify_data(self):
        """
        执行数据分类
        """
        for key, value in self._raw_data.items():
            # 忽略内部接口
            if not isinstance(value, list) or not key.startswith('/redfish/v1'):
                continue

            has_post = False
            has_get = False
            rsp_body = {}

            for item in value:
                if isinstance(item, dict):
                    item_type = str(item['Type']).upper()
                    if item_type == 'POST':
                        has_post = True
                    elif item_type == 'GET':
                        has_get = True
                        rsp_body = item['RspBody'] if 'RspBody' in item else {}

            if has_post and not has_get:
                self._post_only[key] = value
            elif has_get:
                self._classify_get_items(key, value, rsp_body)
            else:
                self._other_data[key] = value

    def save_results(self):
        """
        保存结果到文件
        """
        for data, filename in self.filenames:
            path = os.path.join(self.dir_path, filename + '.json')
            self.filepath[filename] = path
            with open(path, 'w', encoding='utf-8') as f:
                json.dump(data, f, indent=4, ensure_ascii=False)

    def _classify_get_items(self, key, value, rsp_body):
        """
        筛选特殊的GET接口：响应体为引用格式字符串
        """
        if isinstance(rsp_body, str) or isinstance(rsp_body, dict):
            self._resource_uri[key] = value
        else:
            self._other_data[key] = value


class PrivilegUriIndividual:
    def __init__(self, entity, uri, data):
        """
        PrivilegeMap Action资源实例
        """
        self._entity = entity
        self._uri = uri
        self._data = data
        self._init_map()

    def _init_map(self):
        self.method = {
            "GET": [],
            "PATCH": [],
            "POST": [],
            "DELETE": []
        }
        if "OperationMap" not in self._data:
            return
        for method, maps in self._data["OperationMap"].items():
            for prvmap in maps:
                self.method[method.upper()].extend(prvmap["Privilege"])


class PrivilegIndividual:
    def __init__(self, data):
        """
        PrivilegeMap资源实例
        """
        self._entity = data["Entity"]
        self._data = data
        self._init_map()
        self._init_property()
        self._init_uri()

    def get_entity(self):
        return self._entity

    def _init_map(self):
        self.method = {
            "GET": [],
            "PATCH": [],
            "POST": [],
            "DELETE": []
        }
        if "OperationMap" not in self._data:
            return
        for method, maps in self._data["OperationMap"].items():
            for prvmap in maps:
                self.method[method.upper()].extend(prvmap["Privilege"])

    def _init_property(self):
        if "PropertyOverrides" not in self._data:
            return
        for override in self._data["PropertyOverrides"]:
            for method, maps in override["OperationMap"].items():
                for prvmap in maps:
                    self.method[method.upper()].extend(prvmap["Privilege"])

    def _init_uri(self):
        self.resource_uri_overrides = {}
        if "ResourceURIOverrides" not in self._data:
            return
        for override in self._data["ResourceURIOverrides"]:
            for target in override["Targets"]:
                self.resource_uri_overrides[target] = PrivilegUriIndividual(self._entity, target, override)


class PrivilegeMapPaser(Base):
    def __init__(self, config_path=PRIVILEGE_MAP_PATH, error_list=None):
        """
        PrivilegeMap解析器
        """
        super().__init__()
        self.config_path = os.path.join(self.root_path, config_path)
        self._privilege_mapper = {}
        self.error = error_list if error_list else []
        self._init_privilege_mapper()

    def get_privilege_mapper(self):
        return self._privilege_mapper

    def _init_privilege_mapper(self):
        """
        解析PrivilegeMap响应体配置
        """
        with open(self.config_path, 'r', encoding='utf-8') as f:
            self._raw_data = json.load(f)
        mappings = self._raw_data["Resources"][0]["Interfaces"][0]["RspBody"]["Mappings"]
        for mapping in mappings:
            try:
                individual = PrivilegIndividual(mapping)
            except Exception as e:
                self.error.append(f"解析PrivilegeMap时，资源{mapping['Entity']}格式错误")
                return
            entity = individual.get_entity()
            if entity in self._privilege_mapper:
                self.error.append(f"{entity}资源在PrivilegeMap中重复")
            self._privilege_mapper[entity] = individual


def create_uri_mapper(resource_path, output_path):
    try:
        redfish_parser = RedfishConfigParser(resource_path)
        temp_path = redfish_parser.init_temp_file(output_path)
        redfish_parser.parse_all_configs()
        uri_mapper_path = os.path.join(temp_path, "uri_mapper.json")
        redfish_parser.save_uri_mapper(uri_mapper_path)

        redfish_classifier = UriClassifier(uri_mapper_path)
        redfish_classifier.load_data()
        redfish_classifier.classify_data()
        redfish_classifier.save_results()
    except Exception as e:
        print(f"解析所有接口配置文件时出错: {str(e)}")
        return None
    return redfish_classifier.filepath


def create_privilege_mapper(error_list):
    parser = PrivilegeMapPaser(error_list=error_list)
    return parser.get_privilege_mapper()