//! Pacman package manager operations

use std::process::{Command, Stdio};
use std::io::Read;

use crate::error::{ArcError, Result};
use crate::progress::{ProgressCallback, ProgressState};

/// Search for packages using pacman
pub fn search(query: &str) -> Result<Vec<String>> {
    let output = Command::new("pacman")
        .arg("-Ss")
        .arg(query)
        .output()?;

    if !output.status.success() {
        return Ok(Vec::new());
    }

    let stdout = String::from_utf8_lossy(&output.stdout);
    let query_lower = query.to_lowercase();
    
    let packages: Vec<String> = stdout
        .lines()
        .filter(|line| !line.starts_with(' ')) // Skip description lines
        .filter_map(|line| {
            // Format: "repo/package version [installed]"
            let parts: Vec<&str> = line.split_whitespace().collect();
            if let Some(first) = parts.first() {
                if let Some(pkg) = first.split('/').nth(1) {
                    // Only return packages where the package name contains the query
                    if pkg.to_lowercase().contains(&query_lower) {
                        return Some(pkg.to_string());
                    }
                }
            }
            None
        })
        .collect();

    Ok(packages)
}

/// Install a package using pacman with progress callback
pub fn install_with_progress(
    package: &str,
    progress: &dyn ProgressCallback,
) -> Result<()> {
    progress.update(ProgressState::Preparing);
    
    let status = Command::new("pacman")
        .arg("-S")
        .arg("--noconfirm")
        .arg("--needed")
        .arg(package)
        .arg("--overwrite='*'")
        .output()?
        .status;

    if !status.success() {
        progress.update(ProgressState::Failed(format!(
            "Failed to install pacman package: {}",
            package
        )));
        return Err(ArcError::CommandFailed(format!(
            "Failed to install pacman package: {}",
            package
        )));
    }

    progress.update(ProgressState::Completed);
    Ok(())
}

/// Install a package using pacman
pub fn install(package: &str) -> Result<()> {
    let status = Command::new("pacman")
        .arg("-S")
        .arg("--noconfirm")
        .arg("--needed")
        .arg(package)
        .arg("--overwrite='*'")
        .status()?;

    if !status.success() {
        return Err(ArcError::CommandFailed(format!(
            "Failed to install pacman package: {}",
            package
        )));
    }

    Ok(())
}

/// Uninstall a package using pacman with progress callback
pub fn uninstall_with_progress(
    package: &str,
    progress: &dyn ProgressCallback,
) -> Result<()> {
    progress.update(ProgressState::Preparing);
    
    let status = Command::new("pacman")
        .arg("-R")
        .arg("--noconfirm")
        .arg(package)
        .output()?
        .status;

    if !status.success() {
        progress.update(ProgressState::Failed(format!(
            "Failed to uninstall pacman package: {}",
            package
        )));
        return Err(ArcError::CommandFailed(format!(
            "Failed to uninstall pacman package: {}",
            package
        )));
    }

    progress.update(ProgressState::Completed);
    Ok(())
}

/// Uninstall a package using pacman
pub fn uninstall(package: &str) -> Result<()> {
    let status = Command::new("pacman")
        .arg("-R")
        .arg("--noconfirm")
        .arg(package)
        .status()?;

    if !status.success() {
        return Err(ArcError::CommandFailed(format!(
            "Failed to uninstall pacman package: {}",
            package
        )));
    }

    Ok(())
}

/// Check if a package is installed
pub fn is_installed(package: &str) -> Result<bool> {
    let output = Command::new("pacman")
        .arg("-Qi")
        .arg(package)
        .output()?;

    Ok(output.status.success())
}

/// List all installed packages
pub fn list_installed() -> Result<Vec<String>> {
    let output = Command::new("pacman")
        .arg("-Q")
        .output()?;

    if !output.status.success() {
        return Err(ArcError::CommandFailed(
            "Failed to list installed pacman packages".to_string(),
        ));
    }

    let stdout = String::from_utf8_lossy(&output.stdout);
    let packages: Vec<String> = stdout
        .lines()
        .filter_map(|line| {
            let parts: Vec<&str> = line.split_whitespace().collect();
            parts.first().map(|s| s.to_string())
        })
        .collect();

    Ok(packages)
}

/// Install a package using pacman (silent, output captured)
pub fn install_silent(package: &str) -> Result<(bool, String)> {
    let mut child = Command::new("pacman")
        .arg("-S")
        .arg("--noconfirm")
        .arg("--needed")
        .arg(package)
        .arg("--overwrite='*'")
        .stdout(Stdio::piped())
        .stderr(Stdio::piped())
        .spawn()?;

    let mut stdout = String::new();
    let mut stderr = String::new();

    if let Some(mut out) = child.stdout.take() {
        let _ = out.read_to_string(&mut stdout);
    }
    if let Some(mut err) = child.stderr.take() {
        let _ = err.read_to_string(&mut stderr);
    }

    let status = child.wait()?;
    let output = format!("{}{}", stdout, stderr);

    Ok((status.success(), output))
}

/// Uninstall a package using pacman (silent, output captured)
pub fn uninstall_silent(package: &str) -> Result<(bool, String)> {
    let mut child = Command::new("pacman")
        .arg("-R")
        .arg("--noconfirm")
        .arg(package)
        .stdout(Stdio::piped())
        .stderr(Stdio::piped())
        .spawn()?;

    let mut stdout = String::new();
    let mut stderr = String::new();

    if let Some(mut out) = child.stdout.take() {
        let _ = out.read_to_string(&mut stdout);
    }
    if let Some(mut err) = child.stderr.take() {
        let _ = err.read_to_string(&mut stderr);
    }

    let status = child.wait()?;
    let output = format!("{}{}", stdout, stderr);

    Ok((status.success(), output))
}
