use std::collections::HashSet;
use std::fs::OpenOptions;
use std::io::prelude::*;
use std::io::BufReader;
use std::path::Path;

use reqwest::{Client, StatusCode};
use serde_json::{json, Value};
use tokio;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let jira_base_url = "https://jira.someserver.com";
    let username = "userName";
    let password = "passWord! @#";
    let project_key = "projectKey";

    let client = Client::new();

    // 1. Pull a project's component list
    let url = format!("{}/rest/api/2/project/{}/components", jira_base_url, project_key);
    let raw_data = client
        .get(&url)
        .basic_auth(username, Some(password))
        .send()
        .await?
        .json::<Value>()
        .await?;

    // 2. Create a mapping of component ID, component name, and the assignee name
    let component_data: Vec<Value> = raw_data
        .as_array()
        .unwrap()
        .iter()
        .map(|component| {
            json!({
                "id": component["id"],
                "name": component["name"],
                "assignee": component["assignee"]["name"]
            })
        })
        .collect();

    // 3. Show a comma-separated list of the usernames and ask which username we want to replace
    let mut usernames: HashSet<String> = HashSet::new();
    for component in &component_data {
        usernames.insert(component["assignee"].as_str().unwrap().to_string());
    }
    println!("Usernames: {}", usernames.iter().cloned().collect::<Vec<String>>().join(", "));
    let mut old_username = String::new();
    println!("Enter the username you want to replace: ");
    std::io::stdin().read_line(&mut old_username)?;
    let old_username = old_username.trim();

    // 4. Check if the entered username is in the list
    if !usernames.contains(old_username) {
        println!("Username not found in the list. Please select a name from the list.");
        return Ok(());
    }

    // 5. Ask for the new username
    let mut new_username = String::new();
    println!("Enter the new username: ");
    std::io::stdin().read_line(&mut new_username)?;
    let new_username = new_username.trim();

    // Create a folder for the source username and history.txt file
    let history_folder = Path::new(old_username);
    std::fs::create_dir_all(&history_folder)?;

    let history_file_path = history_folder.join("history.txt");
    let mut history_file = OpenOptions::new()
        .write(true)
        .append(true)
        .create(true)
        .open(&history_file_path)?;

 // 6. Create a new mapping of the IDs and new assignees we will be changing
let components_to_update: Vec<&Value> = component_data
    .iter()
    .filter(|component| component["assignee"] == old_username)
    .collect();

// 7. Push an update to the Jira Server API to update those component leads
for component in components_to_update {
    let component_id = component["id"].as_str().unwrap();
    let component_name = component["name"].as_str().unwrap();

    let url = format!("{}/rest/api/2/component/{}", jira_base_url, component_id);
    let post_data = json!({ "leadUserName": new_username });

    let res = client
        .put(&url)
        .basic_auth(username, Some(password))
        .json(&post_data)
        .send()
        .await?;

    if res.status() == StatusCode::OK {
        // Save the changed component ID and timestamp to the history file
        let timestamp = chrono::Local::now().format("%Y-%m-%d %H:%M:%S").to_string();
        let history_entry = format!(
            "Updated component {} ({}) with new assignee {} at {}\n",
            component_name, component_id, new_username, timestamp
        );
        history_file.write_all(history_entry.as_bytes())?;
    } else {
        eprintln!(
            "Failed to update component {} ({}), status code: {}",
            component_name,
            component_id,
            res.status()
        );
    }
}

Ok(())
}