use std::collections::HashSet;

fn binary_search<T: std::cmp::PartialOrd>(
    min_i: usize,
    max_i: usize,
    xs: &Vec<T>,
    needle: T,
) -> usize {
    if min_i >= max_i {
        return max_i;
    }
    let half_i = min_i + (max_i - min_i) / 2;

    if xs[half_i] == needle {
        return half_i;
    }

    if needle < xs[half_i] {
        binary_search(min_i, half_i - 1, &xs, needle)
    } else {
        binary_search(half_i + 1, max_i, xs, needle)
    }
}

pub fn find_two_sums(xs: &mut Vec<i64>) -> usize {
    let mut found: HashSet<i64> = HashSet::new();
    const T_MIN: i64 = -10000;
    const T_MAX: i64 = 10000;
    xs.sort();

    for i in 0..xs.len() {
        let a: i64 = xs[i];
        let b_min = T_MIN - a;
        let b_max = T_MAX - a;
        let i_min = binary_search(i + 1, xs.len() - 1, &xs, b_min);
        let i_max = binary_search(i + 1, xs.len() - 1, &xs, b_max);

        for i in i_min..(i_max + 1) {
            let b = xs[i];
            let t = a + b;
            if T_MIN <= t && t <= T_MAX {
                found.insert(t);
            }
        }
    }
    found.len()
}

// fn two_sum(t: i64, xs: &Vec<i64>, ys: &HashSet<i64>) -> bool {
// 	for &x in xs {
// 		let y = t - x;
// 		if x != y && ys.contains(&y) {
// 			return true;
// 		}
// 	}
// 	false
// }

// pub fn find_two_sums_naiv(xs: Vec<i64>) -> usize {
// 	let mut xs_min: Vec<i64> = xs.to_vec();
// 	xs_min.retain(|&i| i < 0);

// 	let mut xs_max: Vec<i64> = xs.to_vec();
// 	xs_max.retain(|&i| i >= 0);
// 	let xs_max_set: HashSet<i64> = HashSet::from_iter(xs_max);

// 	let mut r: usize = 0;
// 	for t in -10000..10001 {
// 		if t % 10 == 0 {
// 			println!("{:?}", t);
// 		}
// 		if two_sum(t, &xs_min, &xs_max_set) {
// 			r += 1
// 		}
// 	}
// 	r
// }
