# Source code for lesana.command

    import argparse
    import logging
    import os
    import sys

    import hazwaz

    try:
        import argcomplete
    except ImportError:
        argcomplete = None  # type: ignore

    from . import Collection, Entry, TemplatingError

    logger = logging.getLogger(__name__)

    class Command(hazwaz.Command):
        def __init__(self, collection_class=Collection, entry_class=Entry):
            super().__init__()
            self.collection_class = collection_class
            self.entry_class = entry_class

        def add_arguments(self, parser: argparse.ArgumentParser):
            # compatibility with the old way to add arguments: for new
            # commands override add_arguments directly
            for arg in getattr(self, "arguments", []):
                parser.add_argument(*arg[0], **arg[1])

    class New(Command, hazwaz.mixins.ExternalEditorMixin):
        """
        Create a new entry
        """
        arguments = [
            (
                ['--collection', '-c'],
                dict(help='The collection to work on (default .)'),
            ),
            (
                ['--no-git'],
                dict(
                    help="Don't add the new entry to git",
                    action="store_false",
                    dest='git',
                ),
            ),
        ]

        def main(self):
            collection = self.collection_class(self.args.collection)
            new_entry = self.entry_class(collection)
            collection.save_entries([new_entry])
            filepath = os.path.join(collection.itemdir, new_entry.fname)
            if self.edit_file_in_external_editor(filepath):
                collection.update_cache([filepath])
                if self.args.git:
                    collection.git_add_files([filepath])
            saved_entry = collection.entry_from_eid(new_entry.eid)
            print(saved_entry)

    class Edit(Command, hazwaz.mixins.ExternalEditorMixin):
        """
        Edit a lesana entry
        """
        arguments = [
            (
                ['--collection', '-c'],
                dict(help='The collection to work on (default .)'),
            ),
            (
                ['--no-git'],
                dict(
                    help="Don't add the new entry to git",
                    action="store_false",
                    dest='git',
                ),
            ),
            (['eid'], dict(help='eid of an entry to edit',)),
        ]

        def main(self):
            collection = self.collection_class(self.args.collection)
            entries = collection.entries_from_short_eid(self.args.eid)
            if len(entries) > 1:
                return "{} is not an unique eid".format(self.args.eid)
            if not entries:
                return "Could not find an entry with eid starting with: {}".format(
                    self.args.eid
                )
            entry = entries[0]
            # update the entry before editing it
            entry.auto()
            collection.save_entries([entry])
            # and then edit the updated file
            filepath = os.path.join(collection.itemdir, entry.fname)
            if self.edit_file_in_external_editor(filepath):
                collection.update_cache([filepath])
                if self.args.git:
                    collection.git_add_files([filepath])
            saved_entry = collection.entry_from_eid(entry.eid)
            print(saved_entry)

    class Show(Command):
        """
        Show a lesana entry
        """
        arguments = [
            (
                ['--collection', '-c'],
                dict(help='The collection to work on (default .)'),
            ),
            (
                ['--template', '-t'],
                dict(help='Use the specified template to display results.',),
            ),
            (['eid'], dict(help='eid of an entry to edit',)),
        ]

        def main(self):
            collection = self.collection_class(self.args.collection)
            entries = collection.entries_from_short_eid(self.args.eid)
            if len(entries) > 1:
                return "{} is not an unique eid".format(self.args.eid)
            if not entries:
                return "Could not find an entry with eid starting with: {}".format(
                    self.args.eid
                )
            entry = entries[0]
            if self.args.template:
                try:
                    print(entry.render(self.args.template))
                except TemplatingError as e:
                    logger.error("{}".format(e))
                    sys.exit(1)
            else:
                print(entry.yaml_data)

    class Index(Command):
        """
        Index entries in a lesana collection
        """
        arguments = [
            (
                ['--collection', '-c'],
                dict(help='The collection to work on (default .)'),
            ),
            (
                ['--reset'],
                dict(
                    action='store_true',
                    help='Delete the existing index and reindex from scratch.',
                ),
            ),
            (
                ['files'],
                dict(
                    help='List of files to index (default: everything)',
                    default=None,
                    nargs='*',
                ),
            ),
        ]

        def main(self):
            collection = self.collection_class(self.args.collection)
            if self.args.files:
                files = (os.path.basename(f) for f in self.args.files)
            else:
                files = None
            indexed = collection.update_cache(
                fnames=files,
                reset=self.args.reset
            )
            print("Found and indexed {} entries".format(indexed))

    class Search(Command):
        """
        Search for entries
        """
        arguments = [
            (
                ['--collection', '-c'],
                dict(help='The collection to work on (default .)'),
            ),
            (
                ['--template', '-t'],
                dict(help='Template to use when displaying results',),
            ),
            (['--offset'], dict(type=int,)),
            (['--pagesize'], dict(type=int,)),
            (
                ['--all'],
                dict(action='store_true', help='Return all available results'),
            ),
            (
                ['--sort'],
                dict(action='append', help='Sort results by a sortable field'),
            ),
            (
                ['--expand-query-template', '-e'],
                {
                    'action': 'store_true',
                    'help':
                        'Render search_aliases in the query as a jinja2 template',
                },
            ),
            (
                ['query'],
                {
                    'help': 'Xapian query to search in the collection',
                    'nargs': '*',
                    'default': '*',
                },
            ),
        ]

        def main(self):
            # TODO: implement "searching" for everything
            if self.args.offset:
                logger.warning(
                    "offset exposes an internal knob and MAY BE REMOVED "
                    + "from a future release of lesana"  # noqa: W503
                )
            if self.args.pagesize:
                logger.warning(
                    "pagesize exposes an internal knob and MAY BE REMOVED "
                    + "from a future release of lesana"  # noqa: W503
                )
            offset = self.args.offset or 0
            pagesize = self.args.pagesize or 12
            collection = self.collection_class(self.args.collection)
            query = self.args.query
            if self.args.expand_query_template:
                for i, q in enumerate(query):
                    query[i] = collection.render_query_template(q)
            # sorted results require a less efficient full search rather
            # than being able to use the list of all documents.
            if query == ['*'] and not (
                self.args.sort
                or getattr(collection.settings, 'default_sort', False)
            ):
                results = collection.get_all_documents()
            else:
                collection.start_search(
                    ' '.join(query),
                    sort_by=self.args.sort
                )
                if self.args.all:
                    results = collection.get_all_search_results()
                else:
                    results = collection.get_search_results(offset, pagesize)
            if self.args.template:
                try:
                    template = collection.get_template(self.args.template)
                    print(template.render(entries=results))
                except TemplatingError as e:
                    logger.error("{}".format(e))
                    sys.exit(1)
            else:
                for entry in results:
                    print("{entry}".format(entry=entry,))

    class GetValues(Command):
        """
        List all values for one field, with entry counts.
        """
        name = "get-values"

        arguments = [
            (
                ['--collection', '-c'],
                {
                    'help': 'The collection to work on (default .)'
                },
            ),
            (
                ['--field', '-f'],
                {
                    'help': 'Name of the field',
                    'required': True,
                },
            ),
            (
                ['--template', '-t'],
                {
                    'help': 'Template to use when displaying results',
                },
            ),
            (
                ['query'],
                {
                    'help': 'Xapian query to limit the count search " \
                          + "in the collection',
                    'nargs': '*',
                    'default': '*'
                },
            ),
        ]

        def main(self):
            collection = self.collection_class(self.args.collection)
            counts = collection.get_field_values(
                self.args.field,
                ' '.join(self.args.query)
            )
            if self.args.template:
                try:
                    template = collection.get_template(self.args.template)
                    print(template.render(counts=counts))
                except TemplatingError as e:
                    logger.error("{}".format(e))
                    sys.exit(1)
            else:
                for v in counts:
                    print("{value}: {count}".format(
                        value=v['value'],
                        count=v['frequency']
                    ))

    class Export(Command):
        """
        Export entries to a different collection
        """
        arguments = [
            (
                ['--collection', '-c'],
                dict(help='The collection to work on (default .)'),
            ),
            (
                ['--query', '-q'],
                dict(help='Xapian query to search in the collection',),
            ),
            (['destination'], dict(help='The collection to export entries to')),
            (['template'], dict(help='Template to convert entries',)),
        ]

        def main(self):
            collection = self.collection_class(self.args.collection)
            destination = self.collection_class(self.args.destination)
            if not self.args.query:
                results = collection.get_all_documents()
            else:
                collection.start_search(' '.join(self.args.query))
                results = collection.get_all_search_results()
            for entry in results:
                data = {
                    "entry": entry
                }
                data.update(entry.data)
                try:
                    destination.entry_from_rendered_template(
                        self.args.template,
                        data
                    )
                except TemplatingError as e:
                    logger.error("Error converting entry: {}".format(entry))
                    logger.error("{}".format(e))
                    sys.exit(1)

    class Init(Command, hazwaz.mixins.ExternalEditorMixin):
        """
        Initialize a lesana collection
        """
        arguments = [
            (
                ['--collection', '-c'],
                dict(help='The directory to work on (default .)', default='.'),
            ),
            (
                ['--no-git'],
                dict(
                    help='Skip setting up git in this directory',
                    action="store_false",
                    dest='git',
                ),
            ),
        ]

        def main(self):
            self.collection_class.init(
                self.args.collection,
                git_enabled=self.args.git,
                edit_file=self.edit_file_in_external_editor,
            )

    class Remove(Command):
        """
        Remove an entry from a collection
        """
        name = "rm"

        arguments = [
            (
                ['--collection', '-c'],
                dict(help='The collection to work on (default .)',),
            ),
            (['entries'], dict(help='List of entries to remove', nargs='+',)),
        ]

        def main(self):
            collection = self.collection_class(self.args.collection)
            collection.remove_entries(eids=self.args.entries)

    class Update(Command):
        """
        Update a field in multiple entries
        """
        arguments = [
            (
                ['--collection', '-c'],
                dict(help='The collection to work on (default .)',),
            ),
            (['--field', '-f'], dict(help='The field to change',)),
            (['--value', '-t'], dict(help='The value to set',)),
            (
                ['query'],
                dict(help='Xapian query to search in the collection', nargs='+'),
            ),
        ]

        def main(self):
            collection = self.collection_class(self.args.collection)
            collection.update_field(
                ' '.join(self.args.query),
                field=self.args.field,
                value=self.args.value,
            )

    class Lesana(hazwaz.MainCommand):
        """
        Manage collections
        """

        commands = (
            New(),
            Edit(),
            Show(),
            Index(),
            Search(),
            GetValues(),
            Update(),
            Export(),
            Init(),
            Remove(),
        )

    def main():
        Lesana().run()