from __future__ import annotations

import re
from pathlib import Path
from typing import Any

from checkov.common.parsers.yaml.parser import parse

TASK_NAME_PATTERN = re.compile(r"^\s*-\s+name:\s+", re.MULTILINE)

# https://docs.ansible.com/ansible/latest/reference_appendices/playbooks_keywords.html#task
TASK_RESERVED_KEYWORDS = {
    "action",
    "any_errors_fatal",
    "args",
    "async",
    "become",
    "become_exe",
    "become_flags",
    "become_method",
    "become_user",
    "changed_when",
    "check_mode",
    "collections",
    "connection",
    "debugger",
    "delay",
    "delegate_facts",
    "delegate_to",
    "diff",
    "environment",
    "failed_when",
    "ignore_errors",
    "ignore_unreachable",
    "local_action",
    "loop",
    "loop_control",
    "module_defaults",
    "name",
    "no_log",
    "notify",
    "poll",
    "port",
    "register",
    "remote_user",
    "retries",
    "run_once",
    "tags",
    "throttle",
    "timeout",
    "until",
    "vars",
    "when",
}


def get_scannable_file_paths(root_folder: str | Path) -> set[Path]:
    """Finds yaml files"""

    file_paths: set[Path] = set()

    if root_folder:
        root_path = root_folder if isinstance(root_folder, Path) else Path(root_folder)
        file_paths = {file_path for file_path in root_path.rglob("*.[y][am]*[l]") if file_path.is_file()}

    return file_paths


def get_relevant_file_content(file_path: str | Path) -> str | None:
    if not str(file_path).endswith((".yaml", ".yml")):
        return None

    content = Path(file_path).read_text()
    match_task_name = re.search(TASK_NAME_PATTERN, content)
    if match_task_name:
        # there are more files, which belong to an ansible playbook,
        # but we are currently only interested in 'tasks'
        return content

    return None


def parse_file(
    f: str | Path, file_content: str | None = None
) -> tuple[dict[str, Any] | list[dict[str, Any]], list[tuple[int, str]]] | None:
    file_content = get_relevant_file_content(file_path=f)
    if file_content:
        content = parse(filename=str(f), file_content=file_content)
        return content

    return None
