"""Utilities for loading various files."""
from __future__ import annotations

import logging
import os
from collections import defaultdict, namedtuple
from functools import partial
from pathlib import Path
from typing import Any

import yaml
from yaml import YAMLError

try:
    from yaml import CFullLoader as FullLoader
    from yaml import CSafeLoader as SafeLoader
except (ImportError, AttributeError):
    from yaml import FullLoader, SafeLoader  # type: ignore

IgnoreFile = namedtuple("IgnoreFile", "default alternative")
IGNORE_FILE = IgnoreFile(".ansible-lint-ignore", ".config/ansible-lint-ignore.txt")

yaml_load = partial(yaml.load, Loader=FullLoader)
yaml_load_safe = partial(yaml.load, Loader=SafeLoader)
_logger = logging.getLogger(__name__)


def yaml_from_file(filepath: str | Path) -> Any:
    """Return a loaded YAML file."""
    with open(str(filepath), encoding="utf-8") as content:
        return yaml_load(content)


def load_ignore_txt(filepath: Path | None = None) -> dict[str, set[str]]:
    """Return a list of rules to ignore."""
    result = defaultdict(set)

    ignore_file = None

    if filepath:
        if os.path.isfile(filepath):
            ignore_file = str(filepath)
        else:
            _logger.error("Ignore file not found '%s'", ignore_file)
    elif os.path.isfile(IGNORE_FILE.default):
        ignore_file = IGNORE_FILE.default
    elif os.path.isfile(IGNORE_FILE.alternative):
        ignore_file = IGNORE_FILE.alternative

    if ignore_file:
        with open(ignore_file, encoding="utf-8") as _ignore_file:
            _logger.debug("Loading ignores from '%s'", ignore_file)
            for line in _ignore_file:
                entry = line.split("#")[0].rstrip()
                if entry:
                    try:
                        path, rule = entry.split()
                    except ValueError as exc:
                        raise RuntimeError(
                            f"Unable to parse line '{line}' from {ignore_file} file."
                        ) from exc
                    result[path].add(rule)

    return result


__all__ = [
    "load_ignore_txt",
    "yaml_from_file",
    "yaml_load",
    "yaml_load_safe",
    "YAMLError",
    "IGNORE_FILE",
]
