use rusqlite::{Connection, Result};
use std::fs::File;
use std::io::{BufRead, BufReader};

use crate::filter::{sanitize_command, should_filter_command};

pub fn import_zsh_history(conn: &Connection) -> Result<usize> {
    let home = std::env::var("HOME").unwrap_or_default();
    let path = std::path::Path::new(&home).join(".zsh_history");
    if !path.exists() {
        println!("No ~/.zsh_history found.");
        return Ok(0);
    }

    let file = File::open(&path).unwrap();
    let reader = BufReader::new(file);

    let mut stmt = conn.prepare(
        "INSERT OR IGNORE INTO events (ts, pwd, cmd, exit_code, duration)
         VALUES (?1, ?2, ?3, ?4, ?5)",
    )?;

    let mut count = 0;
    for line in reader.lines().map_while(Result::ok) {
        if let Some(rest) = line.strip_prefix(": ") {
            let parts: Vec<&str> = rest.splitn(2, ';').collect();
            if parts.len() == 2 {
                let meta: Vec<&str> = parts[0].splitn(2, ':').collect();
                let ts: i64 = meta[0].trim().parse::<i64>().unwrap_or(0) * 1000;
                let cmd = parts[1].trim();
                if ts > 0 && !cmd.is_empty() && !should_filter_command(cmd) {
                    stmt.execute(rusqlite::params![ts, home.as_str(), sanitize_command(cmd), 0, 0])?;
                    count += 1;
                }
            }
        }
    }

    Ok(count)
}

pub fn import_bash_history(conn: &Connection) -> Result<usize> {
    let home = std::env::var("HOME").unwrap_or_default();
    let path = std::path::Path::new(&home).join(".bash_history");
    if !path.exists() {
        println!("No ~/.bash_history found.");
        return Ok(0);
    }

    let file = File::open(&path).unwrap();
    let reader = BufReader::new(file);

    let mut stmt = conn.prepare(
        "INSERT OR IGNORE INTO events (ts, pwd, cmd, exit_code, duration)
         VALUES (?1, ?2, ?3, ?4, ?5)",
    )?;

    let mut count = 0;
    // Bash history may have optional `#<timestamp>` lines before each command
    // (set via HISTTIMEFORMAT). If absent, ts stays 0 for that entry.
    let mut pending_ts: i64 = 0;

    for line in reader.lines().map_while(Result::ok) {
        if let Some(ts_str) = line.strip_prefix('#') {
            if let Ok(ts) = ts_str.trim().parse::<i64>() {
                pending_ts = ts * 1000;
                continue;
            }
        }
        let cmd = line.trim();
        if !cmd.is_empty() && !should_filter_command(cmd) {
            stmt.execute(rusqlite::params![pending_ts, home.as_str(), sanitize_command(cmd), 0, 0])?;
            count += 1;
        }
        pending_ts = 0;
    }

    Ok(count)
}

pub fn import_fish_history(conn: &Connection) -> Result<usize> {
    let home = std::env::var("HOME").unwrap_or_default();
    // Fish stores history at ~/.local/share/fish/fish_history (XDG_DATA_HOME/fish/fish_history)
    let path = dirs::data_dir()
        .unwrap_or_else(|| std::path::PathBuf::from(format!("{}/.local/share", home)))
        .join("fish/fish_history");

    if !path.exists() {
        println!("No fish history found at {}.", path.display());
        return Ok(0);
    }

    let file = File::open(&path).unwrap();
    let reader = BufReader::new(file);

    let mut stmt = conn.prepare(
        "INSERT OR IGNORE INTO events (ts, pwd, cmd, exit_code, duration)
         VALUES (?1, ?2, ?3, ?4, ?5)",
    )?;

    // Fish history YAML-ish format:
    //   - cmd: git status
    //     when: 1712345678
    let mut count = 0;
    let mut current_cmd: Option<String> = None;
    let mut current_ts: i64 = 0;

    for line in reader.lines().map_while(Result::ok) {
        if let Some(cmd) = line.strip_prefix("- cmd: ") {
            if let Some(c) = current_cmd.take() {
                if !should_filter_command(&c) {
                    stmt.execute(rusqlite::params![current_ts, home.as_str(), sanitize_command(&c), 0, 0])?;
                    count += 1;
                }
            }
            current_cmd = Some(cmd.trim().to_string());
            current_ts = 0;
        } else if let Some(ts_str) = line.strip_prefix("  when: ").or_else(|| line.strip_prefix("   when: ")) {
            if let Ok(ts) = ts_str.trim().parse::<i64>() {
                current_ts = ts * 1000;
            }
        }
    }
    if let Some(c) = current_cmd {
        if !should_filter_command(&c) {
            stmt.execute(rusqlite::params![current_ts, home.as_str(), sanitize_command(&c), 0, 0])?;
            count += 1;
        }
    }

    Ok(count)
}

pub fn import_history(conn: &Connection) -> Result<usize, Box<dyn std::error::Error>> {
    let shell = std::env::var("SHELL").unwrap_or_default();
    let n = if shell.contains("zsh") {
        import_zsh_history(conn)?
    } else if shell.contains("bash") {
        import_bash_history(conn)?
    } else if shell.contains("fish") {
        import_fish_history(conn)?
    } else {
        // Unknown shell: try all three
        import_zsh_history(conn).unwrap_or(0)
            + import_bash_history(conn).unwrap_or(0)
            + import_fish_history(conn).unwrap_or(0)
    };
    Ok(n)
}
