use std::fs;
use std::io::Write;

pub const HOOKS_ZSH_CONTENT: &str = r#"
__recap_preexec() {
    __RECAP_CMD="$1"
    __RECAP_START=$(date +%s%3N)
    __RECAP_PWD="$PWD"
}

__recap_precmd() {
    local exit_code=$?
    if [[ -n "$__RECAP_CMD" ]]; then
        local end=$(date +%s%3N)
        local duration=$(( end - __RECAP_START ))
        printf '%s\t%s\t%s\t%d\t%d\n' \
            "$__RECAP_START" \
            "$__RECAP_PWD" \
            "$__RECAP_CMD" \
            "$exit_code" \
            "$duration" \
            >> "${XDG_DATA_HOME:-$HOME/.local/share}/recap/events.tsv"
        unset __RECAP_CMD
    fi
}

autoload -Uz add-zsh-hook
add-zsh-hook preexec __recap_preexec
add-zsh-hook precmd __recap_precmd
"#;

pub const HOOKS_BASH_CONTENT: &str = r#"
__recap_preexec() {
    if [[ "$BASH_COMMAND" == __recap_precmd* ]]; then
        return
    fi
    __RECAP_CMD="$BASH_COMMAND"
    __RECAP_START=$(date +%s%3N)
    __RECAP_PWD="$PWD"
}

__recap_precmd() {
    local exit_code=$?
    if [[ -n "${__RECAP_CMD:-}" ]]; then
        local end
        end=$(date +%s%3N)
        local duration=$(( end - __RECAP_START ))
        printf '%s\t%s\t%s\t%d\t%d\n' \
            "$__RECAP_START" \
            "$__RECAP_PWD" \
            "$__RECAP_CMD" \
            "$exit_code" \
            "$duration" \
            >> "${XDG_DATA_HOME:-$HOME/.local/share}/recap/events.tsv"
        unset __RECAP_CMD
    fi
}

trap '__recap_preexec' DEBUG
PROMPT_COMMAND="${PROMPT_COMMAND:+$PROMPT_COMMAND;}__recap_precmd"
"#;

pub const HOOKS_FISH_CONTENT: &str = r#"
function __recap_preexec --on-event fish_preexec
    set -g __recap_cmd $argv[1]
    set -g __recap_start (date +%s%3N)
    set -g __recap_pwd $PWD
end

function __recap_postexec --on-event fish_postexec
    set -l exit_code $status
    if set -q __recap_cmd
        set -l end_time (date +%s%3N)
        set -l duration (math $end_time - $__recap_start)
        set -l data_home (set -q XDG_DATA_HOME; and echo $XDG_DATA_HOME; or echo "$HOME/.local/share")
        printf "%s\t%s\t%s\t%d\t%d\n" \
            $__recap_start \
            $__recap_pwd \
            $__recap_cmd \
            $exit_code \
            $duration \
            >> "$data_home/recap/events.tsv"
        set -e __recap_cmd
    end
end
"#;

pub fn install_shell_integration_auto() -> Result<(), Box<dyn std::error::Error>> {
    let shell = std::env::var("SHELL").unwrap_or_default();

    if shell.contains("zsh") {
        install_zsh()
    } else if shell.contains("bash") {
        install_bash()
    } else if shell.contains("fish") {
        install_fish()
    } else {
        println!("Shell not recognised: {}", shell);
        println!("Supported shells: zsh, bash, fish");
        Ok(())
    }
}

pub fn install_zsh() -> Result<(), Box<dyn std::error::Error>> {
    let config_dir = dirs::config_dir().unwrap().join("recap");
    fs::create_dir_all(&config_dir)?;
    let hooks_path = config_dir.join("hooks.zsh");
    fs::write(&hooks_path, HOOKS_ZSH_CONTENT)?;
    println!("✓ Hooks written to {}", hooks_path.display());

    let zshrc = dirs::home_dir().unwrap().join(".zshrc");
    if !zshrc.exists() {
        fs::write(&zshrc, "")?;
    }
    let existing = fs::read_to_string(&zshrc)?;
    let line = "source ~/.config/recap/hooks.zsh";
    if existing.contains(line) {
        println!("✓ Already present in ~/.zshrc");
    } else {
        let mut f = fs::OpenOptions::new().append(true).open(&zshrc)?;
        writeln!(&mut f, "\n{}", line)?;
        println!("✓ Added to ~/.zshrc");
        println!("→ Run: source ~/.zshrc");
    }
    Ok(())
}

pub fn install_bash() -> Result<(), Box<dyn std::error::Error>> {
    let config_dir = dirs::config_dir().unwrap().join("recap");
    fs::create_dir_all(&config_dir)?;
    let hooks_path = config_dir.join("hooks.bash");
    fs::write(&hooks_path, HOOKS_BASH_CONTENT)?;
    println!("✓ Hooks written to {}", hooks_path.display());

    let bashrc = dirs::home_dir().unwrap().join(".bashrc");
    if !bashrc.exists() {
        fs::write(&bashrc, "")?;
    }
    let existing = fs::read_to_string(&bashrc)?;
    let line = "source ~/.config/recap/hooks.bash";
    if existing.contains(line) {
        println!("✓ Already present in ~/.bashrc");
    } else {
        let mut f = fs::OpenOptions::new().append(true).open(&bashrc)?;
        writeln!(&mut f, "\n{}", line)?;
        println!("✓ Added to ~/.bashrc");
        println!("→ Run: source ~/.bashrc");
    }
    Ok(())
}

pub fn install_fish() -> Result<(), Box<dyn std::error::Error>> {
    let fish_conf_d = dirs::config_dir().unwrap().join("fish/conf.d");
    fs::create_dir_all(&fish_conf_d)?;
    let hooks_path = fish_conf_d.join("recap.fish");
    fs::write(&hooks_path, HOOKS_FISH_CONTENT)?;
    println!("✓ Hooks written to {}", hooks_path.display());
    println!("→ Restart fish or run: source {}", hooks_path.display());
    Ok(())
}

pub fn uninstall_shell_integration() -> Result<(), Box<dyn std::error::Error>> {
    let shell = std::env::var("SHELL").unwrap_or_default();

    if shell.contains("zsh") {
        uninstall_zsh()
    } else if shell.contains("bash") {
        uninstall_bash()
    } else if shell.contains("fish") {
        uninstall_fish()
    } else {
        println!("Shell not recognised: {}", shell);
        println!("Supported shells: zsh, bash, fish");
        Ok(())
    }
}

pub fn uninstall_zsh() -> Result<(), Box<dyn std::error::Error>> {
    let hooks_path = dirs::config_dir().unwrap().join("recap/hooks.zsh");
    if hooks_path.exists() {
        fs::remove_file(&hooks_path)?;
        println!("✓ Removed {}", hooks_path.display());
    }
    let zshrc = dirs::home_dir().unwrap().join(".zshrc");
    if zshrc.exists() {
        let content = fs::read_to_string(&zshrc)?;
        let line = "source ~/.config/recap/hooks.zsh";
        if content.contains(line) {
            let cleaned = content
                .lines()
                .filter(|l| !l.trim().eq(line))
                .collect::<Vec<_>>()
                .join("\n");
            fs::write(&zshrc, cleaned + "\n")?;
            println!("✓ Removed from ~/.zshrc");
            println!("→ Run: source ~/.zshrc");
        } else {
            println!("✓ Nothing to remove from ~/.zshrc");
        }
    }
    Ok(())
}

pub fn uninstall_bash() -> Result<(), Box<dyn std::error::Error>> {
    let hooks_path = dirs::config_dir().unwrap().join("recap/hooks.bash");
    if hooks_path.exists() {
        fs::remove_file(&hooks_path)?;
        println!("✓ Removed {}", hooks_path.display());
    }
    let bashrc = dirs::home_dir().unwrap().join(".bashrc");
    if bashrc.exists() {
        let content = fs::read_to_string(&bashrc)?;
        let line = "source ~/.config/recap/hooks.bash";
        if content.contains(line) {
            let cleaned = content
                .lines()
                .filter(|l| !l.trim().eq(line))
                .collect::<Vec<_>>()
                .join("\n");
            fs::write(&bashrc, cleaned + "\n")?;
            println!("✓ Removed from ~/.bashrc");
            println!("→ Run: source ~/.bashrc");
        } else {
            println!("✓ Nothing to remove from ~/.bashrc");
        }
    }
    Ok(())
}

pub fn uninstall_fish() -> Result<(), Box<dyn std::error::Error>> {
    let hooks_path = dirs::config_dir().unwrap().join("fish/conf.d/recap.fish");
    if hooks_path.exists() {
        fs::remove_file(&hooks_path)?;
        println!("✓ Removed {}", hooks_path.display());
        println!("→ Restart fish to apply");
    } else {
        println!("✓ Nothing to remove");
    }
    Ok(())
}
