"""Output generators for keyboard shortcut files.

Generates:
- VSCode keybindings.json (per layout)
- Bash/Zsh alias scripts
- Markdown documentation with ASCII keyboard diagrams
"""

import json
from pathlib import Path

from attune.config import _validate_file_path

from .schema import (
    FeatureManifest,
    GeneratedShortcuts,
    KeyboardLayout,
    LayoutShortcuts,
    ShortcutAssignment,
)


class VSCodeKeybindingsGenerator:
    """Generate VSCode keybindings.json files for each layout."""

    def generate(
        self,
        shortcuts: GeneratedShortcuts,
        output_dir: Path,
    ) -> dict[str, Path]:
        """Generate keybindings files for all layouts.

        Returns dict of layout -> output file path.
        """
        output_dir.mkdir(parents=True, exist_ok=True)
        generated_files = {}

        for layout, layout_shortcuts in shortcuts.layouts.items():
            output_file = output_dir / f"{layout.value}.json"
            bindings = self._generate_bindings(shortcuts.manifest, layout_shortcuts)
            validated_output = _validate_file_path(str(output_file))
            validated_output.write_text(json.dumps(bindings, indent=2), encoding="utf-8")
            generated_files[layout.value] = validated_output

        return generated_files

    def _generate_bindings(
        self,
        manifest: FeatureManifest,
        layout_shortcuts: LayoutShortcuts,
    ) -> list[dict]:
        """Generate VSCode keybinding entries."""
        bindings = []
        prefix = manifest.prefix

        for shortcut in layout_shortcuts.shortcuts:
            # Find the feature to get the command
            command = self._find_command(manifest, shortcut.feature_id)
            if not command:
                continue

            bindings.append(
                {
                    "key": f"{prefix} {shortcut.key}",
                    "mac": f"{prefix.replace('ctrl', 'cmd')} {shortcut.key}",
                    "command": command,
                    "// mnemonic": shortcut.mnemonic,
                },
            )

        return bindings

    def _find_command(self, manifest: FeatureManifest, feature_id: str) -> str | None:
        """Find command for a feature ID."""
        for feature in manifest.all_features():
            if feature.id == feature_id:
                return feature.command
        return None


class CLIAliasGenerator:
    """Generate shell alias scripts for CLI commands."""

    BASH_HEADER = """#!/bin/bash
# Keyboard Conductor CLI Aliases for {project_name}
# Generated by Empathy Framework
#
# Add to your .bashrc or .zshrc:
#   source {output_file}
#
# Mnemonic: {mnemonic}

"""

    def generate(
        self,
        shortcuts: GeneratedShortcuts,
        output_file: Path,
    ) -> Path:
        """Generate a shell alias script."""
        output_file.parent.mkdir(parents=True, exist_ok=True)

        # Use QWERTY layout for CLI (most common)
        layout_shortcuts = shortcuts.layouts.get(KeyboardLayout.QWERTY)
        if not layout_shortcuts:
            layout_shortcuts = next(iter(shortcuts.layouts.values()), None)

        validated_output = _validate_file_path(str(output_file))
        if not layout_shortcuts:
            validated_output.write_text("# No shortcuts generated\n", encoding="utf-8")
            return validated_output

        lines = [
            self.BASH_HEADER.format(
                project_name=shortcuts.manifest.project_name,
                output_file=validated_output.name,
                mnemonic=layout_shortcuts.phrase_mnemonic,
            ),
        ]

        for shortcut in layout_shortcuts.shortcuts:
            # Find the CLI alias for this feature
            cli_alias = self._find_cli_alias(shortcuts.manifest, shortcut.feature_id)
            if not cli_alias:
                continue

            # Create a short alias (e.g., "em" for empathy morning)
            short_alias = f"e{shortcut.key}"
            lines.append(f'alias {short_alias}="{cli_alias}"  # {shortcut.mnemonic}')

        validated_output.write_text("\n".join(lines), encoding="utf-8")
        return validated_output

    def _find_cli_alias(self, manifest: FeatureManifest, feature_id: str) -> str | None:
        """Find CLI alias for a feature ID."""
        for feature in manifest.all_features():
            if feature.id == feature_id and feature.cli_alias:
                return feature.cli_alias
        return None


class MarkdownDocGenerator:
    """Generate Markdown documentation with keyboard cheatsheets."""

    TEMPLATE = """# {project_name} Keyboard Shortcuts

> {phrase_mnemonic}

## Quick Reference

Hold **{prefix}** (Mac: **{mac_prefix}**) then press one key:

{cheatsheet}

## Keyboard Layout

```
{keyboard_diagram}
```

## Scales (Learning Progression)

{scales_section}

## All Shortcuts

{full_table}

---

*Generated by [Empathy Framework](https://github.com/Smart-AI-Memory/empathy-framework) Keyboard Conductor*
"""

    KEYBOARD_DIAGRAM = """
┌─────────────────────────────────────┐
│   [Q][W][E][R][T][Y][U][I][O][P]    │
│    [{a}][{s}][{d}][{f}][G][H][J][K][L]    │
│     [{z}][X][{c}][{v}][{b}][N][M]        │
└─────────────────────────────────────┘
"""

    def generate(
        self,
        shortcuts: GeneratedShortcuts,
        output_file: Path,
    ) -> Path:
        """Generate Markdown documentation."""
        output_file.parent.mkdir(parents=True, exist_ok=True)

        # Use QWERTY layout as default for docs
        layout_shortcuts = shortcuts.layouts.get(KeyboardLayout.QWERTY)
        if not layout_shortcuts:
            layout_shortcuts = next(iter(shortcuts.layouts.values()), None)

        validated_output = _validate_file_path(str(output_file))
        if not layout_shortcuts:
            validated_output.write_text("# No shortcuts generated\n", encoding="utf-8")
            return validated_output

        manifest = shortcuts.manifest
        prefix = manifest.prefix
        mac_prefix = prefix.replace("ctrl", "cmd")

        content = self.TEMPLATE.format(
            project_name=manifest.project_name,
            phrase_mnemonic=layout_shortcuts.phrase_mnemonic,
            prefix=prefix,
            mac_prefix=mac_prefix,
            cheatsheet=self._generate_cheatsheet(manifest, layout_shortcuts),
            keyboard_diagram=self._generate_keyboard_diagram(layout_shortcuts),
            scales_section=self._generate_scales_section(manifest, layout_shortcuts),
            full_table=self._generate_full_table(manifest, layout_shortcuts),
        )

        validated_output.write_text(content, encoding="utf-8")
        return validated_output

    def _generate_cheatsheet(
        self,
        manifest: FeatureManifest,
        layout_shortcuts: LayoutShortcuts,
    ) -> str:
        """Generate quick reference cheatsheet."""
        lines = []

        # Group by scale
        scales = layout_shortcuts.scale_assignments
        scale_features = {
            "Daily (Start Here)": scales.daily,
            "Frequent": scales.frequent,
            "Advanced": scales.advanced,
        }

        for scale_name, keys in scale_features.items():
            if not keys:
                continue

            lines.append(f"### {scale_name}")
            for key in keys:
                shortcut = self._find_shortcut_by_key(layout_shortcuts, key)
                if shortcut:
                    feature = self._find_feature(manifest, shortcut.feature_id)
                    name = feature.name if feature else shortcut.feature_id
                    lines.append(f"- **{key.upper()}** = {name}")
            lines.append("")

        return "\n".join(lines)

    def _generate_keyboard_diagram(self, layout_shortcuts: LayoutShortcuts) -> str:
        """Generate ASCII keyboard diagram highlighting active keys."""
        # Map of positions to highlight
        key_positions = {}
        for shortcut in layout_shortcuts.shortcuts:
            key_positions[shortcut.key.lower()] = shortcut.key.upper()

        # Create the diagram with highlights
        diagram = self.KEYBOARD_DIAGRAM

        # Replace placeholders with actual keys or defaults
        replacements = {
            "a": key_positions.get("a", "A"),
            "s": key_positions.get("s", "S"),
            "d": key_positions.get("d", "D"),
            "f": key_positions.get("f", "F"),
            "z": key_positions.get("z", "Z"),
            "c": key_positions.get("c", "C"),
            "v": key_positions.get("v", "V"),
            "b": key_positions.get("b", "B"),
        }

        for placeholder, value in replacements.items():
            diagram = diagram.replace(f"{{{placeholder}}}", value)

        return diagram

    def _generate_scales_section(
        self,
        manifest: FeatureManifest,
        layout_shortcuts: LayoutShortcuts,
    ) -> str:
        """Generate learning progression section."""
        lines = []
        scales = layout_shortcuts.scale_assignments

        lines.append("### Scale 1: The Basics (4 notes)")
        lines.append("```")
        for key in scales.daily:
            shortcut = self._find_shortcut_by_key(layout_shortcuts, key)
            if shortcut:
                feature = self._find_feature(manifest, shortcut.feature_id)
                name = feature.name if feature else shortcut.feature_id
                lines.append(f"{key.upper()} = {name}")
        lines.append("```")
        lines.append("")

        lines.append("### Scale 2: The Workflows (add 4 more)")
        lines.append("```")
        for key in scales.frequent:
            shortcut = self._find_shortcut_by_key(layout_shortcuts, key)
            if shortcut:
                feature = self._find_feature(manifest, shortcut.feature_id)
                name = feature.name if feature else shortcut.feature_id
                lines.append(f"{key.upper()} = {name}")
        lines.append("```")
        lines.append("")

        lines.append("### Scale 3: Full Orchestra (power users)")
        lines.append("```")
        for key in scales.advanced:
            shortcut = self._find_shortcut_by_key(layout_shortcuts, key)
            if shortcut:
                feature = self._find_feature(manifest, shortcut.feature_id)
                name = feature.name if feature else shortcut.feature_id
                lines.append(f"{key.upper()} = {name}")
        lines.append("```")

        return "\n".join(lines)

    def _generate_full_table(
        self,
        manifest: FeatureManifest,
        layout_shortcuts: LayoutShortcuts,
    ) -> str:
        """Generate full table of all shortcuts."""
        lines = [
            "| Key | Command | Mnemonic |",
            "|-----|---------|----------|",
        ]

        for shortcut in layout_shortcuts.shortcuts:
            feature = self._find_feature(manifest, shortcut.feature_id)
            name = feature.name if feature else shortcut.feature_id
            lines.append(f"| {shortcut.key.upper()} | {name} | {shortcut.mnemonic} |")

        return "\n".join(lines)

    def _find_shortcut_by_key(
        self,
        layout_shortcuts: LayoutShortcuts,
        key: str,
    ) -> ShortcutAssignment | None:
        """Find shortcut by key."""
        for shortcut in layout_shortcuts.shortcuts:
            if shortcut.key.lower() == key.lower():
                return shortcut
        return None

    def _find_feature(self, manifest: FeatureManifest, feature_id: str):
        """Find feature by ID."""
        for feature in manifest.all_features():
            if feature.id == feature_id:
                return feature
        return None


class ComprehensiveGenerator:
    """Generate all output formats at once."""

    def __init__(self):
        self.vscode_gen = VSCodeKeybindingsGenerator()
        self.cli_gen = CLIAliasGenerator()
        self.markdown_gen = MarkdownDocGenerator()

    def generate_all(
        self,
        shortcuts: GeneratedShortcuts,
        output_dir: Path,
    ) -> dict[str, Path]:
        """Generate all output formats.

        Returns dict of format -> output path(s).
        """
        output_dir.mkdir(parents=True, exist_ok=True)
        generated = {}

        # VSCode keybindings (one per layout)
        keybindings_dir = output_dir / "keybindings"
        vscode_files = self.vscode_gen.generate(shortcuts, keybindings_dir)
        generated["vscode"] = vscode_files

        # CLI aliases
        aliases_file = output_dir / "aliases.sh"
        self.cli_gen.generate(shortcuts, aliases_file)
        generated["cli"] = aliases_file

        # Markdown documentation
        docs_file = output_dir / "KEYBOARD_SHORTCUTS.md"
        self.markdown_gen.generate(shortcuts, docs_file)
        generated["docs"] = docs_file

        return generated
