use crate::config::{CommandSequence, KeyBinding, PluginEntry, TmuxConfig, Workspace};
use crate::registry::{self, OptionScope};
use std::path::PathBuf;

pub fn generate_conf(config: &TmuxConfig) -> String {
    let mut out = String::new();
    out.push_str("# Generated by tumix — https://github.com/CoderWeasley/tumix\n\n");

    emit_options(config, &mut out);
    emit_feature_presets(config, &mut out);
    emit_bindings(config, &mut out);
    emit_plugins(config, &mut out);
    emit_extra(config, &mut out);

    out
}

fn emit_options(config: &TmuxConfig, out: &mut String) {
    out.push_str("# --- Options ---\n");
    let mut names: Vec<_> = config.options.keys().collect();
    names.sort();

    for name in names {
        let value = &config.options[name];
        if value.is_empty() {
            continue;
        }
        let is_custom = registry::find_option(name).is_none();
        if !is_custom {
            if let Some(def) = registry::find_option(name) {
                if value == def.default {
                    continue;
                }
            }
        }
        let line = if let Some(def) = registry::find_option(name) {
            format!(
                "{} {} {}",
                registry::set_command(def.scope),
                name,
                format_value(value, def.scope)
            )
        } else {
            format!(
                "set -g {} {}",
                name,
                format_value(value, OptionScope::Session)
            )
        };
        out.push_str(&line);
        out.push('\n');
    }
    out.push('\n');
}

fn format_value(value: &str, _scope: OptionScope) -> String {
    if value.chars().any(|c| c.is_whitespace()) || value.contains('#') {
        format!("\"{}\"", value.replace('"', "\\\""))
    } else {
        value.to_string()
    }
}

fn emit_feature_presets(config: &TmuxConfig, out: &mut String) {
    let f = &config.features;
    out.push_str("# --- Feature presets ---\n");

    if f.rebind_prefix {
        let prefix = config.get_option("prefix");
        out.push_str("unbind C-b\n");
        if prefix != "C-b" {
            out.push_str(&format!("bind-key {} send-prefix\n", prefix));
            out.push_str(&format!("bind-key {} last-window\n", prefix));
        }
    }

    if f.vim_navigation {
        out.push_str(
            r#"# Vim-style pane navigation (no prefix)
bind-key -n C-h select-pane -L
bind-key -n C-j select-pane -D
bind-key -n C-k select-pane -U
bind-key -n C-l select-pane -R
bind-key -n M-h select-pane -L
bind-key -n M-j select-pane -D
bind-key -n M-k select-pane -U
bind-key -n M-l select-pane -R
bind-key -r H resize-pane -L 5
bind-key -r J resize-pane -D 5
bind-key -r K resize-pane -U 5
bind-key -r L resize-pane -R 5
"#,
        );
    }

    if f.aggressive_resize {
        config_set(out, "setw -g aggressive-resize on");
    }

    if f.automatic_rename {
        config_set(out, "setw -g automatic-rename on");
    }

    if f.reload_config_key {
        let prefix = config.get_option("prefix");
        out.push_str(&format!(
            "bind-key {} source-file ~/.tmux.conf \\; display \"Config reloaded\"\n",
            prefix
        ));
    }

    if f.system_monitor {
        out.push_str(
            r#"# System monitor in status-right (requires compatible status-right)
# set -g status-right '#[fg=green](#(uptime -p | sed s/up\ //)) CPU:#(top -bn1 | awk "/Cpu/ {print \$2}") MEM:#(free -m | awk "/Mem:/ {printf \"%.0f%%\", \$3/\$2*100}")'
"#,
        );
    }
    out.push('\n');
}

fn config_set(out: &mut String, line: &str) {
    out.push_str(line);
    out.push('\n');
}

fn emit_bindings(config: &TmuxConfig, out: &mut String) {
    if config.bindings.is_empty() {
        return;
    }
    out.push_str("# --- Custom key bindings ---\n");
    for b in &config.bindings {
        out.push_str(&binding_line(b));
        out.push('\n');
    }
    out.push('\n');
}

pub fn binding_line(b: &KeyBinding) -> String {
    if b.flags.is_empty() {
        format!("bind-key {} {}", b.key, b.command)
    } else {
        format!("bind-key {} {} {}", b.flags.trim(), b.key, b.command)
    }
}

fn emit_plugins(config: &TmuxConfig, out: &mut String) {
    let enabled: Vec<&PluginEntry> = config.plugins.iter().filter(|p| p.enabled).collect();
    if enabled.is_empty() {
        return;
    }

    out.push_str("# --- Plugins (TPM) ---\n");
    for plugin in enabled {
        if plugin.name.contains("tpm") {
            continue;
        }
        out.push_str(&format!("set -g @plugin '{}'\n", plugin.name));
    }

    let tpm_path = tpm_install_path();
    out.push_str(&format!("\nrun '{}'\n\n", tpm_path.display()));
}

fn tpm_install_path() -> PathBuf {
    if let Ok(home) = std::env::var("HOME") {
        return PathBuf::from(home).join(".tmux/plugins/tpm/tpm");
    }
    if let Ok(profile) = std::env::var("USERPROFILE") {
        return PathBuf::from(profile).join(".tmux/plugins/tpm/tpm");
    }
    PathBuf::from("~/.tmux/plugins/tpm/tpm")
}

fn emit_extra(config: &TmuxConfig, out: &mut String) {
    if config.extra_lines.is_empty() {
        return;
    }
    out.push_str("# --- Extra lines ---\n");
    for line in &config.extra_lines {
        out.push_str(line);
        if !line.ends_with('\n') {
            out.push('\n');
        }
    }
}

pub fn generate_workspace_script(ws: &Workspace) -> String {
    let mut out = String::new();
    out.push_str("#!/bin/sh\n");
    out.push_str(&format!("# Spawn workspace: {}\n\n", ws.name));

    for sess in &ws.sessions {
        if sess.windows.is_empty() {
            continue;
        }

        let first_win = &sess.windows[0];

        if !first_win.panes.is_empty() {
            out.push_str(&format!(
                "tmux new-session -d -s '{}' -n '{}' \\;\n",
                sess.name, first_win.name
            ));
            for (pi, pane) in first_win.panes.iter().enumerate() {
                if pi > 0 {
                    out.push_str(&format!(
                        "tmux split-window -t '{}' \\;\n",
                        sess.name
                    ));
                }
                for cmd in &pane.commands {
                    let target = if pi == 0 {
                        format!("{}.{}", sess.name, first_win.name)
                    } else {
                        format!("{}.{}", sess.name, first_win.name)
                    };
                    out.push_str(&format!(
                        "tmux send-keys -t '{}' '{}' Enter \\;\n",
                        target,
                        cmd.replace('\'', "'\\''")
                    ));
                }
            }
            if first_win.panes.len() > 1 {
                let layout = first_win
                    .layout
                    .as_deref()
                    .unwrap_or("even-horizontal");
                out.push_str(&format!(
                    "tmux select-layout -t '{}' '{}' \\;\n",
                    sess.name, layout
                ));
            }
        } else {
            out.push_str(&format!(
                "tmux new-session -d -s '{}' -n '{}' \\;\n",
                sess.name, first_win.name
            ));
        }

        for win in sess.windows.iter().skip(1) {
            if !win.panes.is_empty() {
                out.push_str(&format!(
                    "tmux new-window -t '{}' -n '{}' \\;\n",
                    sess.name, win.name
                ));
                for (pi, pane) in win.panes.iter().enumerate() {
                    if pi > 0 {
                        out.push_str(&format!(
                            "tmux split-window -t '{}' \\;\n",
                            sess.name
                        ));
                    }
                    for cmd in &pane.commands {
                        out.push_str(&format!(
                            "tmux send-keys -t '{}.{}' '{}' Enter \\;\n",
                            sess.name,
                            win.name,
                            cmd.replace('\'', "'\\''")
                        ));
                    }
                }
                if win.panes.len() > 1 {
                    let layout = win.layout.as_deref().unwrap_or("even-horizontal");
                    out.push_str(&format!(
                        "tmux select-layout -t '{}' '{}' \\;\n",
                        sess.name, layout
                    ));
                }
            } else {
                out.push_str(&format!(
                    "tmux new-window -t '{}' -n '{}' \\;\n",
                    sess.name, win.name
                ));
            }
        }

        out.push_str(&format!(
            "tmux select-window -t '{}':{} \\;\n",
            sess.name, 1
        ));
    }

    out.push_str("\n# Attach to first session\n");
    if let Some(first) = ws.sessions.first() {
        out.push_str(&format!(
            "tmux attach-session -t '{}'\n",
            first.name
        ));
    }

    out
}

pub fn generate_bash_completions(workspaces: &[Workspace], sequences: &[CommandSequence]) -> String {
    let ws_names: Vec<&str> = workspaces.iter().map(|w| w.name.as_str()).collect();
    let seq_names: Vec<&str> = sequences.iter().map(|s| s.name.as_str()).collect();

    let mut out = String::new();
    out.push_str("# tumix shell completion: workspace names\n");
    out.push_str("_tumix_workspace_completions() {\n");
    out.push_str("    local words=\"");
    out.push_str(&ws_names.join(" "));
    out.push_str("\"\n");
    out.push_str("    COMPREPLY=($(compgen -W \"$words\" -- \"${COMP_WORDS[COMP_CWORD]}\"))\n");
    out.push_str("}\n");
    out.push_str("complete -F _tumix_workspace_completions tumix-spawn\n\n");

    out.push_str("_tumix_sequence_completions() {\n");
    out.push_str("    local words=\"");
    out.push_str(&seq_names.join(" "));
    out.push_str("\"\n");
    out.push_str("    COMPREPLY=($(compgen -W \"$words\" -- \"${COMP_WORDS[COMP_CWORD]}\"))\n");
    out.push_str("}\n");
    out.push_str("complete -F _tumix_sequence_completions tumix-run\n\n");

    out
}

pub fn generate_zsh_completions(workspaces: &[Workspace], sequences: &[CommandSequence]) -> String {
    let mut out = String::new();
    out.push_str("#compdef tumix-spawn tumix-run\n\n");
    out.push_str("_tumix_workspace_completions() {\n");
    out.push_str("    _values 'workspace' \\\n");
    for ws in workspaces {
        out.push_str(&format!("        '{}' \\\n", ws.name));
    }
    out.push_str("        ':\n");
    out.push_str("}\n\n");
    out.push_str("_tumix_sequence_completions() {\n");
    out.push_str("    _values 'sequence' \\\n");
    for seq in sequences {
        out.push_str(&format!("        '{}' \\\n", seq.name));
    }
    out.push_str("        ':\n");
    out.push_str("}\n\n");
    out.push_str("compdef _tumix_workspace_completions tumix-spawn\n");
    out.push_str("compdef _tumix_sequence_completions tumix-run\n");

    out
}

pub fn generate_powershell_completions(
    workspaces: &[Workspace],
    sequences: &[CommandSequence],
) -> String {
    let mut out = String::new();
    out.push_str("# tumix PowerShell completion\n\n");
    out.push_str("$tumixWorkspaces = @(\n");
    for ws in workspaces {
        out.push_str(&format!("    '{}'\n", ws.name));
    }
    out.push_str(")\n\n");
    out.push_str("$tumixSequences = @(\n");
    for seq in sequences {
        out.push_str(&format!("    '{}'\n", seq.name));
    }
    out.push_str(")\n\n");

    out.push_str(
        "Register-ArgumentCompleter -Native -CommandName tumix-spawn -ScriptBlock {
    param($wordToComplete, $commandAst, $cursorPosition)
    $tumixWorkspaces | Where-Object { $_ -like \"$wordToComplete*\" } | ForEach-Object { $_ }
}\n\n",
    );

    out.push_str(
        "Register-ArgumentCompleter -Native -CommandName tumix-run -ScriptBlock {
    param($wordToComplete, $commandAst, $cursorPosition)
    $tumixSequences | Where-Object { $_ -like \"$wordToComplete*\" } | ForEach-Object { $_ }
}\n",
    );

    out
}
