use std::io::{Error, ErrorKind};
use std::{collections::HashMap, fs::read_to_string};

fn main() {
    // Read the input file
    let input = read_to_string("input_day_1.txt")
        .expect("Failed to read the input file.");
    dbg!(aoc_part_1(input.clone()));
    dbg!(aoc_part_2(input));
}

#[cfg(test)]
mod tests {
    use crate::aoc_part_1;
    use crate::aoc_part_2;

    #[test]
    fn test_aoc_1_part_1() {
        assert_eq!(
            142,
            aoc_part_1(
                r#"
1abc2
pqr3stu8vwx
a1b2c3d4e5f
treb7uchet
"#
                .to_string()
            )
        );
    }
    #[test]
    fn test_aoc_1_part_2() {
        assert_eq!(
            281,
            aoc_part_2(
                r#"
two1nine
eightwothree
abcone2threexyz
xtwone3four
4nineeightseven2
zoneight234
7pqrstsixteen
"#
                .to_string()
            )
        );
    }
}

fn aoc_part_2(input: String) -> u32 {
    // Make an interator over the lines
    let lines = input.lines();

    // Start value is zero
    let mut value = 0;

    // Iterate over the lines
    for line in lines {
        // The number in the current line
        let mut number = String::new();
        // Find the first written number
        let mut firstnumber = String::new();
        // Find the last written number
        let mut lastnumber = String::new();

        'firstnumberloop: for character in line.chars() {
            // Check if a character is a number.
            // If it is a number, then push the number to `number`-string and break out of the loop
            if character.is_numeric() {
                number.push(character);
                break 'firstnumberloop;
            }
            // If there was not a number found yet, push the current character being checked to `firstnumber`-string.
            firstnumber.push(character);

            // Check if the `firstnumber`-string is a valid string
            match match_alphabetic_number(firstnumber.clone()) {
                Ok(val) => {
                    number = val.to_string();
                    break 'firstnumberloop;
                }
                Err(_) => {
                    continue 'firstnumberloop;
                }
            };
        }

        'secondnumberloop: for character in line.chars().rev() {
            // Check if a character is a number.
            // If it is a number, then push the number to `number`-string and break out of the loop
            if character.is_numeric() {
                number.push(character);
                break 'secondnumberloop;
            }
            // If there was not a number found yet, push the current character being checked to `lastnumber`-string.
            lastnumber = format!("{character}{lastnumber}");

            // Check if the `lastnumber`-string is a valid string
            match match_alphabetic_number(lastnumber.clone()) {
                Ok(val) => {
                    number = format!("{number}{val}");
                    break 'secondnumberloop;
                }
                Err(_) => {
                    continue 'secondnumberloop;
                }
            };
        }
        match number.parse::<u32>() {
            Ok(val) => value += val,
            Err(_) => {
                continue;
            }
        };
    }
    value
}

fn match_alphabetic_number(matchnumber: String) -> Result<u32, Error> {
    let hashmapofnumbers: HashMap<&str, u32> = HashMap::from([
        ("one", 1),
        ("two", 2),
        ("three", 3),
        ("four", 4),
        ("five", 5),
        ("six", 6),
        ("seven", 7),
        ("eight", 8),
        ("nine", 9),
    ]);

    for number in hashmapofnumbers {
        if matchnumber.contains(number.0) {
            return Ok(number.1);
        }
    }
    Err(Error::new(
        ErrorKind::NotFound,
        "In the current string there was no number found.",
    ))
}

#[allow(unused)]
// old quick and dirty
fn part2() {
    let input = read_to_string("input_day_1.txt").unwrap();
    let lines = input.lines();

    //one, two, three, four, five, six, seven, eight, and nine
    let mut value = 0;
    for line in lines {
        let mut number = String::new();
        let mut firstword = String::new();
        let mut secondword = String::new();
        dbg!(&line);
        'loopone: for char in line.chars() {
            if char.is_numeric() {
                number.push(char);
                break 'loopone;
            }

            firstword.push(char);
            dbg!(&firstword);

            let resultarm = matcharm(firstword.clone());

            if resultarm != '0' {
                number.push(resultarm);
                break 'loopone;
            }
        }
        println!("number {number}");
        'looptwo: for char in line.chars().rev() {
            if char.is_numeric() {
                number.push(char);
                break 'looptwo;
            }

            secondword = format!("{char}{secondword}");
            dbg!(&secondword);

            let resultarm = matcharm(secondword.clone());

            if resultarm != '0' {
                number.push(resultarm);

                break 'looptwo;
            }
        }
        println!("total number {number}");
        value += number.parse::<i32>().unwrap();
    }
    println!("value {}", value);
}

#[allow(unused)]
// old quick and dirty
fn matcharm(firstword: String) -> char {
    let answer = if firstword.contains("one") {
        '1'
    } else if firstword.contains("two") {
        '2'
    } else if firstword.contains("three") {
        '3'
    } else if firstword.contains("four") {
        '4'
    } else if firstword.contains("five") {
        '5'
    } else if firstword.contains("six") {
        '6'
    } else if firstword.contains("seven") {
        '7'
    } else if firstword.contains("eight") {
        '8'
    } else if firstword.contains("nine") {
        '9'
    } else {
        '0'
    };
    answer
}

fn aoc_part_1(input: String) -> u32 {
    let lines = input.lines();

    let mut value = 0;

    for line in lines {
        //println!("{line}");
        let mut number = String::new();
        let characters = line.chars();
        'firstloop: for char in characters.clone() {
            if char.is_numeric() {
                number.push(char);
                break 'firstloop;
            }
        }
        'secondloop: for char in characters.rev() {
            if char.is_numeric() {
                number.push(char);
                break 'secondloop;
            }
        }
        match number.parse::<u32>() {
            Ok(val) => value += val,
            Err(_) => {
                continue;
            }
        };
    }
    value
}
