# ----------------------------------------------------------------------------
# Copyright (c) 2016-2022, QIIME 2 development team.
#
# Distributed under the terms of the Modified BSD License.
#
# The full license is in the file LICENSE, distributed with this software.
# ----------------------------------------------------------------------------

import click

from .type import QIIME2Type

# Sentinel to avoid the situation where `None` *is* the default value.
NoDefault = {}


class GeneratedOption(click.Option):
    def __init__(self, *, prefix, name, repr, ast, multiple, is_bool_flag,
                 metadata, metavar, default=NoDefault, description=None,
                 **attrs):
        import q2cli.util

        if metadata is not None:
            prefix = 'm'
        if multiple is not None:
            multiple = list if multiple == 'list' else set

        if is_bool_flag:
            yes = q2cli.util.to_cli_name(name)
            no = q2cli.util.to_cli_name('no_' + name)
            opt = f'--{prefix}-{yes}/--{prefix}-{no}'
        elif metadata is not None:
            cli_name = q2cli.util.to_cli_name(name)
            opt = f'--{prefix}-{cli_name}-file'
            if metadata == 'column':
                self.q2_extra_dest, self.q2_extra_opts, _ = \
                    self._parse_decls([f'--{prefix}-{cli_name}-column'], True)
        else:
            cli_name = q2cli.util.to_cli_name(name)
            opt = f'--{prefix}-{cli_name}'

        click_type = QIIME2Type(ast, repr, is_output=prefix == 'o')
        attrs['metavar'] = metavar
        attrs['multiple'] = multiple is not None
        attrs['param_decls'] = [opt]
        attrs['required'] = default is NoDefault
        attrs['help'] = self._add_default(description, default)
        if default is not NoDefault:
            attrs['default'] = default

        # This is to evade clicks __DEBUG__ check
        if not is_bool_flag:
            attrs['type'] = click_type
        else:
            attrs['type'] = None

        super().__init__(**attrs)
        # put things back the way they _should_ be after evading __DEBUG__
        self.is_bool_flag = is_bool_flag
        self.type = click_type

        # attrs we will use elsewhere
        self.q2_multiple = multiple
        self.q2_prefix = prefix
        self.q2_name = name
        self.q2_ast = ast
        self.q2_metadata = metadata

    @property
    def meta_help(self):
        if self.q2_metadata == 'file':
            return 'multiple arguments will be merged'

    def _add_default(self, desc, default):
        if desc is not None:
            desc += '  '
        else:
            desc = ''
        if default is not NoDefault:
            if default is None:
                desc += '[optional]'
            else:
                desc += '[default: %r]' % (default,)
        return desc

    def consume_value(self, ctx, opts):
        if self.q2_metadata == 'column':
            return self._consume_metadata(ctx, opts)
        else:
            return super().consume_value(ctx, opts)

    def _consume_metadata(self, ctx, opts):
        # double consume
        md_file = super().consume_value(ctx, opts)
        # consume uses self.name, so mutate but backup for after
        backup, self.name = self.name, self.q2_extra_dest
        md_col = super().consume_value(ctx, opts)
        self.name = backup

        if (md_col is None) != (md_file is None):
            # missing one or the other
            if md_file is None:
                raise click.MissingParameter(ctx=ctx, param=self)
            else:
                raise click.MissingParameter(param_hint=self.q2_extra_opts,
                                             ctx=ctx, param=self)

        if md_col is None and md_file is None:
            return None
        else:
            return (md_file, md_col)

    def get_help_record(self, ctx):
        record = super().get_help_record(ctx)
        if self.is_bool_flag:
            metavar = self.make_metavar()
            if metavar: