from typing import List
from typing import Dict


def fallback_valid(people_before: List, people_after: List,
                   config: Dict) -> List[bool]:
    """Verifies that fallback cohorts are assigned correctly, if applicable.

    If there is only one cohort in the configuration, the only two cohorts in
    the output should be that cohort and `None`. A person should be in the
    `None` cohort iff their schedule does not allow them to be scheduled within
    their original cohort's bounds.

    If there are two cohorts (1x/2x) in the configuration, then people in the
    2x cohort should be assigned to the 1x cohort iff they are compatible with
    1x but not 2x. People compatible with neither should be assigned to `None`.

    It is difficult to check that there are _no_ schedules for a particular
    cohort that a person is compatible with without calling a myriad of
    internal functions, so instead simply we check for ordering: a person
    in 1x can only be moved to `None`, and a person in 2x can be moved
    to either 1x or `None`.

    Args:
        people_before: A roster of unscheduled people.
        people_after: The same roster of people with assigned schedules.
            (Order not required to match `people_before`.)
        config: A campus-level configuration.

    Returns:
        A list of booleans indicating whether each person (in the order
        of `people_before`) has a properly assigned cohort.
    """
    people_after_by_id = {p['id']: p for p in people_after}
    valid = []
    cohorts = config['policy']['cohorts']
    full_hierarchy = ['2x', '1x']
    hierarchy = [h for h in full_hierarchy if h in cohorts] + [None]
    for person_before in people_before:
        coh_before = person_before['cohort']
        person_after = people_after_by_id[person_before['id']]
        coh_after = person_after['cohort']
        valid.append(hierarchy.index(coh_after) >= hierarchy.index(coh_before))
    return valid