//! Install command — fetches SKILL.md from the Adom Wiki at install
//! time. NEVER include_str! the SKILL.md (rule from
//! gallia/skills/tool-publisher/SKILL.md "install rule"). On any wiki
//! error the install exits non-zero with a clear message; no fallback.

use crate::ui::{err, hint, ok};
use clap::CommandFactory;
use std::fs;
use std::io::Write;
use std::path::PathBuf;
use std::time::Duration;

const SKILL_URL: &str =
    "https://wiki.adom.inc/api/pages/adom/adom-chip-thumbnailer/files/SKILL.md";

fn fetch_skill_md() -> ! {
    panic!("never called — fetch_skill_md returns into main; here for type-only docs");
}

pub fn run() {
    let home = std::env::var("HOME").unwrap_or_else(|_| "/home/adom".into());

    // 1. Skill file → ~/.claude/skills/adom-chip-thumbnailer/SKILL.md
    let skill_md = match ureq::get(SKILL_URL).timeout(Duration::from_secs(10)).call() {
        Ok(r) => match r.into_string() {
            Ok(s) => s,
            Err(e) => fail(&format!("read SKILL.md body from {SKILL_URL}: {e}")),
        },
        Err(ureq::Error::Status(code, _)) => {
            fail(&format!("wiki returned HTTP {code} for {SKILL_URL}"))
        }
        Err(e) => fail(&format!("could not reach {SKILL_URL}: {e}")),
    };

    let skill_dir = PathBuf::from(&home).join(".claude/skills/adom-chip-thumbnailer");
    if let Err(e) = fs::create_dir_all(&skill_dir) {
        fail(&format!("mkdir {}: {e}", skill_dir.display()));
    }
    let skill_path = skill_dir.join("SKILL.md");
    if let Err(e) = fs::write(&skill_path, &skill_md) {
        fail(&format!("write {}: {e}", skill_path.display()));
    }
    ok(format!(
        "skill installed at {} ({} bytes from wiki)",
        skill_path.display(),
        skill_md.len()
    ));

    // 2. Bash completions → ~/.local/share/bash-completion/completions/chip-thumbnailer
    let comp_dir = PathBuf::from(&home).join(".local/share/bash-completion/completions");
    let _ = fs::create_dir_all(&comp_dir);
    let mut cmd = crate::cli::Cli::command();
    let mut buf = Vec::new();
    clap_complete::generate(
        clap_complete::Shell::Bash,
        &mut cmd,
        "chip-thumbnailer",
        &mut buf,
    );
    let _ = fs::write(comp_dir.join("chip-thumbnailer"), &buf);
    ok(format!(
        "bash completions at {}/chip-thumbnailer",
        comp_dir.display()
    ));

    // 3. .bashrc nudge (idempotent).
    let bashrc_path = PathBuf::from(&home).join(".bashrc");
    let existing = fs::read_to_string(&bashrc_path).unwrap_or_default();
    if !existing.contains("# chip-thumbnailer completions") {
        if let Ok(mut f) = fs::OpenOptions::new().append(true).open(&bashrc_path) {
            let _ = f.write_all(
                b"\n# chip-thumbnailer completions\neval \"$(chip-thumbnailer completions bash 2>/dev/null)\"\n",
            );
            ok(".bashrc: completion hook appended (open a new shell or `source ~/.bashrc`)");
        }
    }

    println!();
    ok("chip-thumbnailer installed. Try `chip-thumbnailer health`.");
}

fn fail(msg: &str) -> ! {
    err(format!("install aborted — {msg}"));
    hint("SKILL.md is fetched from the wiki at install time (no embedded fallback).");
    hint("Check connectivity to wiki-ufypy5dpx93o.adom.cloud and retry `chip-thumbnailer install`.");
    std::process::exit(2);
}

// Keep fetch_skill_md private hint above; the trick is `fail` returns `!`
// so callers can use it in expression position. The dummy fn above keeps
// the docstring discoverable; lint silenced.
#[allow(dead_code)]
fn _doc_fetch_skill_md() {
    let _ = fetch_skill_md;
}