import argparse
import importlib
import logging
import sys
import warnings

from ocdskit.exceptions import CommandError
from ocdskit.util import ijson

logger = logging.getLogger("ocdskit")

COMMAND_MODULES = (
    "ocdskit.commands.combine_record_packages",
    "ocdskit.commands.combine_release_packages",
    "ocdskit.commands.compile",
    "ocdskit.commands.detect_format",
    "ocdskit.commands.echo",
    "ocdskit.commands.indent",
    "ocdskit.commands.mapping_sheet",
    "ocdskit.commands.package_records",
    "ocdskit.commands.package_releases",
    "ocdskit.commands.schema_report",
    "ocdskit.commands.schema_strict",
    "ocdskit.commands.set_closed_codelist_enums",
    "ocdskit.commands.split_record_packages",
    "ocdskit.commands.split_release_packages",
    "ocdskit.commands.upgrade",
)


# The arguments are for use in oc4idskit.
def main(description="Open Contracting Data Standard CLI", modules=COMMAND_MODULES, logger=logger):
    parser = argparse.ArgumentParser(description=description)
    parser.add_argument("--encoding", help="the file encoding")
    parser.add_argument("--ascii", help="print escape sequences instead of UTF-8 characters", action="store_true")
    parser.add_argument("--pretty", help="pretty print output", action="store_true")

    subparsers = parser.add_subparsers(dest="subcommand")

    subcommands = {}

    for module in modules:
        try:
            command = importlib.import_module(module).Command(subparsers)
        except ImportError as e:
            logger.error('exception "%s" prevented loading of %s module', e, module)  # noqa: TRY400 # UX
        else:
            subcommands[command.name] = command

    args = parser.parse_args()

    if args.subcommand:
        command = subcommands[args.subcommand]
        try:
            command.args = args
            try:
                with warnings.catch_warnings():
                    warnings.showwarning = _showwarning
                    command.handle()
            except ijson.common.IncompleteJSONError as e:
                if e.args and isinstance(e.args[0], (bytes, UnicodeDecodeError)):
                    message = e.args[0]
                    if isinstance(e.args[0], bytes):  # YAJL backends
                        message = e.args[0].decode(errors="backslashreplace")
                    _raise_encoding_error(message, args.encoding)
                raise CommandError(f"JSON error: {e}") from e
            except UnicodeDecodeError as e:
                _raise_encoding_error(e, args.encoding)
        except CommandError as e:
            logger.critical(e)
            sys.exit(1)
    else:
        parser.print_help()


def _showwarning(message, category, filename, lineno, file=None, line=None):  # noqa: ARG001
    if file is None:
        file = sys.stderr
    print(message, file=file)


def _raise_encoding_error(e, encoding):
    suggestion = "utf-8" if encoding and encoding.lower() == "iso-8859-1" else "iso-8859-1"
    raise CommandError(f"encoding error: {e}\nTry `--encoding {suggestion}`?")


if __name__ == "__main__":
    main()
