use pad::PadStr;
use rand::Rng;
use std::fs::File;
use std::io::{BufRead, BufReader, Error};
use std::process;

const FILENAME: &str = "members-list.txt";

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
struct Member {
    name: String,
    emoji: String,
    membership_number: u16,
}

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
struct UserInput {
    name: String,
    membership_number: u16,
}

fn main() -> Result<(), Error> {
    let file = File::open(FILENAME)?;
    let mut structs = read_file_to_members(file)?;

    println!("{} | membership number", "name".pad_to_width(10));
    println!("-----------|------------------------");
    structs.sort_by(|a, b| b.membership_number.cmp(&a.membership_number));
    structs.reverse();
    for line in structs.iter() {
        let name_string = line.name.pad_to_width(10);
        println!("{} | {}", name_string, line.membership_number);
    }

    println!("Add member: y/n");

    let yes_no = get_string();

    if yes_no == "n" {
        process::exit(0);
    } else if yes_no == "y" {
        println!("Enter the name of the new member!");
        let input = get_string();

        let mut new_member = fetch_input_and_add_to_members(input)?;
        let stripped_structs = strip_emoji_from_members(structs);

        for stripped_struct in stripped_structs {
            new_member.push(stripped_struct);
        }

        println!("{} | membership number", "name".pad_to_width(10));
        println!("-----------|------------------------");

        new_member.sort_by(|a, b| b.membership_number.cmp(&a.membership_number));
        new_member.reverse();
        for member in new_member {
            let name_string = member.name.pad_to_width(10);
            println!("{} | {}", name_string, member.membership_number);
        }
    }

    Ok(())
}

fn read_file_to_members(file: File) -> Result<Vec<Member>, Error> {
    let buffered = BufReader::new(file);
    let mut _line_read = String::new();
    let mut member_vec = Vec::new();

    for line in buffered.lines() {
        _line_read = match line {
            Ok(line) => line,
            Err(e) => {
                return Err(e);
            }
        };

        let string_vec: Vec<&str> = _line_read.split_whitespace().collect();
        let member = Member {
            name: string_vec[0].to_string(),
            emoji: string_vec[1].to_string(),
            membership_number: string_vec[2].parse::<u16>().unwrap(),
        };

        member_vec.push(member);
    }

    Ok(member_vec)
}

fn fetch_input_and_add_to_members(user_input: String) -> Result<Vec<UserInput>, Error> {
    let mut input = Vec::new();
    let membership_number = rand::thread_rng().gen::<u16>();

    let new_member = UserInput {
        name: user_input,
        membership_number,
    };

    input.push(new_member);

    Ok(input)
}

fn strip_emoji_from_members(members: Vec<Member>) -> Vec<UserInput> {
    let mut stripped_member_vec = Vec::new();
    for member in members.iter() {
        let stripped_member = UserInput {
            name: member.name.clone(),
            membership_number: member.membership_number,
        };

        stripped_member_vec.push(stripped_member);
    }

    stripped_member_vec
}

fn get_string() -> String {
    let mut buffer = String::new();
    let stdin = std::io::stdin();

    stdin.read_line(&mut buffer).expect("BROKEN STDIN");

    let input = buffer.trim();

    input.parse().expect("Peng")
}