import random
from typing import Optional

import factory

from common.tests import factories
from measures.sheet_importers import MeasureSheetRow


class MeasureSheetRowFactory(factory.Factory):
    """
    A factory that produces a row that might be read from a sheet of measures as
    recognised by the :class:`measures.sheet_importers.MeasureSheetRow`
    importer.

    The factory references a MeasureFactory to do the production of an actual
    Measure, and then references the data produced by the MeasureFactory to
    build up a row of string values.

    The values are then built into a tuple in the order specified in the
    `MeasureSheetRow` importer.
    """

    class Meta:
        model = tuple
        exclude = ["measure"]

    measure = factory.SubFactory(factories.MeasureFactory)

    item_id = factory.SelfAttribute("measure.goods_nomenclature.item_id")
    measure_type_description = factory.SelfAttribute("measure.measure_type.description")
    duty_sentence = factory.sequence(lambda n: f"{n}.00%")
    origin_description = factory.LazyAttribute(
        lambda m: m.measure.geographical_area.get_description().description,
    )
    excluded_origin_descriptions = factory.LazyAttribute(
        lambda m: random.choice(MeasureSheetRow.separators).join(
            e.excluded_geographical_area.get_description().description
            for e in m.measure.exclusions.all()
        ),
    )
    quota_order_number = factory.LazyAttribute(
        lambda m: m.measure.order_number.order_number
        if m.measure.order_number
        else m.measure.dead_order_number,
    )
    additional_code_id = factory.LazyAttribute(
        lambda m: m.measure.additional_code.type.sid + m.measure.additional_code.code
        if m.measure.additional_code
        else m.measure.dead_additional_code,
    )
    validity_start_date = factory.SelfAttribute("measure.valid_between.lower")
    validity_end_date = factory.SelfAttribute("measure.valid_between.upper")
    regulation_id = factory.SelfAttribute("measure.generating_regulation.regulation_id")
    footnote_ids = factory.LazyAttribute(
        lambda m: random.choice(MeasureSheetRow.separators).join(
            f.footnote_type.footnote_type_id + f.footnote_id
            for f in m.measure.footnotes.all()
        ),
    )

    @factory.lazy_attribute
    def conditions(self) -> Optional[str]:
        """Returns a string that can be parsed by the
        :class:`measures.parsers.ConditionSentenceParser`."""
        if not self.measure.conditions.exists():
            return None

        parts = []
        for c in self.measure.conditions.all():
            part = []
            part.append(c.condition_code.code)
            if c.required_certificate:
                part.append("cert:")
                part.append(
                    f"{c.required_certificate.certificate_type.sid}-{c.required_certificate.sid}",
                )
            part.append(f"({c.action.code}):")
            parts.append(" ".join(part))
        return f"Cond: {'; '.join(parts)}"

    @classmethod
    def _create(cls, model_class, *args, **kwargs):
        data = [kwargs[k] for k in MeasureSheetRow.columns]
        return super()._create(model_class, data)

[((28, 14, 28, 58), 'factory.SubFactory', 'factory.SubFactory', ({(28, 33, 28, 57): 'factories.MeasureFactory'}, {}), '(factories.MeasureFactory)', False, 'import factory\n'), ((30, 14, 30, 73), 'factory.SelfAttribute', 'factory.SelfAttribute', ({(30, 36, 30, 72): '"""measure.goods_nomenclature.item_id"""'}, {}), "('measure.goods_nomenclature.item_id')", False, 'import factory\n'), ((31, 31, 31, 88), 'factory.SelfAttribute', 'factory.SelfAttribute', ({(31, 53, 31, 87): '"""measure.measure_type.description"""'}, {}), "('measure.measure_type.description')", False, 'import factory\n'), ((32, 20, 32, 58), 'factory.sequence', 'factory.sequence', ({(32, 37, 32, 57): "lambda n: f'{n}.00%'"}, {}), "(lambda n: f'{n}.00%')", False, 'import factory\n'), ((42, 25, 46, 5), 'factory.LazyAttribute', 'factory.LazyAttribute', ({(43, 8, 45, 40): 'lambda m: m.measure.order_number.order_number if m.measure.order_number else m.measure.dead_order_number'}, {}), '(lambda m: m.measure.order_number.order_number if m.\n    measure.order_number else m.measure.dead_order_number)', False, 'import factory\n'), ((47, 25, 51, 5), 'factory.LazyAttribute', 'factory.LazyAttribute', ({(48, 8, 50, 43): 'lambda m: m.measure.additional_code.type.sid + m.measure.additional_code.code if m.measure.additional_code else m.measure.dead_additional_code'}, {}), '(lambda m: m.measure.additional_code.type.sid + m.\n    measure.additional_code.code if m.measure.additional_code else m.\n    measure.dead_additional_code)', False, 'import factory\n'), ((52, 26, 52, 78), 'factory.SelfAttribute', 'factory.SelfAttribute', ({(52, 48, 52, 77): '"""measure.valid_between.lower"""'}, {}), "('measure.valid_between.lower')", False, 'import factory\n'), ((53, 24, 53, 76), 'factory.SelfAttribute', 'factory.SelfAttribute', ({(53, 46, 53, 75): '"""measure.valid_between.upper"""'}, {}), "('measure.valid_between.upper')", False, 'import factory\n'), ((54, 20, 54, 88), 'factory.SelfAttribute', 'factory.SelfAttribute', ({(54, 42, 54, 87): '"""measure.generating_regulation.regulation_id"""'}, {}), "('measure.generating_regulation.regulation_id')", False, 'import factory\n'), ((37, 18, 37, 59), 'random.choice', 'random.choice', ({(37, 32, 37, 58): 'MeasureSheetRow.separators'}, {}), '(MeasureSheetRow.separators)', False, 'import random\n'), ((56, 18, 56, 59), 'random.choice', 'random.choice', ({(56, 32, 56, 58): 'MeasureSheetRow.separators'}, {}), '(MeasureSheetRow.separators)', False, 'import random\n')]