#!/usr/bin/env python3
"""
TODO
"""

from __future__ import annotations

import argparse
import json
import os.path
from enum import Enum
from typing import NamedTuple

import ruamel.yaml  # type: ignore[import]


class LintSeverity(str, Enum):
    ERROR = "error"
    WARNING = "warning"
    ADVICE = "advice"
    DISABLED = "disabled"


class LintMessage(NamedTuple):
    path: str | None
    line: int | None
    char: int | None
    code: str
    severity: LintSeverity
    name: str
    original: str | None
    replacement: str | None
    description: str | None


if __name__ == "__main__":
    parser = argparse.ArgumentParser(
        description="github actions linter",
        fromfile_prefix_chars="@",
    )
    parser.add_argument(
        "filenames",
        nargs="+",
        help="paths to lint",
    )

    args = parser.parse_args()

    for fn in args.filenames:
        with open(fn) as f:
            contents = f.read()

        yaml = ruamel.yaml.YAML()  # type: ignore[attr-defined]
        try:
            r = yaml.load(contents)
        except Exception as err:
            msg = LintMessage(
                path=None,
                line=None,
                char=None,
                code="GHA",
                severity=LintSeverity.ERROR,
                name="YAML load failure",
                original=None,
                replacement=None,
                description=f"Failed due to {err.__class__.__name__}:\n{err}",
            )

            print(json.dumps(msg._asdict()), flush=True)
            continue

        for job_name, job in r.get("jobs", {}).items():
            # This filter is flexible, the idea is to avoid catching all of
            # the random label jobs that don't need secrets
            # TODO: binary might be good to have too, but it's a lot and
            # they're autogenerated too
            uses = os.path.basename(job.get("uses", ""))
            if ("build" in uses or "test" in uses) and "binary" not in uses:
                if job.get("secrets") != "inherit":
                    desc = "missing 'secrets: inherit' field"
                    if job.get("secrets") is not None:
                        desc = "has 'secrets' field which is not standard form 'secrets: inherit'"
                    msg = LintMessage(
                        path=fn,
                        line=job.lc.line,
                        char=None,
                        code="GHA",
                        severity=LintSeverity.ERROR,
                        name="missing secrets: inherit",
                        original=None,
                        replacement=None,
                        description=(f"GitHub actions job '{job_name}' {desc}"),
                    )

                    print(json.dumps(msg._asdict()), flush=True)
