// @flow

import groupBy from 'lodash/groupBy'
import flatten from 'lodash/flatten'
import sortBy from 'lodash/sortBy'

import {type AreaOfStudyType} from './types'

function convertRevisionToYear(rev) {
	// The +1 is because the year is the beginning of the academic year, but
	// the graduation is the end.
	return Number((rev || '').split('-')[0]) + 1
}

// Matricated in: 2014
// Graduates in:  2018

// Physics (2011-12)
// Physics (2015-16)

// If there's only one Physics major, then anyone can see and choose it.
// Otherwise, if there are more than one, then the list gets culled.

// The newest revision of a major is always available, unless the 'available
// through' key is set.

// You can only enroll in a major if there isn't a newer one, unless your
// class year is between the previous one and the newest.

export function filterAreaList(
	areas: Array<AreaOfStudyType>,
	{graduation}: {graduation: number},
): Array<AreaOfStudyType> {
	// Remove all areas that are closed to new class years.
	let onlyAvailableAreas = areas.filter(
		area =>
			!(
				area['available through'] &&
				area['available through'] <= graduation
			),
	)

	// Group them together to filter them down
	const groupedAreas = groupBy(
		onlyAvailableAreas,
		area => `(${area.name}, ${area.type})`,
	)

	onlyAvailableAreas = Object.values(groupedAreas).map((areaSet: any) => {
		if (!Array.isArray(areaSet)) {
			return []
		}

		;(areaSet: Array<AreaOfStudyType>)

		// The newest revision of a major is always available, unless the
		// 'available through' key is set. (We took care of that up above.)
		if (areaSet.length === 1) {
			return areaSet
		}

		// You can only enroll in a major if there isn't a newer one, unless
		// your class year is between the prior revision and the newest revision.

		// We'll start out by sorting them.
		areaSet = sortBy(areaSet, (a: AreaOfStudyType) => a.revision)

		// Now for the filtering.
		return areaSet.filter((area: AreaOfStudyType, i, list) => {
			// Get the year for this area.
			let revision = convertRevisionToYear(area.revision)

			// If we're not at the end of the list,
			if (i < areaSet.length - 1) {
				// grab the next revision, and see if the graduation year
				// falls between the two revisions.
				// if it does, then this revision is *available*.
				let nextAreaRevision = convertRevisionToYear(
					list[i + 1].revision,
				)
				return revision <= graduation && graduation <= nextAreaRevision
			} else {
				// the last revision is always available
				return revision <= graduation
			}
		})
	})

	return flatten(onlyAvailableAreas)
}

@@ -111,16 +111,90 @@
 /sortBy'
+%0Aimport values from 'lodash/values'%0Aimport findLast from 'lodash/findLast'
 %0A%0Aimport
@@ -962,41 +962,32 @@
 %3E,%0A%09
-%7Bgraduation%7D: %7Bgraduation
+availableThrough
 : number
 %7D,%0A)
@@ -986,14 +986,22 @@
 mber
-%7D
 ,%0A): 
+$ReadOnly
 Arra
@@ -1132,22 +1132,16 @@
  =%3E%0A%09%09%09!
-(%0A%09%09%09%09
 area%5B'av
@@ -1162,12 +1162,11 @@
 h'%5D 
-&&%0A%09
+%7C%7C%0A
 %09%09%09a
@@ -1194,26 +1194,26 @@
 h'%5D 
-%3C= graduation%0A%09%09%09)
+%3E availableThrough
 ,%0A%09)
@@ -1263,12 +1263,10 @@
 wn%0A%09
-cons
+le
 t gr
@@ -1320,17 +1320,16 @@
 rea =%3E %60
-(
 $%7Barea.n
@@ -1332,18 +1332,17 @@
 ea.name%7D
-, 
+%7C
 $%7Barea.t
@@ -1349,17 +1349,16 @@
 ype%7D
-)
 %60,%0A%09)%0A%0A%09
 only
@@ -1357,36 +1357,23 @@
 )%0A%0A%09
-onlyAvailableAreas = Object.
+let filtered = 
 valu
@@ -1397,117 +1397,21 @@
 map(
-(
 areaSet
-: any)
  =%3E %7B%0A
-%09%09if (!Array.isArray(areaSet)) %7B%0A%09%09%09return %5B%5D%0A%09%09%7D%0A%0A%09%09;(areaSet: Array%3CAreaOfStudyType%3E)%0A%0A
 %09%09//
@@ -1725,32 +1725,37 @@
 n and the newest
+%0A%09%09//
  revision.%0A%0A%09%09//
@@ -1820,32 +1820,19 @@
 et, 
-(a: AreaOfStudyType)
+area
  =%3E 
+are
 a.re
@@ -1846,435 +1846,71 @@
 %0A%0A%09%09
-// Now for the filtering.%0A%09%09return areaSet.filter((area: AreaOfStudyType, i, list) =%3E %7B%0A%09%09%09// Get the year for this area.%0A%09%09%09let revision = convertRevisionToYear(area.revision)%0A%0A%09%09%09// If we're not at the end of the list,%0A%09%09%09if (i %3C areaSet.length - 1) %7B%0A%09%09%09%09// grab the next revision, and see if the graduation year%0A%09%09%09%09// falls between the two revisions.%0A%09%09%09%09// if it does, then this revision is *available*.%0A%09%09%09%09let nextAreaR
+let newestApplicableArea = findLast(areaSet, area =%3E %7B%0A%09%09%09let r
 evis
@@ -1941,25 +1941,12 @@
 ear(
-%0A%09%09%09%09%09list%5Bi + 1%5D
+area
 .rev
@@ -1954,17 +1954,10 @@
 sion
-,%0A%09%09%09%09
 )%0A
-%09
 %09%09%09r
@@ -1978,153 +1978,66 @@
  %3C= 
-graduation && graduation %3C= nextAreaRevision%0A%09%09%09%7D else %7B%0A%09%09%09%09// the last revision is always available%0A%09%09%09%09return revision %3C= graduation%0A%09%09%09%7D%0A%09%09%7D)
+availableThrough%0A%09%09%7D)%0A%0A%09%09return newestApplicableArea %7C%7C %5B%5D
 %0A%09%7D)
@@ -2054,30 +2054,20 @@
 flatten(
-onlyAvailableAreas
+filtered
 )%0A%7D%0A

refactor filterAreaList