from pulp import lpSum
from random import randint, sample
import logging

from lib.errors.item_generation_error import ItemGenerationError

def build_constraints(solver_run, problem, items):
  try:
    total_form_items = solver_run.total_form_items
    constraints = solver_run.constraints

    for constraint in constraints:
      attribute = constraint.reference_attribute
      min = constraint.minimum
      max = constraint.maximum

      if attribute.type == 'metadata':
        con = dict(zip([item.id for item in solver_run.items],
                      [item.attribute_exists(attribute)
                      for item in solver_run.items]))
        problem += lpSum([con[item.id]
                        * items[item.id]
                        for item in solver_run.items]) >= round(total_form_items * (min / 100)), f'{attribute.id} - {attribute.value} - min'
        problem += lpSum([con[item.id]
                        * items[item.id]
                        for item in solver_run.items]) <= round(total_form_items * (max / 100)), f'{attribute.id} - {attribute.value} - max'
      elif attribute.type == 'bundle':
        # # TODO: account for many different bundle types, since the id condition in L33 could yield duplicates
        total_bundles = randint(constraint.minimum, constraint.maximum)
        selected_bundles = sample(solver_run.bundles, total_bundles)

        for bundle in selected_bundles:
          con = dict(zip([item.id for item in solver_run.items],
                      [(getattr(item, bundle.type, False) == bundle.id)
                      for item in solver_run.items]))
          problem += lpSum([con[item.id]
                          * items[item.id]
                          for item in solver_run.items]) == bundle.count, f'Bundle constraint for {bundle.type} ({bundle.id})'

    return problem
  except ValueError as error:
    logging.error(error)
    raise ItemGenerationError("Bundle min and/or max larger than bundle amount provided", error.args[0])