use std::fs;
use std::path::Path;

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

use crate::init::patch_claude;
use crate::ui;

const INDEX_TEMPLATE: &str = include_str!("../templates/index.md");
const GRAPH_TEMPLATE: &str = include_str!("../templates/graph.md");
const NEEDS_REVIEW_TEMPLATE: &str = include_str!("../templates/needs_review.md");
const ENV_EXAMPLE: &str = include_str!("../templates/env_example");
const DOMAIN_OVERVIEW_TEMPLATE: &str = include_str!("../templates/domain_overview.md");
const DECISION_TEMPLATE: &str = include_str!("../templates/decision.md");

const WIKI_CONSULT_CMD: &str = include_str!("../templates/commands/wiki_consult.md");
const WIKI_UPDATE_CMD: &str = include_str!("../templates/commands/wiki_update.md");
const WIKI_ADD_CONTEXT_CMD: &str = include_str!("../templates/commands/wiki_add_context.md");
const WIKI_ADD_DECISION_CMD: &str = include_str!("../templates/commands/wiki_add_decision.md");
const WIKI_CHECK_WORKFLOW: &str = include_str!("../templates/wiki-check.yml");

pub fn run() -> Result<()> {
    let wiki_dir = Path::new(".wiki");

    if wiki_dir.exists() {
        bail!(
            ".wiki/ already exists. Use `codefidence rebuild` to regenerate, \
             or delete .wiki/ manually to start fresh."
        );
    }

    ui::app_header(env!("CARGO_PKG_VERSION"));
    ui::action("Initializing project wiki");
    eprintln!();

    // Create directory structure
    ui::step("Creating .wiki/ directory structure...");
    fs::create_dir_all(".wiki/_templates")
        .context("Failed to create .wiki/_templates directory")?;
    fs::create_dir_all(".wiki/domains").context("Failed to create .wiki/domains directory")?;
    fs::create_dir_all(".wiki/decisions").context("Failed to create .wiki/decisions directory")?;

    // Write template files
    ui::step("Writing wiki templates...");
    let date = chrono::Utc::now().format("%Y-%m-%d").to_string();
    let index_content = INDEX_TEMPLATE.replace("{date}", &date);
    fs::write(".wiki/_index.md", index_content).context("Failed to write _index.md")?;
    fs::write(".wiki/_graph.md", GRAPH_TEMPLATE).context("Failed to write _graph.md")?;
    fs::write(".wiki/_needs-review.md", NEEDS_REVIEW_TEMPLATE)
        .context("Failed to write _needs-review.md")?;
    fs::write(".wiki/.env.example", ENV_EXAMPLE).context("Failed to write .env.example")?;
    fs::write(
        ".wiki/_templates/domain-overview.md",
        DOMAIN_OVERVIEW_TEMPLATE,
    )
    .context("Failed to write domain-overview.md template")?;
    fs::write(".wiki/_templates/decision.md", DECISION_TEMPLATE)
        .context("Failed to write decision.md template")?;

    // Write default config
    fs::write(
        ".wiki/config.toml",
        "# codefidence configuration\n# staleness_days = 30\n# auto_index = true\n",
    )
    .context("Failed to write config.toml")?;

    // Gitattributes for merge strategy on generated files
    ui::step("Writing .gitattributes for generated files...");
    fs::write(
        ".wiki/.gitattributes",
        "# Auto-generated by codefidence. Regenerate with: codefidence rebuild\n\
         # These files are generated and can be safely overwritten after a merge conflict.\n\
         # Strategy merge=ours keeps your local version; run `codefidence rebuild` after merge.\n\
         \n\
         _index.md merge=ours\n\
         _index.json merge=ours\n\
         _graph.md merge=ours\n\
         _needs-review.md merge=ours\n\
         .file-index.json merge=ours\n",
    )
    .context("Failed to write .gitattributes")?;

    // Gitkeep files for empty directories
    fs::write(".wiki/domains/.gitkeep", "").context("Failed to write domains/.gitkeep")?;
    fs::write(".wiki/decisions/.gitkeep", "").context("Failed to write decisions/.gitkeep")?;

    // Update .gitignore
    ui::step("Updating .gitignore...");
    update_gitignore().context("Failed to update .gitignore")?;

    eprintln!();
    ui::done("Wiki structure created.");
    ui::info("Next steps:");
    ui::info("  codefidence init --scan     Scan codebase and generate domain notes");
    ui::info("  codefidence init --hooks    Install Claude Code hooks");
    ui::info("  codefidence init --full     All of the above + CLAUDE.md patch");
    eprintln!();

    Ok(())
}

/// Install Claude slash commands and patch CLAUDE.md.
/// Called by `init --full` or as a separate opt-in step.
pub fn install_claude_integration() -> Result<()> {
    // Create .claude/commands/ slash command files
    ui::step("Installing Claude slash commands...");
    fs::create_dir_all(".claude/commands")
        .context("Failed to create .claude/commands directory")?;
    fs::write(".claude/commands/wiki-consult.md", WIKI_CONSULT_CMD)
        .context("Failed to write wiki-consult.md")?;
    fs::write(".claude/commands/wiki-update.md", WIKI_UPDATE_CMD)
        .context("Failed to write wiki-update.md")?;
    fs::write(".claude/commands/wiki-add-context.md", WIKI_ADD_CONTEXT_CMD)
        .context("Failed to write wiki-add-context.md")?;
    fs::write(
        ".claude/commands/wiki-add-decision.md",
        WIKI_ADD_DECISION_CMD,
    )
    .context("Failed to write wiki-add-decision.md")?;

    // Patch CLAUDE.md
    ui::step("Patching CLAUDE.md...");
    patch_claude::run().context("Failed to patch CLAUDE.md")?;

    // Install GitHub Actions workflow
    ui::step("Installing GitHub Actions workflow...");
    fs::create_dir_all(".github/workflows")
        .context("Failed to create .github/workflows directory")?;
    fs::write(".github/workflows/wiki-check.yml", WIKI_CHECK_WORKFLOW)
        .context("Failed to write wiki-check.yml")?;

    Ok(())
}

fn update_gitignore() -> Result<()> {
    let gitignore_path = Path::new(".gitignore");
    let mut content = if gitignore_path.exists() {
        fs::read_to_string(gitignore_path).context("Failed to read .gitignore")?
    } else {
        String::new()
    };

    let entries = [".wiki/.env", ".wiki/.file-index.json"];
    let mut added = false;

    for entry in &entries {
        if !content.lines().any(|line| line.trim() == *entry) {
            if !content.ends_with('\n') && !content.is_empty() {
                content.push('\n');
            }
            if !added {
                content.push_str("\n# Codefidence\n");
            }
            content.push_str(entry);
            content.push('\n');
            added = true;
        }
    }

    if added {
        fs::write(gitignore_path, content).context("Failed to write .gitignore")?;
    }

    Ok(())
}
