use std::process::Command;

use anyhow::{bail, Context, Result};

const CLAUDE_SERVICE: &str = "Claude Code-credentials";

/// Parse the "acct" field from `security find-generic-password` stdout output.
fn extract_acct_from_security_output(output: &str) -> Option<String> {
    for line in output.lines() {
        let trimmed = line.trim();
        if trimmed.starts_with("\"acct\"") {
            if let Some(eq_pos) = trimmed.rfind('=') {
                let value = trimmed[eq_pos + 1..].trim();
                if value.starts_with('"') && value.ends_with('"') && value.len() >= 2 {
                    return Some(value[1..value.len() - 1].to_string());
                }
            }
        }
    }
    None
}

/// Get the account name Claude Code used when storing its keychain entry.
fn claude_account_name() -> String {
    if let Ok(out) = Command::new("security")
        .args(["find-generic-password", "-s", CLAUDE_SERVICE])
        .output()
    {
        let stdout = String::from_utf8_lossy(&out.stdout);
        if let Some(acct) = extract_acct_from_security_output(&stdout) {
            if !acct.is_empty() {
                return acct;
            }
        }
    }
    std::env::var("USER")
        .or_else(|_| std::env::var("LOGNAME"))
        .unwrap_or_else(|_| "user".to_string())
}

/// Read the current Claude Code credentials JSON from the macOS Keychain.
pub fn read_claude_credentials() -> Result<String> {
    let output = Command::new("security")
        .args(["find-generic-password", "-s", CLAUDE_SERVICE, "-w"])
        .output()
        .context("failed to run 'security' command — is this macOS?")?;

    if !output.status.success() {
        bail!(
            "Claude Code credentials not found in Keychain.\n\
             Make sure you are logged in to Claude Code."
        );
    }

    let password = String::from_utf8(output.stdout)
        .context("credentials contain invalid UTF-8")?;
    Ok(password.trim_end_matches('\n').to_string())
}

/// Write (replace) the Claude Code credentials in the macOS Keychain.
/// No ACL flags — preserves the existing item's ACL so macOS only prompts
/// once ("Always Allow") and is silent on every subsequent switch.
pub fn write_claude_credentials(credentials: &str) -> Result<()> {
    let account = claude_account_name();

    let output = Command::new("security")
        .args([
            "add-generic-password",
            "-U",
            "-s", CLAUDE_SERVICE,
            "-a", &account,
            "-w", credentials,
        ])
        .output()
        .context("failed to run 'security' command")?;

    if !output.status.success() {
        let stderr = String::from_utf8_lossy(&output.stderr);
        bail!(
            "failed to write Claude Code credentials to Keychain: {}",
            stderr.trim()
        );
    }

    Ok(())
}
