from typing import List
from pathlib import Path
from typing import Set


def get_cl_tags(files: List[Path]) -> List[str]:
  """
  Come up with descriptive tags given a list of files changed.

  For each path, use the first rule that applies in the following order:

  1) Pick the path component right after the last "lib", "bin", "drivers",
     or "devices".
  2) If the path begins with "src", then
     - if the third path component is "tests" then pick the fourth component
     - pick the third path component, e.g. src/developer/shell -> shell
  3) If the path begins with "zircon", then pick the path component after
     either "ulib" or "utest", e.g.
     zircon/system/ulib/fs-pty/test/service-test.cc -> fs-pty

  Example:

    get_cl_tags([
      "src/lib/loader_service/loader_service_test.cc",
      "src/lib/loader_service/loader_service_test_fixture.cc",
    ]) == ["loader_service"]

  """

  def get_tag(p: Path) -> str:
    tag: str = ""
    for part, next_part in zip(p.parts, p.parts[1:]):
      if (
        part == "lib"
        or part == "bin"
        or part == "drivers"
        or part == "devices"
      ):
        if next_part != "tests" and not next_part.endswith(".cc"):
          tag = next_part
    if tag != "":
      return tag
    if p.parts[0] == "build":
      return "build"
    if p.parts[0] == "src":
      if len(p.parts) >= 3:
        if p.parts[2] == "tests" and not p.parts[3].endswith(".cc"):
          return p.parts[3]
        return p.parts[2]
    if p.parts[0] == "zircon":
      for part, next_part in zip(p.parts, p.parts[1:]):
        if part == "ulib" or part == "utest":
          return next_part
    raise RuntimeError(f"Could not infer tags from path {p}")

  tags: Set[str] = set()
  for file in files:
    tags.add(get_tag(file))
  return sorted(list(tags))