use chrono::{Datelike, Duration, NaiveDate, Utc};
use indicatif::{ProgressBar, ProgressStyle};
use serde::{Deserialize, Serialize};
use serde_json::{json, Value};
use std::collections::HashMap;
use std::fs::{self, File};
use std::io::{Read, Write};
use std::path::Path;

// Example API response type
#[derive(Debug, Serialize, Deserialize, Clone)]
struct HistoryItem {
    checkpoint: Option<String>,
    datetime: String,
    sha256: Option<String>,
    filename: Option<String>,
    hostname: Option<String>,
    // other fields...
}

// JSON file structure
#[derive(Debug, Serialize, Deserialize)]
struct JsonFile {
    error: String,
    response: ResponseData,
}

#[derive(Debug, Serialize, Deserialize)]
struct ResponseData {
    exechistories: Vec<HistoryItem>,
}

// Mock API function
fn history_logging(_type: &str, checkpoint: &str, _policy: &[&str]) -> Vec<HistoryItem> {
    // Replace with actual API call
    vec![]
}

fn main() {
    let file_path = Path::new("data/example.json");
    let mut checkpoint = "initial_checkpoint".to_string();
    let policy_name = "policy1".to_string();
    let days = 7;

    // Initialize JSON output
    let mut json_output = JsonFile {
        error: "Success".to_string(),
        response: ResponseData {
            exechistories: vec![],
        },
    };

    // Outer progress bar (filebar)
    let filebar = ProgressBar::new(10_000);
    filebar.set_style(
        ProgressStyle::default_bar()
            .template("Checkpoint Progress: {msg} [{bar:40.cyan/blue}] {pos}/{len}")
            .unwrap(),
    );
    filebar.set_message(&checkpoint);

    // Inner progress bar (total progress)
    let pbar = ProgressBar::new(100);
    pbar.set_style(
        ProgressStyle::default_bar()
            .template("Total of {msg} Complete: [{bar:40.cyan/blue}] {pos}/{len}")
            .unwrap(),
    );
    pbar.set_message(&policy_name);

    loop {
        let histories = history_logging("type", &checkpoint, &[&policy_name]);

        if !histories.iter().all(|h| h.datetime.len() > 0) {
            eprintln!("Unexpected response format from API.");
            break;
        }

        filebar.set_length(histories.len() as u64);

        if histories.is_empty() {
            break;
        }

        for (index, history_item) in histories.iter().enumerate() {
            if history_item.checkpoint.is_none() || history_item.datetime.is_empty() {
                continue;
            }

            if index == histories.len() - 1 {
                checkpoint = history_item.checkpoint.clone().unwrap();
                filebar.set_message(&checkpoint);
                break;
            }

            // Parse date
            let history_date = match NaiveDate::parse_from_str(
                &history_item.datetime.replace(" +0000 UTC", ""),
                "%Y-%m-%dT%H:%M:%SZ",
            ) {
                Ok(date) => date,
                Err(_) => continue,
            };

            let cutoff = Utc::today().naive_utc() - Duration::days(days);
            if history_date >= cutoff {
                json_output.response.exechistories.push(history_item.clone());
            }

            filebar.inc(1);
            filebar.tick();
        }

        // Deduplicate
        let mut seen: HashMap<(Option<String>, Option<String>, Option<String>), HistoryItem> =
            HashMap::new();

        let combined = if file_path.exists() {
            let mut f = File::open(file_path).unwrap();
            let mut contents = String::new();
            f.read_to_string(&mut contents).unwrap();
            let existing_data: JsonFile = serde_json::from_str(&contents).unwrap_or(JsonFile {
                error: "Success".to_string(),
                response: ResponseData {
                    exechistories: vec![],
                },
            });
            [existing_data.response.exechistories, json_output.response.exechistories.clone()]
                .concat()
        } else {
            json_output.response.exechistories.clone()
        };

        for entry in combined {
            let key = (entry.sha256.clone(), entry.filename.clone(), entry.hostname.clone());
            seen.insert(key, entry);
        }

        let deduplicated: Vec<HistoryItem> = seen.into_values().collect();

        // Write to file
        let output_file = File::create(file_path).unwrap();
        serde_json::to_writer_pretty(&output_file, &json!({
            "error": "Success",
            "response": { "exechistories": deduplicated }
        }))
        .unwrap();

        json_output.response.exechistories.clear();

        // Update inner progress bar (percentage based on last valid item)
        if let Some(last_item) = histories.last() {
            if let Ok(last_date) = NaiveDate::parse_from_str(
                &last_item.datetime.replace(" +0000 UTC", ""),
                "%Y-%m-%dT%H:%M:%SZ",
            ) {
                let date_diff = Utc::today().naive_utc() - last_date;
                let percentage_diff = ((days + 10) - date_diff.num_days()) as f64 / (days + 10) as f64 * 100.0;
                pbar.set_position(percentage_diff.round() as u64);
                pbar.set_message(&policy_name);
                pbar.tick();
            }
        }

        filebar.set_position(1);
    }

    filebar.finish();
    pbar.finish();
}
