from pathlib import Path


def construct_filename(output_dir,
                       file_descriptor,
                       extension,
                       *args,
                       **kwargs):
    """Construct a filename from varying experimental parameters.

    The format of the filename will roughly look like this:
    {output_dir}/{a}_{k}_{file_descriptor}{extension}
    where a = '_'.join([ar for ar in args]),
          k = '_'.join(['{k}{v} for k, v in kwargs.items()])

    For example:
    >>> construct_filename('output_dir', 'output', '.tsv',
    ...                    'expression', 'signal',
    ...                    s=42, n=5000)
    output_dir/expression_signal_s42_n5000_output.tsv

    Also note that if a parameter has a value of None, it will be silently
    skipped in the output filename.
    """
    if len(args) == 0 and len(kwargs) == 0:
        return Path(output_dir,
                    '{}{}'.format(file_descriptor, extension))
    elif len(args) == 0:
        return Path(output_dir,
                    '{}_{}{}'.format('_'.join([f'{k}{v}' for k, v in kwargs.items()
                                                             if v is not None]),
                                     file_descriptor,
                                     extension))
    elif len(kwargs) == 0:
        return Path(output_dir,
                    '{}_{}{}'.format('_'.join([ar for ar in args if ar is not None]),
                                     file_descriptor,
                                     extension))
    else:
        return Path(output_dir,
                    '{}_{}_{}{}'.format('_'.join([ar for ar in args if ar is not None]),
                                        '_'.join([f'{k}{v}' for k, v in kwargs.items()
                                                                if v is not None]),
                                        file_descriptor,
                                        extension))