supgit 0.2.0

A simple Git CLI wrapper for common Git operations
use anyhow::Result;
use dialoguer::{MultiSelect, Select};

use crate::git::run_git_silent;
use crate::status::{
    get_all_uncommitted_files, get_porcelain_lines, get_repo_root, get_staged_files,
    get_unstaged_files, get_untracked_files,
};

pub fn run_reset(
    all: bool,
    staged: bool,
    unstaged: bool,
    tracked: bool,
    untracked: bool,
) -> Result<()> {
    let is_interactive = !all && !staged && !unstaged && !tracked && !untracked;

    if is_interactive {
        let selection = Select::new()
            .with_prompt("What would you like to reset?")
            .items(&[
                "All files",
                "Staged files only",
                "Unstaged changes only",
                "Tracked files only",
                "Untracked files only",
                "Custom files",
            ])
            .default(0)
            .interact()?;

        match selection {
            0 => reset_all()?,
            1 => reset_staged()?,
            2 => reset_unstaged()?,
            3 => reset_tracked()?,
            4 => reset_untracked()?,
            5 => reset_custom()?,
            _ => {}
        }
    } else if all {
        reset_all()?;
    } else if staged {
        reset_staged()?;
    } else if unstaged {
        reset_unstaged()?;
    } else if tracked {
        reset_tracked()?;
    } else if untracked {
        reset_untracked()?;
    }

    Ok(())
}

fn reset_all() -> Result<()> {
    run_git_silent(&["reset", "--hard"])?;
    run_git_silent(&["clean", "-fd"])?;
    println!("✓ All files reset.");
    Ok(())
}

fn reset_staged() -> Result<()> {
    let files = get_staged_files()?;
    if files.is_empty() {
        println!("No staged files to reset.");
        return Ok(());
    }
    run_git_silent(&["restore", "--staged", "."])?;
    println!("✓ Staged files reset.");
    Ok(())
}

fn reset_unstaged() -> Result<()> {
    let files = get_unstaged_files()?;
    if files.is_empty() {
        println!("No unstaged changes to reset.");
        return Ok(());
    }
    run_git_silent(&["restore", "."])?;
    println!("✓ Unstaged changes reset.");
    Ok(())
}

fn reset_tracked() -> Result<()> {
    run_git_silent(&["reset", "--hard"])?;
    println!("✓ Tracked files reset.");
    Ok(())
}

fn reset_untracked() -> Result<()> {
    let files = get_untracked_files()?;
    if files.is_empty() {
        println!("No untracked files to reset.");
        return Ok(());
    }
    run_git_silent(&["clean", "-fd"])?;
    println!("✓ Untracked files removed.");
    Ok(())
}

fn reset_custom() -> Result<()> {
    let files = get_all_uncommitted_files()?;
    if files.is_empty() {
        println!("No files to reset.");
        return Ok(());
    }

    let selected = MultiSelect::new()
        .with_prompt("Select files to reset")
        .items(&files)
        .interact()?;

    if selected.is_empty() {
        println!("No files selected.");
        return Ok(());
    }

    let repo_root = get_repo_root()?;
    for idx in selected {
        let file = &files[idx];
        let entries = get_porcelain_lines()?;
        let status = entries
            .iter()
            .find(|(_, p)| p == file)
            .map(|(s, _)| s.clone())
            .unwrap_or_default();
        let xy: Vec<char> = status.chars().collect();
        let x = xy.first().copied().unwrap_or(' ');
        let y = xy.get(1).copied().unwrap_or(' ');

        if x == '?' && y == '?' {
            crate::git::run_git_in_dir_silent(&["clean", "-f", file], &repo_root)?;
        } else {
            if x != ' ' {
                crate::git::run_git_in_dir_silent(&["restore", "--staged", file], &repo_root)?;
            }
            if y != ' ' && y != '?' {
                crate::git::run_git_in_dir_silent(&["restore", file], &repo_root)?;
            }
        }
    }

    println!("✓ Selected files reset.");
    Ok(())
}