"""LanguageTool command line."""

import argparse
import locale
import re
import sys

from .server import LanguageTool
from .utils import LanguageToolError

import pkg_resources 
__version__ = pkg_resources.require("language_tool_python")[0].version


def parse_args():
    parser = argparse.ArgumentParser(
        description=__doc__.strip() if __doc__ else None,
        prog='language_tool_python')
    parser.add_argument('files', nargs='+',
                        help='plain text file or "-" for stdin')
    parser.add_argument('-c', '--encoding',
                        help='input encoding')
    parser.add_argument('-l', '--language', metavar='CODE',
                        help='language code of the input or "auto"')
    parser.add_argument('-m', '--mother-tongue', metavar='CODE',
                        help='language code of your first language')
    parser.add_argument('-d', '--disable', metavar='RULES', type=get_rules,
                        action=RulesAction, default=set(),
                        help='list of rule IDs to be disabled')
    parser.add_argument('-e', '--enable', metavar='RULES', type=get_rules,
                        action=RulesAction, default=set(),
                        help='list of rule IDs to be enabled')
    parser.add_argument('--enabled-only', action='store_true',
                        help='disable all rules except those specified in '
                             '--enable')
    parser.add_argument(
        '--version', action='version',
        version='%(prog)s {}'.format(__version__),
        help='show version')
    parser.add_argument('-a', '--apply', action='store_true',
                        help='automatically apply suggestions if available')
    parser.add_argument('-s', '--spell-check-off', dest='spell_check',
                        action='store_false',
                        help='disable spell-checking rules')
    parser.add_argument('--ignore-lines',
                        help='ignore lines that match this regular expression')
    parser.add_argument('--remote-host',
                        help='hostname of the remote LanguageTool server')
    parser.add_argument('--remote-port',
                        help='port of the remote LanguageTool server')

    args = parser.parse_args()

    if args.enabled_only:
        if args.disable:
            parser.error('--enabled-only cannot be used with --disable')

        if not args.enable:
            parser.error('--enabled-only requires --enable')

    return args


class RulesAction(argparse.Action):
    def __call__(self, parser, namespace, values, option_string=None):
        getattr(namespace, self.dest).update(values)


def get_rules(rules: str) -> set:
    return {rule.upper() for rule in re.findall(r"[\w\-]+", rules)}


def get_text(filename, encoding, ignore):
    with open(filename, encoding=encoding) as f:
        text = ''.join('\n' if (ignore and re.match(ignore, line)) else line
                       for line in f.readlines())
    return text


def print_unicode(text):
    """Print in a portable manner."""
    if sys.version_info[0] < 3:
        text = text.encode('utf-8')

    print(text)


def main():
    args = parse_args()

    status = 0

    for filename in args.files:
        if len(args.files) > 1:
            print(filename, file=sys.stderr)

        if filename == '-':
            filename = sys.stdin.fileno()
            encoding = args.encoding or (
                sys.stdin.encoding if sys.stdin.isatty()
                else locale.getpreferredencoding()
            )
        else:
            encoding = args.encoding or 'utf-8'

        remote_server = None
        if args.remote_host is not None:
            remote_server = args.remote_host
            if args.remote_port is not None:
                remote_server += ':{}'.format(args.remote_port)
        lang_tool = LanguageTool(
            motherTongue=args.mother_tongue,
            remote_server=remote_server,
        )
        guess_language = None

        try:
            text = get_text(filename, encoding, ignore=args.ignore_lines)
        except UnicodeError as exception:
            print('{}: {}'.format(filename, exception), file=sys.stderr)
            continue

        if args.language:
            if args.language.lower() == 'auto':
                try:
                    from guess_language import guess_language
                except ImportError:
                    print('guess_language is unavailable.', file=sys.stderr)
                    return 1
                else:
                    language = guess_language(text)
                    print('Detected language: {}'.format(language),
                          file=sys.stderr)
                    if not language:
                        return 1
                    lang_tool.language = language
            else:
                lang_tool.language = args.language

        if not args.spell_check:
            lang_tool.disable_spellchecking()

        lang_tool.disabled_rules.update(args.disable)
        lang_tool.enabled_rules.update(args.enable)
        lang_tool.enabled_rules_only = args.enabled_only

        try:
            if args.apply:
                print_unicode(lang_tool.correct(text))
            else:
                for match in lang_tool.check(text):
                    rule_id = match.ruleId

                    replacement_text = ', '.join(
                        "'{}'".format(word)
                        for word in match.replacements).strip()

                    message = match.message

                    # Messages that end with punctuation already include the
                    # suggestion.
                    if replacement_text and not message.endswith(('.', '?')):
                        message += '; suggestions: ' + replacement_text

                    print_unicode('{}: {}: {}'.format(
                        filename,
                        rule_id,
                        message))

                    status = 2
        except LanguageToolError as exception:
            print('{}: {}'.format(filename, exception), file=sys.stderr)
            continue

    return status


sys.exit(main())