gitas 0.0.8

GitHub Account Switch — manage multiple git identities
use crate::github;
use crate::models::{Account, Config, save_config, set_token};
use crate::tui::{
    enter_raw_mode, exit_raw_mode, raw_confirm, raw_input, raw_password, raw_println, raw_select,
};
use colored::Colorize;

pub fn run(config: &mut Config) {
    enter_raw_mode(); // Start raw mode immediately

    raw_println("");
    raw_println(&format!("  {}", "Add Git Account".bold()));
    raw_println(&format!("  {}", "".repeat(48).dimmed()));
    raw_println("");

    let methods = vec![
        "Manual Input".to_string(),
        "GitHub Browser Login".to_string(),
    ];

    let selection = raw_select("Authentication Method", &methods, 0);

    match selection {
        Some(0) => {
            // Manual - stay in raw mode
            add_manual(config);
            exit_raw_mode();
        }
        Some(1) => {
            // GitHub - exit raw mode because github::login prints standard output and opens browser
            exit_raw_mode();
            add_github(config);
        }
        _ => {
            exit_raw_mode();
        }
    }
}

fn add_github(config: &mut Config) {
    // Normal terminal mode
    let Some((username, email, _name, token)) = github::login() else {
        return;
    };

    println!(
        "  Authenticated as: {} <{}>",
        username.cyan(),
        email.dimmed()
    );

    // We could re-enter raw mode here for the alias input, but mixing modes is complex.
    // Let's stick to standard input for consistency within this flow since we already left raw mode.

    enter_raw_mode();

    let alias = raw_input("Alias (optional)", "").unwrap_or_default();
    let alias = if alias.is_empty() { None } else { Some(alias) };

    // Check for duplicate
    let existing_idx = config
        .accounts
        .iter()
        .position(|a| a.username == username && a.alias == alias);

    if existing_idx.is_some() {
        let prompt = format!(
            "Account '{}' (alias: {}) already exists. Overwrite?",
            username.yellow(),
            alias.as_deref().unwrap_or("none").yellow()
        );

        if raw_confirm(&prompt, false) != Some(true) {
            raw_println(&format!("\n  {}\n", "Cancelled.".dimmed()));
            exit_raw_mode();
            return;
        }
    }

    let account = Account {
        username: username.clone(),
        email,
        alias: alias.clone(),
        host: None,
        ssh_key: None,
    };

    set_token(&username, alias.as_deref(), &token);

    if let Some(idx) = existing_idx {
        upsert_account_raw(config, account, Some(idx));
    } else {
        upsert_account_raw(config, account, None);
    }
    exit_raw_mode();
}

use crate::utils::scan_ssh_keys;

fn add_manual(config: &mut Config) {
    let Some(username) = raw_input("Username", "").filter(|u| !u.is_empty()) else {
        return;
    };
    let Some(email) = raw_input("Email", "").filter(|e| !e.is_empty()) else {
        return;
    };

    let alias = raw_input("Alias (optional)", "").unwrap_or_default();
    let alias = if alias.is_empty() { None } else { Some(alias) };

    // Check duplicate
    let existing_idx = config
        .accounts
        .iter()
        .position(|a| a.username == username && a.alias == alias);

    if existing_idx.is_some() {
        let prompt = format!(
            "Account '{}' (alias: {}) already exists. Overwrite?",
            username.yellow(),
            alias.as_deref().unwrap_or("none").yellow()
        );

        if raw_confirm(&prompt, false) != Some(true) {
            raw_println(&format!("\n  {}\n", "Cancelled.".dimmed()));
            return;
        }
    }

    let auth_types = vec!["Token/PAT".to_string(), "SSH Key".to_string()];
    let Some(auth_choice) = raw_select("Authentication Type", &auth_types, 0) else {
        return;
    };

    let mut token = String::new();
    let mut host = None;
    let mut ssh_key = None;

    if auth_choice == 0 {
        // Token/PAT
        token = raw_password("Token/PAT (optional)").unwrap_or_default();
        let host_in = raw_input("Host", "github.com").unwrap_or_else(|| "github.com".to_string());
        host = if host_in == "github.com" || host_in.is_empty() {
            None
        } else {
            Some(host_in)
        };
    } else {
        // SSH Key
        let (display_items, paths, default_idx) = scan_ssh_keys(&username, &email);
        let Some(selection) = raw_select("Keys in ~/.ssh", &display_items, default_idx) else {
            return;
        };

        if selection < paths.len() {
            ssh_key = Some(paths[selection].to_string_lossy().to_string());
        } else if selection == paths.len() {
            let manual = raw_input("SSH Key Path", "").unwrap_or_default();
            ssh_key = if manual.is_empty() {
                None
            } else {
                Some(manual)
            };
        }
    }

    let account = Account {
        username: username.clone(),
        email,
        alias: alias.clone(),
        host,
        ssh_key,
    };

    if !token.is_empty() {
        set_token(&username, alias.as_deref(), &token);
    } else {
        crate::models::delete_token(&username, alias.as_deref());
    }

    if let Some(idx) = existing_idx {
        upsert_account_raw(config, account, Some(idx));
    } else {
        upsert_account_raw(config, account, None);
    }
}

fn upsert_account_raw(config: &mut Config, account: Account, index: Option<usize>) {
    let username = account.username.clone();
    if let Some(idx) = index {
        config.accounts[idx] = account;
        raw_println(&format!(
            "\n  {} Account '{}' updated successfully.\n",
            "".green().bold(),
            username.cyan()
        ));
    } else {
        config.accounts.push(account);
        raw_println(&format!(
            "\n  {} Account '{}' added successfully.\n",
            "".green().bold(),
            username.cyan()
        ));
    }
    save_config(config);
}