use crate::dictionary::app_data_dir;
use crate::lang::{Id, WordOpenMode};
use chrono::{DateTime, Utc};
use std::fs;
use std::fs::{File, OpenOptions};
use std::io::Write;
use std::io::{BufRead, BufReader};
use std::path::PathBuf;

pub fn get_history_of_set(id: Id) -> Vec<HistoryItem> {
    let app_dir = history_dir();
    let head = app_dir.clone().join(format!("set_{}_history.csv", id));
    let mut lines = Vec::new();

    append_lines_if_exists(head, &mut lines);
    lines.reverse();
    parse_history_items(lines)
}

fn append_lines_if_exists(path: PathBuf, lines: &mut Vec<String>) {
    if path.exists() {
        let reader = BufReader::new(File::open(path).unwrap());
        for line in reader.lines() {
            lines.push(line.unwrap());
        }
    }
}

fn parse_history_items(strings: Vec<String>) -> Vec<HistoryItem> {
    let mut items = Vec::with_capacity(strings.len());
    for string in strings {
        if let [time, word, mode, before, after] = string.split(';').collect::<Vec<&str>>()[..] {
            let id = word.parse::<Id>();
            if id.is_err() {
                continue;
            }
            let id = id.unwrap();
            if !id.is_valid() {
                continue;
            }
            items.push(HistoryItem {
                timestamp: DateTime::from_timestamp(time.parse().unwrap_or_default(), 0).unwrap(),
                word_id: id,
                mode: match mode.parse::<u8>().unwrap_or_default() {
                    2 => WordOpenMode::Hard,
                    3 => WordOpenMode::Ok,
                    4 => WordOpenMode::Easy,
                    _ => WordOpenMode::None,
                },
                before: before.parse().unwrap_or_default(),
                after: after.parse().unwrap_or_default(),
            });
        }
    }

    items
}

pub fn push_note(set_id: Id, item: HistoryItem) {
    let app_dir = history_dir();
    let path = app_dir.clone().join(format!("set_{}_history.csv", set_id));

    let mut file = OpenOptions::new()
        .create(true)
        .append(true)
        .open(path)
        .unwrap();
    let line_str = format!(
        "{};{};{};{};{}",
        item.timestamp.timestamp(),
        item.word_id,
        match item.mode {
            WordOpenMode::Easy => 4,
            WordOpenMode::Ok => 3,
            WordOpenMode::Hard => 2,
            WordOpenMode::None => 1,
        },
        item.before,
        item.after
    );
    writeln!(&mut file, "{}", line_str).unwrap();
}

pub fn history_dir() -> PathBuf {
    let directory = app_data_dir().join("history");
    if !directory.exists() {
        fs::create_dir(directory.clone()).unwrap();
    }
    directory
}

#[derive(Clone)]
pub struct HistoryItem {
    pub timestamp: DateTime<Utc>,
    pub word_id: Id,
    pub mode: WordOpenMode,
    pub before: u8,
    pub after: u8,
}
