use anyhow::{bail, Result};
use std::process::Command;

use crate::git::cli::GitCli;

impl GitCli {
    pub fn stash_list(&self, repo_path: &str) -> Result<Vec<crate::app::state::StashEntry>> {
        let output = Command::new("git")
            .args([
                "-C", repo_path,
                "stash", "list",
                "--format=%gd|%h|%gs|%cr"
            ])
            .output()?;
        if !output.status.success() {
            bail!(
                "git stash list failed: {}",
                String::from_utf8_lossy(&output.stderr)
            );
        }

        let text = String::from_utf8_lossy(&output.stdout);
        let mut stashes = Vec::new();
        for line in text.lines() {
            let parts: Vec<&str> = line.splitn(4, '|').collect();
            if parts.len() == 4 {
                stashes.push(crate::app::state::StashEntry {
                    name: parts[0].to_string(),
                    message: parts[2].to_string(),
                });
            }
        }
        Ok(stashes)
    }

    pub fn stash_apply(&self, repo_path: &str, selector: &str, drop: bool) -> Result<()> {
        let output = if drop {
            Command::new("git")
                .args(["-C", repo_path, "stash", "pop", selector])
                .output()?
        } else {
            Command::new("git")
                .args(["-C", repo_path, "stash", "apply", selector])
                .output()?
        };
        if !output.status.success() {
            bail!(
                "git stash apply/pop failed: {}",
                String::from_utf8_lossy(&output.stderr)
            );
        }
        Ok(())
    }

    pub fn stash_push(&self, repo_path: &str, message: &str) -> Result<()> {
        let output = if message.is_empty() {
            // When message is empty, use stash push without -m flag
            Command::new("git")
                .args(["-C", repo_path, "stash", "push"])
                .output()?
        } else {
            Command::new("git")
                .args(["-C", repo_path, "stash", "push", "-m", message])
                .output()?
        };
        if !output.status.success() {
            let stderr = String::from_utf8_lossy(&output.stderr);
            // Check for common error: no changes to stash
            if stderr.contains("No local changes to save") {
                bail!("No local changes to save");
            }
            bail!(
                "git stash push failed: {}",
                stderr
            );
        }
        Ok(())
    }

    pub fn stash_drop(&self, repo_path: &str, selector: &str) -> Result<()> {
        let output = Command::new("git")
            .args(["-C", repo_path, "stash", "drop", selector])
            .output()?;
        if !output.status.success() {
            bail!(
                "git stash drop failed: {}",
                String::from_utf8_lossy(&output.stderr)
            );
        }
        Ok(())
    }

}
