#!/usr/bin/env python3
# Copyright (c) 2025 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 os
from pathlib import Path
from posixpath import dirname
import posixpath
import shutil
import subprocess
import sys
from typing import Dict, List, TypeAlias, TypedDict
import yaml

usage = f"""\
Usage: {sys.argv[0]} [--all] inputs

    inputs: a (possibly empty) list of paths to diagnostic YAMLs
    --all: run on all YAMLs that look like they include diagnostics
    -h | --help: print this help
    """

def check_graveyard(yaml_path: Path)-> bool:
    yaml_path = Path(posixpath.normpath(yaml_path.absolute()))
    # strip trailing newline, otherwise path isn't valid
    repo_dir = Path(posixpath.normpath(subprocess.run(["git", "rev-parse", "--show-toplevel"], cwd=dirname(yaml_path), capture_output=True).stdout.decode()[:-1])).absolute()
    yaml_relative = yaml_path.relative_to(repo_dir)

    diff_proc = subprocess.run(["git", "diff", "--quiet", yaml_path], cwd=repo_dir)
    assert diff_proc.returncode in (0, 1)
    has_changes = diff_proc.returncode == 1

    prev_rev = 'HEAD' if has_changes else 'HEAD^'

    with open(yaml_path) as f:
        current_doc = yaml.safe_load(f)

    diags_key = find_diags_key(current_doc)

    graveyard = set(current_doc['graveyard'])
    current_ids = {diag['id'] for diag in current_doc[diags_key]}

    show_proc = subprocess.run(["git", "show", f"{prev_rev}:{yaml_relative}"], cwd=repo_dir, capture_output=True)
    show_proc.check_returncode()
    prev_doc = yaml.safe_load(show_proc.stdout.decode())
    prev_ids = {diag['id'] for diag in prev_doc[diags_key]}

    removed_ids = prev_ids - current_ids
    not_in_graveyard = removed_ids - graveyard
    if not_in_graveyard:
        print(f"{yaml_path}: Missing from graveyard: {sorted(list(not_in_graveyard))}")
        return False
    return True

def find_diags_key(current):
    keys = set(current.keys())
    keys.remove('graveyard')
    assert len(keys) == 1
    diags_key = keys.pop()
    return diags_key

def known_file_paths():
    repo_base = posixpath.dirname(shutil.which(sys.argv[0])) + "/../../"
    for relative in subprocess.run(["git", "grep", "--files-with-matches", "-e" "^  message:", "--", "**.yaml"], cwd = repo_base, stdout=subprocess.PIPE).stdout.decode().splitlines():
        yield repo_base + relative

def main():
    params = sys.argv[1:]
    if "-h" in sys.argv or "--help" in params:
        print(usage, file=sys.stderr)
        sys.exit(1)
    if "--all" in params:
        params = [p for p in params if p != "--all"]
        for path in known_file_paths():
            params.append(path)
    passed = True
    for path in params:
        print("Processing", path)
        passed = passed and check_graveyard(Path(path))
    sys.exit(0 if passed else 1)

if __name__ == "__main__":
    main()