from itertools import chain
from django.db import models


class FieldListBuilder(object):
    """Класс для формирования множества полей в выдаче.
    `get_all_fields` формирует общий список полей с учетом связанных,
    дополнительных и исключенных.
    """

    def __init__(self, model, related_fields=None, extra_fields=None,
                 excluded_fields=None):
        self.model = model
        self.related_fields = related_fields
        self.extra_fields = extra_fields
        self.excluded_fields = excluded_fields
        super(FieldListBuilder, self).__init__()

    def get_model_fields(self):
        """Поля модели, для внешних ключей вида поле_id"""
        for field in self.model._meta.fields:
            if isinstance(field, models.ForeignKey):
                yield field.name + '_id'
            else:
                yield field.name

    def get_related_fields(self):
        """Поля моделей"""
        # TODO: не передавать класс модели, автоматически интроспектить
        for foreign_field_name, model_ in self.related_fields.items():
            builder = self.__class__(model=model_)
            for field_name in builder.get_model_fields():
                yield foreign_field_name + '__' + field_name

    def get_extra_fields(self):
        for field in self.extra_fields:
            yield field

    def get_all_fields(self):
        iterables = [self.get_model_fields()]

        if self.related_fields is not None:
            iterables.append(self.get_related_fields())
        if self.extra_fields is not None:
            iterables.append(self.get_extra_fields())

        all_fields_sequence = chain(*iterables)

        if self.excluded_fields is None:
            return all_fields_sequence
        else:
            return [field for field in all_fields_sequence if field not in self.excluded_fields]

    def filter_valid_fields(self, requested_fields):
        for field in requested_fields:
            if field in self.get_all_fields():
                yield field
