"""Lesson 5: Dotfiles in ONA."""

from __future__ import annotations

from cde_onboard.lessons.base import BaseLesson
from cde_onboard.models import CodeBlock, LessonMeta, LessonStep, ScaffoldFile


class DotfilesLesson(BaseLesson):
    """Teaches creating a dotfiles repo, install scripts, and linking to ONA."""

    @classmethod
    def meta(cls) -> LessonMeta:
        return LessonMeta(
            id="dotfiles",
            number=5,
            title="Dotfiles",
            description="Personalize your ONA environment with a dotfiles repository.",
            overview="Create a dotfiles repo on GitLab, write an install script, link it to ONA, "
            "and learn best practices for non-interactive setup.",
        )

    def steps(self) -> list[LessonStep]:
        return [
            LessonStep(
                title="What Are Dotfiles?",
                explanation=(
                    "**Dotfiles** are configuration files (like `.bashrc`, `.gitconfig`, "
                    "`.vimrc`) that personalize your shell and tools. They're called 'dotfiles' "
                    "because they start with a dot.\n\n"
                    "In ONA, you can maintain a GitLab repository with your dotfiles. ONA will "
                    "clone them to `~/dotfiles` and apply them automatically to every new "
                    "environment."
                ),
                why=(
                    "Dotfiles ensure your terminal aliases, Git config, and editor preferences "
                    "are consistent across all ONA environments. Set them up once, use them "
                    "everywhere."
                ),
            ),
            LessonStep(
                title="Create Your Dotfiles Repository on GitLab",
                explanation=(
                    "**Before scaffolding files**, create a new repository on GitLab to store "
                    "your dotfiles:\n\n"
                    "1. Navigate to `https://gitlab.example.com`\n"
                    "2. Click **New Project** (top right)\n"
                    "3. Choose **Create blank project**\n"
                    "4. Project name: `dotfiles` (this is the standard convention)\n"
                    "5. Visibility: **Private** (recommended)\n"
                    "6. **Uncheck** 'Initialize repository with a README'\n"
                    "7. Click **Create project**\n\n"
                    "GitLab will show you the repository URL. Copy it—you'll need it next."
                ),
                code=CodeBlock(
                    language="bash",
                    source=(
                        "# Your dotfiles repository URL will look like:\n"
                        "https://gitlab.example.com/your-username/dotfiles.git"
                    ),
                ),
            ),
            LessonStep(
                title="Clone Your Repository Locally",
                explanation=(
                    "Now clone your empty dotfiles repository to your local machine:"
                ),
                code=CodeBlock(
                    language="bash",
                    source=(
                        "# Clone your dotfiles repository\n"
                        "git clone https://gitlab.example.com/your-username/dotfiles.git\n"
                        "cd dotfiles\n"
                        "\n"
                        "# Verify you're in an empty git repo\n"
                        "git status\n"
                        "# Should show: 'On branch main' with no files"
                    ),
                ),
                why=(
                    "Cloning first ensures you have a proper Git repository before adding files. "
                    "This prevents issues with git init and remote URL setup later."
                ),
            ),
            LessonStep(
                title="Repository Structure",
                explanation=(
                    "Your dotfiles repository will contain:\n\n"
                    "- **install.sh** — Auto-detected script that ONA runs to set up your dotfiles\n"
                    "- **.bashrc** — Shell configuration (aliases, prompt, etc.)\n"
                    "- **.gitconfig** — Git settings (name, email, aliases)\n"
                    "- **.vimrc** — Editor configuration (optional)\n\n"
                    "After adding files, the structure will look like:"
                ),
                code=CodeBlock(
                    language="bash",
                    source=(
                        "dotfiles/\n"
                        "├── install.sh      # Install script (auto-detected)\n"
                        "├── .bashrc         # Shell configuration\n"
                        "├── .gitconfig      # Git configuration\n"
                        "└── .vimrc          # Editor configuration (optional)"
                    ),
                ),
            ),
            LessonStep(
                title="The Install Script",
                explanation=(
                    "ONA looks for an install script in this priority order:\n\n"
                    "1. `install.sh`\n"
                    "2. `bootstrap.sh`\n"
                    "3. `setup.sh`\n\n"
                    "The script **must be non-interactive** — no prompts or user input. "
                    "It runs automatically during environment creation."
                ),
                code=CodeBlock(
                    language="bash",
                    source=(
                        "#!/usr/bin/env bash\n"
                        "set -euo pipefail\n"
                        "\n"
                        'DOTFILES_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"\n'
                        "\n"
                        'echo "Installing dotfiles from $DOTFILES_DIR..."\n'
                        "\n"
                        "for file in .bashrc .gitconfig; do\n"
                        '    if [ -f "$DOTFILES_DIR/$file" ]; then\n'
                        '        ln -sf "$DOTFILES_DIR/$file" "$HOME/$file"\n'
                        '        echo "  Linked $file"\n'
                        "    fi\n"
                        "done\n"
                        "\n"
                        'echo "Dotfiles installation complete!"'
                    ),
                    filename="install.sh",
                ),
                why=(
                    "Using symbolic links (`ln -sf`) is preferred over copying. This way, if "
                    "you update your dotfiles repo and rebuild, the changes are reflected "
                    "immediately without re-running the install script."
                ),
            ),
            LessonStep(
                title="Copy Scaffolded Files and Commit",
                explanation=(
                    "Now that you've scaffolded the sample dotfiles (click **Scaffold & Complete** "
                    "at the bottom if you haven't already), copy them into your cloned dotfiles "
                    "repository, make the install script executable, and push to GitLab."
                ),
                code=CodeBlock(
                    language="bash",
                    source=(
                        "# From your cloned dotfiles repo directory\n"
                        "cd ~/path/to/dotfiles  # or wherever you cloned it\n"
                        "\n"
                        "# Copy scaffolded files (adjust path to where you ran cde-onboard)\n"
                        "cp -R /path/to/cde-onboard-practice/lesson-05-dotfiles/dotfiles/. ./\n"
                        "\n"
                        "# Make install script executable\n"
                        "chmod +x install.sh\n"
                        "\n"
                        "# Commit and push to GitLab\n"
                        "git add .\n"
                        "git commit -m \"Add initial dotfiles and install script\"\n"
                        "git push origin main"
                    ),
                ),
                why=(
                    "The scaffolded files are templates. By copying them to your Git repository "
                    "and pushing to GitLab, they become available to ONA. You can customize them "
                    "further before committing."
                ),
            ),
            LessonStep(
                title="Linking Dotfiles to ONA",
                explanation=(
                    "Tell ONA where your dotfiles repository is (after pushing it to GitLab):"
                ),
                code=CodeBlock(
                    language="bash",
                    source=(
                        "# Set your dotfiles repository\n"
                        "gitpod user dotfiles set \\\n"
                        "  --repository https://gitlab.example.com/your-user/dotfiles.git\n"
                        "\n"
                        "# To apply changes, rebuild your environment:\n"
                        "gitpod environment devcontainer rebuild"
                    ),
                ),
                deep_dive=(
                    "ONA clones your dotfiles to `~/dotfiles` in the environment. The install "
                    "script is then executed from that directory.\n\n"
                    "Each user has **one** dotfiles repository. It's applied to all environments "
                    "created by that user.\n\n"
                    "If you need to test changes to your install script, use "
                    "`gitpod environment devcontainer rebuild` to rebuild the current environment "
                    "with the latest version."
                ),
            ),
            LessonStep(
                title="Testing & Verification",
                explanation=(
                    "Before pushing your dotfiles, test the install script:\n\n"
                    "**1. Test Install Script Locally**"
                ),
                code=CodeBlock(
                    language="bash",
                    source=(
                        "# From your dotfiles repo\n"
                        "cd ~/path/to/dotfiles\n"
                        "\n"
                        "# Test the install script in a safe way\n"
                        "bash -n install.sh  # Check syntax without running\n"
                        "\n"
                        "# Run it (will create symlinks in your home directory)\n"
                        "bash install.sh\n"
                        "\n"
                        "# Verify symlinks were created\n"
                        "ls -la ~ | grep -E '\\.bashrc|\\.gitconfig'"
                    ),
                ),
                deep_dive=(
                    "**2. Test in ONA Environment**\n\n"
                    "After linking dotfiles and rebuilding your environment:\n"
                    "```bash\n"
                    "# Check dotfiles were cloned\n"
                    "ls -la ~/dotfiles\n"
                    "\n"
                    "# Verify symlinks exist\n"
                    "ls -la ~ | grep -E '\\.bashrc|\\.gitconfig'\n"
                    "\n"
                    "# Test bashrc is active (if you added aliases)\n"
                    "alias  # Should show your custom aliases\n"
                    "\n"
                    "# Verify gitconfig is active\n"
                    "git config --list | grep -E 'user\\.name|user\\.email'\n"
                    "```\n\n"
                    "**Expected Success Indicators:**\n"
                    "- ✓ Dotfiles cloned to ~/dotfiles\n"
                    "- ✓ Install script ran without errors\n"
                    "- ✓ Symlinks created in home directory\n"
                    "- ✓ Shell aliases and git config active\n\n"
                    "**Common Issues:**\n"
                    "- Install script fails → Test locally first, check for syntax errors\n"
                    "- Symlinks not created → Check file paths in install script\n"
                    "- Changes not applied → Rebuild environment to rerun install script\n"
                    "- Repo not found → Verify dotfiles repository URL is correct"
                ),
            ),
            LessonStep(
                title="Best Practices",
                explanation=(
                    "Tips for effective dotfiles:\n\n"
                    "- Keep the install script **non-interactive** (no `read` or `select`)\n"
                    "- Use `set -euo pipefail` for safety\n"
                    "- Check if files exist before linking (`if [ -f ... ]`)\n"
                    "- Use `ln -sf` (force) to overwrite existing files\n"
                    "- Don't include secrets in your dotfiles repo\n"
                    "- Test your install script locally before pushing\n"
                    "- Consider backing up existing files before overwriting\n\n"
                    "Click **Scaffold & Complete** at the bottom to create sample dotfiles, then "
                    "follow the copy instructions from the previous step."
                ),
            ),
        ]

    def scaffold_files(self) -> list[ScaffoldFile]:
        return [
            ScaffoldFile(
                relative_path="dotfiles/install.sh",
                template_name="dotfiles_install.sh",
                description="Non-interactive install script that symlinks dotfiles.",
            ),
            ScaffoldFile(
                relative_path="dotfiles/.bashrc",
                template_name="dotfiles_bashrc",
                description="Sample .bashrc with aliases and prompt customization.",
            ),
            ScaffoldFile(
                relative_path="dotfiles/.gitconfig",
                template_name="dotfiles_gitconfig",
                description="Sample .gitconfig with useful aliases and defaults.",
            ),
        ]
