# -*- coding: utf-8 -*-

"""
Call as script
"""

import logging
import sys

from argparse import REMAINDER, ArgumentParser
from enum import Enum
from importlib.metadata import PackageNotFoundError, version as metadata_version
from json import dumps as json_dumps, load as json_load
from pathlib import Path
from sys import stdin

from . import FrozenStructure
from .commons import DOT

if sys.version_info >= (3, 11):
    from tomllib import loads as tomli_loads
else:
    from tomli import loads as tomli_loads  # ty: ignore[unresolved-import]
#


_PACKAGE_NAME = "ncw"
_DEFAULT_SEPARATOR = DOT
_INFO_TEXT = """This package does not have a useful commandline interface;
programs like jq and yq offer much more sophisticated functionality
for shell environments, and we do not intend to re-invent the wheel.

That being said, you can use the '-c' option to construct a simple
nested collection using one or more 'deep.nested.locator=value' expressions
and prion it to stdout as JSON,
or the '-x' option to extract values from JSON provided through standard input
using one or more 'deep.nested.locator' expressions, and print the extracted
values to stdout.

Package documentation is available at https://blackstream-x.gitlab.io/ncw/"""


class Action(Enum):
    """Possible actions"""

    NOTHING = 0
    EXTRACT = 1
    CONSTRUCT = 2


def get_file_contents(file_name: str, up_dirs: int = 0) -> str:
    """get contents of a file in an ancestor directory
    of the current file (up_dirs directory levels up)
    """
    file_dir_path = Path(__file__).resolve()
    for _ in range(up_dirs):
        file_dir_path = file_dir_path.parent
    #
    file_path = file_dir_path / file_name
    return file_path.read_text(encoding="utf-8")


def get_metadata_version(
    metadata_file_name: str = "pyproject.toml", up_dirs: int = 3
) -> str:
    """get version information from metadata_file up_dirs directories above"""
    try:
        metadata_file_contents = get_file_contents(metadata_file_name, up_dirs=up_dirs)
    except IOError as error:
        return str(error)
    #
    metadata = FrozenStructure.from_native(tomli_loads(metadata_file_contents))
    try:
        # logging.warning(str(metadata.items()))
        version = metadata["project.version"]
    except KeyError:
        return f"Error: no version information in metadata from {metadata_file_name}"
    #
    return f"{version} (read directly from {metadata_file_name})"


def construct(expressions: list[str], separator: str = _DEFAULT_SEPARATOR) -> None:
    """Construct a structure and print its JSON representation"""
    source_items: list[tuple[str, str]] = []
    for index, current_expression in enumerate(expressions):
        try:
            collection_index, value = current_expression.split("=", 1)
        except ValueError as error:
            raise ValueError(
                f"Expression #{index + 1} ({current_expression!r})"
                " must contain at least one 'equals' sign ('=')"
            ) from error
        #
        source_items.append((collection_index, value))
    #
    fs = FrozenStructure(source_items, separator=separator)
    print(json_dumps(fs.to_native(), indent=2))


def extract(expressions: list[str], separator: str = _DEFAULT_SEPARATOR) -> None:
    """Extract items from the nested collection receibed as JSON through stdin"""
    fs = FrozenStructure.from_native(
        json_load(stdin),
        separator=separator,
    )
    for collection_index in expressions:
        value = fs[collection_index]
        if isinstance(value, str):
            print(value)
        else:
            print(json_dumps(value, indent=2))
        #
    #


def dispatch(
    action: Action, expressions: list[str], separator: str = _DEFAULT_SEPARATOR
) -> None:
    """Dispatch to the specialized functions"""
    if expressions:
        if action == Action.CONSTRUCT:
            return construct(expressions, separator=separator)
        #
        if action == Action.EXTRACT:
            return extract(expressions, separator=separator)
        #
    #
    return print(_INFO_TEXT)


def main() -> int:
    """Script fuction autogenerated by uv, might delete later"""
    try:
        version = metadata_version(_PACKAGE_NAME)
    except PackageNotFoundError:
        version = get_metadata_version()
    #
    argument_parser = ArgumentParser(
        prog="ncw", description="Nested collections wrapper"
    )
    argument_parser.set_defaults(action=Action.NOTHING)
    argument_parser.add_argument("--version", action="version", version=version)
    argument_parser.add_argument(
        "-s", "--separator", default=".", help="separator character"
    )
    mutex_group = argument_parser.add_mutually_exclusive_group()
    mutex_group.add_argument(
        "-c",
        "--construct",
        action="store_const",
        const=Action.CONSTRUCT,
        dest="action",
        help="construct a nested data structure",
    )
    mutex_group.add_argument(
        "-x",
        "--extract",
        action="store_const",
        const=Action.EXTRACT,
        dest="action",
        help="extract an item from the data structure read from stdin",
    )
    argument_parser.add_argument("expressions", nargs=REMAINDER, help="index=value")
    arguments = argument_parser.parse_args()
    try:
        dispatch(arguments.action, arguments.expressions, separator=arguments.separator)
    except (IndexError, KeyError, TypeError, ValueError) as error:
        logging.error(repr(error))
        return 1
    #
    return 0


if __name__ == "__main__":
    sys.exit(main())  # not testable

# vim: fileencoding=utf-8 ts=4 sts=4 sw=4 autoindent expandtab syntax=python:
