import inspect


def _make_experiment_signature(function):
    """Generate an ExperimentTemplate's signature from its function.

    Checks that the first parameter is named ctxt and removes it from the
    signature. Makes all other parameters keyword only.

    Args:
        function (callable[ExperimentContext, ...]): The wrapped function.

    Returns:
        inspect.Signature: The signature of the ExperimentTemplate.

    Raises:
        ValueError: If the wrapped function's first parameter is not 'ctxt'.

    """
    func_sig = inspect.signature(function)
    new_params = []
    saw_first_param = False
    for param in func_sig.parameters.values():
        if not saw_first_param:
            # Don't output it to the experiment params, since it will contain
            # the context.
            if param.name != 'ctxt':
                raise ValueError(
                    'Experiment functions should have a first '
                    "parameter named 'ctxt' instead of {!r}".format(
                        param.name))
            saw_first_param = True
        else:
            new_params.append(
                inspect.Parameter(name=param.name,
                                  kind=inspect.Parameter.KEYWORD_ONLY,
                                  default=param.default,
                                  annotation=param.annotation))
    if not saw_first_param:
        raise ValueError(
            'Experiment functions should have a first parameter '
            "named 'ctxt', but {!r} has no parameters".format(function))
    return inspect.Signature(new_params,
                             return_annotation=func_sig.return_annotation)