import csv
import io
import re
from tokenize import String
from typing import Tuple

from helpers import common_helper
from models.item import Item
from models.solver_run import SolverRun

def csv_to_item(items_csv_reader, solver_run):
    items = []
    headers = []

    # get headers and items
    for key, row in enumerate(items_csv_reader):
        if key == 0:
            headers = row
        else:
            item = {'attributes': []}

            # ensure that the b param is formatted correctly
            if row[len(headers) - 1] != '' and common_helper.is_float(row[len(headers) - 1]):
                for key, col in enumerate(headers):
                    if solver_run.irt_model.formatted_b_param() == col:
                        value = float(row[key])
                        item['b_param'] = value
                    elif solver_run.get_constraint(
                            col) and solver_run.get_constraint(
                                col).reference_attribute.type == 'bundle':
                        if row[key]:
                            item[solver_run.get_constraint(
                                col).reference_attribute.id] = row[key]
                    elif solver_run.get_constraint(col):
                        constraint = solver_run.get_constraint(col)
                        item['attributes'].append({
                            'id':
                            col,
                            'value':
                            row[key],
                            'type':
                            constraint.reference_attribute.type
                        })
                    else:
                        if row[key]:
                            item[col] = row[key]

                # confirm item is only added if it meets the criteria of 100% constraints as a pre-filter
                valid_item = True
                item = Item.parse_obj(item)
                for constraint in solver_run.constraints:
                    if item.attribute_exists(constraint.reference_attribute) == False and constraint.minimum == 100:
                        valid_item = False

                if valid_item: items.append(item)

    return items


def solution_to_file(buffer, total_form_items, forms):
    wr = csv.writer(buffer, dialect='excel', delimiter=',')

    # write header row for first row utilizing the total items all forms will have
    # fill the rows with the targets and cut score then the items
    header = ['status']

    for result in forms[0].tif_results:
        header += [f'tif @ {round(result.theta, 2)}']

    for result in forms[0].tcc_results:
        header += [f'tcc @ {round(result.theta, 2)}']

    header += ['cut score'] + [x + 1 for x in range(total_form_items)]
    wr.writerow(header)

    # add each form as row to processed csv
    for form in forms:
        row = [form.status]

        for result in form.tif_results + form.tcc_results:
            row += [
                f'target - {result.value}\nresult - {round(result.result, 2)}'
            ]

        # provide generated items and cut score
        row += [round(form.cut_score, 2)] + [item.id for item in form.items]
        wr.writerow(row)

    buff2 = io.BytesIO(buffer.getvalue().encode())

    return buff2


def error_to_file(buffer, error):
    wr = csv.writer(buffer, dialect='excel', delimiter=',')
    wr.writerow(['status'])
    wr.writerow([error.args[0]])

    return io.BytesIO(buffer.getvalue().encode())


def key_to_uuid(key):
    return re.split("_", key)[0]


def solution_items(variables: list, solver_run: SolverRun) -> Tuple[list]:
    form_items = []
    form_bundles = []
    final_items = []
    solver_variables = []

    for v in variables:
        if v.varValue > 0:
            solver_variables.append(v.name)

            if 'Item_' in v.name:
                item_id = v.name.replace('Item_', '')
                item = solver_run.get_item(int(item_id))
                # add item to list and then remove from master item list
                if item: form_items.append(item)
            elif 'Bundle_' in v.name:
                bundle_id = v.name.replace('Bundle_', '')
                bundle = solver_run.get_bundle(int(bundle_id))

                if bundle: form_bundles.append(bundle)

    for bundle in form_bundles:
        items = bundle.ordered_items(
        ) if solver_run.bundle_first_ordering else bundle.items
        for item in items:
            final_items.append(item)

    for item in form_items:
        final_items.append(item)

    return final_items, solver_variables

def print_problem_variables(problem):
    # Uncomment this as needed in local dev
    # print(problem);
    for v in problem.variables(): print(v.name, "=", v.varValue)