#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Copyright (c) 2024 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

import json
import os
import sys
import stat

precise_repo_xts = sys.argv[1]
DEEP = int(sys.argv[2]) if len(sys.argv) > 2 else -1
home = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
manifest_home = os.path.join(home, ".repo")
preloader_path = os.path.join(home, "out", "preloader")
PRECISE_GNI_NAME = "precise_run.gni"
DEPENDS_TREE_NAME = "depends_tree.txt"
F_DEPENDS_NAME = "f_depends.txt"
MAX_PRECISE_PR_NUM = 20

# 首层依赖关系dist
dependency_dist = {}
# 全量编译白名单
whitelist = {"test/xts/acts", "build"}


def get_f_dependes_dist(path):
    count = 0
    # 遍历目录下的所有文件和子目录
    for root, dirs, files in os.walk(path):
        for file in files:
            if file == 'bundle.json':
                count = count + 1
                # 构建完整的文件路径
                file_path = os.path.join(root, file)
                # 读取 JSON 文件并转换为 Python 对象
                with open(file_path, 'r', encoding='utf-8') as f:
                    json_data = json.load(f)
                    bundle_name = json_data['name'].split('/')[-1]
                    if "deps" not in json_data['component']:
                        continue
                    deps = json_data['component']['deps']
                    # 依赖关系额写入dependency_dist
                    if bundle_name not in dependency_dist:
                        dependency_dist[bundle_name] = []
                    if "components" in deps:
                        components_defs = deps['components']
                        for c_def in components_defs:
                            if c_def in dependency_dist:
                                dependency_dist[c_def].append(bundle_name)
                            else:
                                dependency_dist[c_def] = [bundle_name]
                    if "third_party" in deps:
                        third_party_defs = deps['third_party']
                        for t_def in third_party_defs:
                            if t_def in dependency_dist:
                                dependency_dist[t_def].append(bundle_name)
                            else:
                                dependency_dist[t_def] = [bundle_name]
    print(count)


def getbundname(path_list):
    print(path_list)
    bundle_list = []
    for path in path_list:
        # 读取JSON文件并获取指定key的value
        with open(os.path.join(home, path, "bundle.json"), 'r') as file:
            data = json.load(file)
        bundle_list.append(data['component']['name'])
    return bundle_list


def get_all_dependencies(nodes, dependencies):
    visited = set()  # 存储已访问的节点
    string_buffer = []

    def dfs(node, num, string_buffer):
        string_buffer.append("  " * num + node)  # 追加内容到列表
        if node in visited:
            return
        if DEEP != -1 and num > DEEP:
            return
        visited.add(node)
        if node in dependencies:
            for dependency in dependencies[node]:
                dfs(dependency, num + 1, string_buffer)  # 传递可变对象进行修改

    for node in nodes:
        dfs(node, 0, string_buffer)

    return visited, string_buffer


def write_precise_gni(depends_list, file_name):
    # 将数组转换为字符串形式,例如使用逗号分隔
    array_str = json.dumps(list(depends_list))

    # 打开文件并写入数组字符串
    file_descriptor = os.open(file_name, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP)
    with os.fdopen(file_descriptor, 'w') as file:
        file.write("precise_run=")
        file.write(array_str)


def write_file(depends_list, file_name):
    file_descriptor = os.open(file_name, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP)
    with os.fdopen(file_descriptor, 'w') as f:
        json.dump(depends_list, f, indent=4)


def run(precise_repo_xts_list):
    # pr数>MAX或在白名单中的
    if len(precise_repo_xts_list) >= MAX_PRECISE_PR_NUM or any(item in precise_repo_xts_list for item in whitelist):
        depends_tree = "all"
        depends_list = {"all"}
    else:
        try:
            # 获取bundle_name_list
            bundlelist = getbundname(precise_repo_xts_list)
            # 计算首层依赖map
            get_f_dependes_dist(home)
            print(bundlelist)
            # 获取全部需要跑的bundlename
            depends_list, depends_tree = get_all_dependencies(bundlelist, dependency_dist)
            depends_list.add("acts")
            print(depends_list)
        except Exception as e:
            print("发生异常:", str(e))
            depends_tree = "all"
            depends_list = {"all"}
    # 依赖树输出
    write_file(depends_tree, os.path.join(preloader_path, DEPENDS_TREE_NAME))
    # 写入gni文件
    write_precise_gni(depends_list, os.path.join(preloader_path, PRECISE_GNI_NAME))


if __name__ == '__main__':
    print("counting dependencies start")
    run(precise_repo_xts.split(','))
    print("counting dependencies finished")