from typing import Sequence
from typing import Optional
from typing import Dict
from typing import Any


def _fit(
    genes: Sequence[str],
    lineage_names: Sequence[Optional[str]],
    start_lineages: Sequence[Optional[str]],
    end_lineages: Sequence[Optional[str]],
    queue,
    **kwargs,
) -> Dict[str, Dict[str, Any]]:
    """
    Fit model for given genes and lineages.

    Params
    ------
    genes
        Genes for which to fit the models.
    lineage_names
        Lineages for which to fit the models.
    start_lineages
        Start clusters for given :paramref:`lineage_names`.
    end_lineages
        End clusters for given :paramref:`lineage_names`.
    queue
        Signalling queue in the parent process/thread used to update the progress bar.
    kwargs
        Keyword arguments for :func:`cellrank.utils.models.Model.prepare`.

    Returns
    -------
        The fitted models, optionally containing the confidence interval.
    """

    res = {}
    models = kwargs.pop("models")
    conf_int = kwargs.pop("conf_int", False)

    for gene in genes:
        res[gene] = {}
        for ln, sc, ec in zip(lineage_names, start_lineages, end_lineages):
            model = (
                models[gene][ln]
                .prepare(gene, ln, start_lineage=sc, end_lineage=ec, **kwargs)
                .fit()
            )
            model.predict()
            if conf_int:
                model.confidence_interval()

            res[gene][ln] = model
        queue.put(1)
    queue.put(None)

    return res