"""Lesson 1: Dev Container Basics."""

from __future__ import annotations

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


class DevcontainerLesson(BaseLesson):
    """Teaches devcontainer.json structure, base images, features, and lifecycle commands."""

    @classmethod
    def meta(cls) -> LessonMeta:
        return LessonMeta(
            id="devcontainer-basics",
            number=1,
            title="Dev Container Basics",
            description="Learn to configure .devcontainer/devcontainer.json for ONA environments.",
            overview="Understand devcontainer.json structure, choose base images, add features, "
            "configure VS Code extensions, and set up lifecycle commands.",
        )

    def steps(self) -> list[LessonStep]:
        return [
            LessonStep(
                title="What is a Dev Container?",
                explanation=(
                    "A **dev container** defines your development environment as code. "
                    "ONA uses the open Dev Container specification to configure reproducible "
                    "environments. The configuration lives in `.devcontainer/devcontainer.json` "
                    "at the root of your repository."
                ),
                why=(
                    "Dev containers eliminate 'works on my machine' problems. Every engineer "
                    "gets the exact same environment — same OS, same tools, same versions."
                ),
            ),
            LessonStep(
                title="Choosing a Base Image",
                explanation=(
                    "Every devcontainer starts with a base Docker image. Microsoft provides "
                    "official images optimized for dev containers."
                ),
                code=CodeBlock(
                    language="json",
                    source='{\n  "image": "mcr.microsoft.com/devcontainers/base:ubuntu"\n}',
                    filename="devcontainer.json",
                ),
                deep_dive=(
                    "Common base images:\n\n"
                    "- `mcr.microsoft.com/devcontainers/base:ubuntu` — General purpose\n"
                    "- `mcr.microsoft.com/devcontainers/python:3.11` — Python-focused\n"
                    "- `mcr.microsoft.com/devcontainers/javascript-node:20` — Node.js-focused\n"
                    "- `mcr.microsoft.com/devcontainers/typescript-node:20` — TypeScript + Node\n\n"
                    "You can also use any Docker image, but the Microsoft images include "
                    "dev container tooling pre-installed."
                ),
            ),
            LessonStep(
                title="Adding Features",
                explanation=(
                    "**Features** add tools and runtimes to your container without writing "
                    "Dockerfiles. They're modular, composable, and maintained by the community."
                ),
                code=CodeBlock(
                    language="json",
                    source=(
                        '{\n'
                        '  "features": {\n'
                        '    "ghcr.io/devcontainers/features/node:1": {\n'
                        '      "version": "20"\n'
                        '    },\n'
                        '    "ghcr.io/devcontainers/features/python:1": {\n'
                        '      "version": "3.11"\n'
                        '    }\n'
                        '  }\n'
                        '}'
                    ),
                    filename="devcontainer.json",
                ),
                why=(
                    "Features are better than manually installing tools in a Dockerfile. "
                    "They're versioned, cacheable, and handle OS-level dependencies automatically."
                ),
            ),
            LessonStep(
                title="Editor Extensions",
                explanation=(
                    "You can pre-install VS Code extensions so they're available the moment "
                    "the environment starts. Extensions are specified by their marketplace ID."
                ),
                code=CodeBlock(
                    language="json",
                    source=(
                        '{\n'
                        '  "customizations": {\n'
                        '    "vscode": {\n'
                        '      "extensions": [\n'
                        '        "esbenp.prettier-vscode",\n'
                        '        "dbaeumer.vscode-eslint",\n'
                        '        "ms-python.python"\n'
                        '      ],\n'
                        '      "settings": {\n'
                        '        "editor.formatOnSave": true\n'
                        '      }\n'
                        '    }\n'
                        '  }\n'
                        '}'
                    ),
                    filename="devcontainer.json",
                ),
            ),
            LessonStep(
                title="Lifecycle Commands",
                explanation=(
                    "Lifecycle commands run at different stages of container creation:\n\n"
                    "- **onCreateCommand**: Runs once when the container is first created "
                    "(e.g., clone repos, install global tools)\n"
                    "- **postCreateCommand**: Runs after creation and after rebuilds "
                    "(e.g., install dependencies)\n"
                    "- **postStartCommand**: Runs every time the container starts "
                    "(e.g., start dev servers)"
                ),
                code=CodeBlock(
                    language="json",
                    source=(
                        '{\n'
                        '  "onCreateCommand": "echo \'Environment created!\'",\n'
                        '  "postCreateCommand": "npm install",\n'
                        '  "postStartCommand": "echo \'Ready to code!\'"\n'
                        '}'
                    ),
                    filename="devcontainer.json",
                ),
                why=(
                    "Understanding lifecycle timing is critical. `onCreateCommand` is for "
                    "one-time setup, `postCreateCommand` for dependency installs that "
                    "should also run on rebuild, and `postStartCommand` for commands that "
                    "should run every session."
                ),
            ),
            LessonStep(
                title="Full Example",
                explanation=(
                    "Here's a complete `devcontainer.json` combining everything you've learned. "
                    "Click **Scaffold & Complete** below to create this file in your practice "
                    "directory."
                ),
                code=CodeBlock(
                    language="json",
                    source=(
                        '{\n'
                        '  "name": "My ONA Environment",\n'
                        '  "image": "mcr.microsoft.com/devcontainers/base:ubuntu",\n'
                        '  "features": {\n'
                        '    "ghcr.io/devcontainers/features/node:1": { "version": "20" },\n'
                        '    "ghcr.io/devcontainers/features/python:1": { "version": "3.11" }\n'
                        '  },\n'
                        '  "customizations": {\n'
                        '    "vscode": {\n'
                        '      "extensions": [\n'
                        '        "esbenp.prettier-vscode",\n'
                        '        "dbaeumer.vscode-eslint",\n'
                        '        "ms-python.python"\n'
                        '      ]\n'
                        '    }\n'
                        '  },\n'
                        '  "onCreateCommand": "echo \'Environment created!\'",\n'
                        '  "postCreateCommand": "npm install",\n'
                        '  "postStartCommand": "echo \'Ready to code!\'"\n'
                        '}'
                    ),
                    filename=".devcontainer/devcontainer.json",
                ),
            ),
            LessonStep(
                title="Testing & Verification",
                explanation=(
                    "Before pushing to GitLab, verify your `devcontainer.json` is correct:\n\n"
                    "**1. Validate JSON Syntax**"
                ),
                code=CodeBlock(
                    language="bash",
                    source=(
                        "# Check for JSON syntax errors\n"
                        "cat .devcontainer/devcontainer.json | jq .\n"
                        "# If valid, you'll see formatted JSON output"
                    ),
                ),
                deep_dive=(
                    "**2. Test in ONA Dashboard**\n\n"
                    "After pushing your config:\n"
                    "1. Go to the ONA dashboard (https://ona.example.com)\n"
                    "2. Click **New Environment**\n"
                    "3. Enter your repository URL\n"
                    "4. Watch the build logs for errors\n\n"
                    "**Expected Success Indicators:**\n"
                    "- ✓ Build completes without errors\n"
                    "- ✓ VS Code Browser opens successfully\n"
                    "- ✓ Extensions are installed (check Extensions panel)\n"
                    "- ✓ Terminal shows `/workspaces/<your-repo>/`\n"
                    "- ✓ Run `node --version` and `python --version` to verify features\n\n"
                    "**Common Issues:**\n"
                    "- JSON syntax errors → Use `jq` to validate\n"
                    "- Base image typo → Check image name spelling\n"
                    "- Feature version mismatch → Verify version exists\n"
                    "- Extension not loading → Check if it supports browser VS Code"
                ),
            ),
            LessonStep(
                title="Apply to Your Repository",
                explanation=(
                    "Scaffolding creates files under "
                    "`./cde-onboard-practice/lesson-01-devcontainer-basics/`. "
                    "Copy the `.devcontainer` folder into your actual repo, then commit it."
                ),
                code=CodeBlock(
                    language="bash",
                    source=(
                        "# From your repo root\n"
                        "cp -R cde-onboard-practice/lesson-01-devcontainer-basics/.devcontainer ./\n"
                        "git add .devcontainer/devcontainer.json\n"
                        "git commit -m \"Add devcontainer config\"\n"
                        "git push"
                    ),
                ),
            ),
        ]

    def scaffold_files(self) -> list[ScaffoldFile]:
        return [
            ScaffoldFile(
                relative_path=".devcontainer/devcontainer.json",
                template_name="devcontainer_basic.json",
                description="Basic devcontainer.json with base image, features, and lifecycle commands.",
            ),
        ]
