def METHOD_NAME(courses: list[Course], user: User, start: Tuple[int, int], end: Tuple[int, int], uoc_max: list[int]) -> list[Tuple[str, Tuple[int, int]]]:
    """
    given a list of courses, we will fill our terms in a valid ordering.
    we will enforce that:
        - the course must be offered in that term
        - duplicate courses (usually only multiterm courses) must be taken consecutively
        - the UOC max for each term is adhered to (no overloading, and the user should be allowed to manipulate this)
        - the prerequisites are respected.
    """
    # TODO: add a way to lock in courses
    model = cp_model.CpModel()
    # 1. enforces terms
    variables = [model.NewIntVarFromDomain(cp_model.Domain.FromIntervals(course.term_domain(start, end)), course.name) for course in courses]
    # 2. if any courses are named the same, then they must be taken consecutively
    possible_course_dupes = [course.name for course in courses if not course.locked]
    duplicate_courses = set(c for c in possible_course_dupes if possible_course_dupes.count(c) > 1)
    for dupe in duplicate_courses:
        matched_courses = [variable for variable in variables if variable.Name() == dupe]
        for match, next_match in zip(matched_courses, matched_courses[1:]):
            model.Add(match + 1 == next_match)
    # 3. set max UOC for a term
    for index, m in enumerate(uoc_max):
        boolean_indexes = []
        for v in variables:
            # b is a 'channeling constraint'. This is done to fill the resovoir only *if* the course is in that given term
            # https://developers.google.com/optimization/cp/channeling
            b = model.NewBoolVar('hi')
            model.Add(v == index).OnlyEnforceIf(b)
            model.Add(v != index).OnlyEnforceIf(b.Not())
            boolean_indexes.append(b)
        # if the course is in term 'index', only allow 0 to m UOC to exist in that term. 
        model.AddReservoirConstraintWithActive(
            variables,
            list(map_var_to_course(courses, var).uoc for var in variables), # this fills the resovoir by UoC units if active
            boolean_indexes, # a course is only active if in term 'index'
            0,
            m # uoc_max
        )
    # 4. enforce prereqs, only if not locked by user
    for course in courses:
        if course.locked:
            continue
        # this is the responsibility of the condition class to generate prereq model.
        course.condition.condition_to_model(
            model,
            user,
            list((variable, map_var_to_course(courses, variable)) for variable in variables),
            map_course_to_var(course, variables)
        )
    solver = cp_model.CpSolver()
    status: int = solver.Solve(model)
    if status == 3 or status == 1:
        raise Exception(f'your courses are impossible to put in these terms! Error code: {status}')
    else:
        return [(v.Name(), convert_to_term_year(solver.Value(v), start)) for v in variables]