"""Module for the OdkChoices class."""
from ppp.definitions.error import InvalidLanguageException
from ppp.definitions.constants import CHOICE_NAME_VARIATIONS


class OdkChoices:
    """A class to represent a choice list defined in an XLSForm.

    Attributes:
        list_name (str): The name of the choice list.
        data (list): A list of choice options for the choice list.

    """

    def __init__(self, list_name):
        """Initialize a choice list.

        Args:
            list_name (str): The name of the choice list.
        """
        self.list_name = list_name
        self.data = []

    def __repr__(self):
        """Print representation of instance."""
        return "<Odkchoices '{}(len: {})'>".format(self.list_name, len(self.data))

    def __str__(self):
        """Convert instance to string."""
        return "{}: {}".format(self.list_name, self.labels(lang="English"))

    def add(self, choice):
        """Add a choice to this choice list.

        Args:
            choice (dict): A single choice row.
        """
        self.data.append(choice)

    def labels(self, lang=""):
        """Get the labels for this choice list in the desired language.

        Args:
            lang (str): The language in which to return the choice labels.

        Returns:
            list: Correctly ordered list of choice labels.

        Raises:
            InvalidLanguageException
        """
        label_variations = []
        if lang:
            label_variations += [x.format(lang) for x in ("label::{}", "label:{}")]
        else:
            label_variations.append("label")

        try:
            col_header = ""
            for label in label_variations:
                if label in self.data[0]:
                    col_header = label
            if not col_header:
                raise KeyError
            return [d[col_header] for d in self.data]
        except (KeyError, IndexError):
            msg = (
                "InvalidLanguageException: "
                "Language '{}' not found in choice list '{}'.\n"
                "You may want to check for the following:\n"
                "- Are the languages in the 'survey' and 'choices' "
                "worksheets consistent?\n"
                "- Is there an issue with 'default_language' in the "
                "'settings' worksheet?".format(lang, self.list_name)
            )
            raise InvalidLanguageException(msg)

    def name_labels(self, lang):
        """Get choice name labels.

        Args:
            lang (str): The language of choice list.

        Returns:
            list: Choice variable names and associated labels for choice list.
        """
        rows = enumerate(self.data)
        labels = self.labels(lang)
        formatted_rows = []
        for i, row in rows:
            formatted_row = {"label": labels[i]}
            for x in CHOICE_NAME_VARIATIONS:
                if x in row:
                    formatted_row["name"] = row[x]
            formatted_rows.append(formatted_row)
        return formatted_rows

    def choice_langs(self):
        """Discover all languages for these choices.

        Returns:
            list: Alphabetized list of languages.

        Raises:
            InvalidLanguageException: If languages of first row differ from
                languages in any other row.
        """
        langs = set()
        for datum in self.data:
            these_langs = set()
            for k in datum:
                if k == "label":
                    these_langs.add("")  # Default language
                elif k.startswith("label::"):
                    lang = k[len("label::") :]
                    these_langs.add(lang)
                elif k.startswith("label:"):
                    lang = k[len("label:") :]
                    these_langs.add(lang)
            if not langs:
                langs = these_langs
            elif langs != these_langs:
                msg = "In choice list {}, different languages found: {} and {}"
                msg = msg.format(self.list_name, langs, these_langs)
                raise InvalidLanguageException(msg)
        lang_list = sorted(list(langs))
        return lang_list
