"""Generate devcontainer.json for existing containers and specs.

This module provides utilities to generate devcontainer.json files from
existing gaol containers or specification files.
"""

from __future__ import annotations

from pathlib import Path
from typing import Any

from gaol.devcontainer.converter import DevcontainerConverter
from gaol.devcontainer.loader import DevcontainerLoader
from gaol.devcontainer.models import (
    DevcontainerCustomizations,
    DevcontainerSpec,
    DevcontainerVSCodeCustomizations,
)
from gaol.specs.loader import SpecLoader
from gaol.specs.models import ContainerSpec
from gaol.store import ContainerStore, get_container_store


class DevcontainerGenerator:
    """Generate devcontainer.json for existing containers.

    This class provides methods to generate devcontainer.json files from:
    - Stored container configurations
    - Gaol spec files (YAML/TOML)
    - Minimal parameters for quick setup
    """

    def __init__(
        self,
        store: ContainerStore | None = None,
        converter: DevcontainerConverter | None = None,
    ):
        """Initialize generator.

        Args:
            store: ContainerStore for reading container configs.
            converter: Converter for format translation.
        """
        self.store = store or get_container_store()
        self.converter = converter or DevcontainerConverter()

    def generate_for_container(
        self,
        container_name: str,
        vscode_extensions: list[str] | None = None,
        post_create_command: str | list[str] | None = None,
        remote_user: str | None = None,
    ) -> DevcontainerSpec:
        """Generate devcontainer.json from stored container config.

        Args:
            container_name: Name of the container in the store.
            vscode_extensions: Additional VS Code extensions to include.
            post_create_command: Command to run after container creation.
            remote_user: Remote user for VS Code operations.

        Returns:
            Generated DevcontainerSpec.

        Raises:
            ValueError: If container not found in store.
        """
        stored = self.store.get(container_name)
        if stored is None:
            raise ValueError(f"Container '{container_name}' not found in store")

        # Convert ContainerConfig to ContainerSpec first
        spec = ContainerSpec.from_container_config(stored.config)

        return self.converter.from_container_spec(
            spec,
            vscode_extensions=vscode_extensions,
            post_create_command=post_create_command,
            remote_user=remote_user,
        )

    def generate_for_spec(
        self,
        spec_path: Path,
        vscode_extensions: list[str] | None = None,
        post_create_command: str | list[str] | None = None,
        remote_user: str | None = None,
    ) -> DevcontainerSpec:
        """Generate devcontainer.json from a gaol spec file.

        Args:
            spec_path: Path to the YAML/TOML spec file.
            vscode_extensions: Additional VS Code extensions to include.
            post_create_command: Command to run after container creation.
            remote_user: Remote user for VS Code operations.

        Returns:
            Generated DevcontainerSpec.
        """
        loader = SpecLoader()
        spec = loader.load(spec_path)

        return self.converter.from_container_spec(
            spec,
            vscode_extensions=vscode_extensions,
            post_create_command=post_create_command,
            remote_user=remote_user,
        )

    def generate_minimal(
        self,
        image: str,
        name: str | None = None,
        forward_ports: list[int] | None = None,
        vscode_extensions: list[str] | None = None,
        post_create_command: str | list[str] | None = None,
        workspace_folder: str = "/workspace",
    ) -> DevcontainerSpec:
        """Generate a minimal devcontainer.json.

        Args:
            image: Container image to use.
            name: Display name for the container.
            forward_ports: Ports to forward.
            vscode_extensions: VS Code extensions to include.
            post_create_command: Command to run after creation.
            workspace_folder: Default workspace folder path.

        Returns:
            Minimal DevcontainerSpec.
        """
        customizations = DevcontainerCustomizations()
        if vscode_extensions:
            customizations = DevcontainerCustomizations(
                vscode=DevcontainerVSCodeCustomizations(extensions=vscode_extensions)
            )

        return DevcontainerSpec(
            name=name,
            image=image,
            forward_ports=forward_ports or [],
            workspace_folder=workspace_folder,
            post_create_command=post_create_command,
            customizations=customizations,
        )

    def generate_for_profile(
        self,
        profile: str,
        name: str | None = None,
        image: str | None = None,
    ) -> DevcontainerSpec:
        """Generate devcontainer.json for a gaol profile.

        Creates a devcontainer configuration suitable for a specific
        development profile (e.g., dev-python, dev-node).

        Args:
            profile: Gaol profile name.
            name: Display name for the container.
            image: Override image (uses profile default otherwise).

        Returns:
            DevcontainerSpec configured for the profile.
        """
        # Default images for profiles
        profile_images: dict[str, str] = {
            "dev-python": "python:3.11",
            "dev-node": "node:20",
            "dev-rust": "rust:latest",
            "dev-go": "golang:1.22",
            "dev-java": "eclipse-temurin:21",
            "dev-cpp": "gcc:14",
            "dev-dotnet": "mcr.microsoft.com/dotnet/sdk:8.0",
            "base": "debian:bookworm",
        }

        # Default extensions for profiles
        profile_extensions: dict[str, list[str]] = {
            "dev-python": [
                "ms-python.python",
                "ms-python.pylint",
                "charliermarsh.ruff",
            ],
            "dev-node": [
                "dbaeumer.vscode-eslint",
                "esbenp.prettier-vscode",
            ],
            "dev-rust": [
                "rust-lang.rust-analyzer",
                "serayuzgur.crates",
            ],
            "dev-go": [
                "golang.go",
            ],
            "dev-java": [
                "vscjava.vscode-java-pack",
            ],
            "dev-cpp": [
                "ms-vscode.cpptools",
                "ms-vscode.cmake-tools",
            ],
            "dev-dotnet": [
                "ms-dotnettools.csharp",
                "ms-dotnettools.csdevkit",
            ],
        }

        # Default post-create commands
        profile_commands: dict[str, str] = {
            "dev-python": "pip install --upgrade pip",
            "dev-node": "npm install",
            "dev-rust": "cargo fetch 2>/dev/null || true",
            "dev-go": "go mod download 2>/dev/null || true",
        }

        container_image = image or profile_images.get(profile, "debian:bookworm")
        container_name = name or f"{profile}-dev"
        extensions = profile_extensions.get(profile, [])
        post_create = profile_commands.get(profile)

        return self.generate_minimal(
            image=container_image,
            name=container_name,
            vscode_extensions=extensions,
            post_create_command=post_create,
        )


def generate_devcontainer(
    container_name: str | None = None,
    spec_path: Path | None = None,
    image: str | None = None,
    output_dir: Path | None = None,
    vscode_extensions: list[str] | None = None,
    post_create_command: str | list[str] | None = None,
) -> Path:
    """Generate and save devcontainer.json.

    This is a convenience function that generates a devcontainer.json file
    from various sources and saves it to the specified location.

    Args:
        container_name: Generate from stored container config.
        spec_path: Generate from gaol spec file.
        image: Generate minimal config with this image.
        output_dir: Output directory (default: .devcontainer/).
        vscode_extensions: Additional VS Code extensions.
        post_create_command: Post-create command.

    Returns:
        Path to the saved devcontainer.json.

    Raises:
        ValueError: If no valid source is provided.
    """
    generator = DevcontainerGenerator()

    if container_name:
        spec = generator.generate_for_container(
            container_name,
            vscode_extensions=vscode_extensions,
            post_create_command=post_create_command,
        )
    elif spec_path:
        spec = generator.generate_for_spec(
            spec_path,
            vscode_extensions=vscode_extensions,
            post_create_command=post_create_command,
        )
    elif image:
        spec = generator.generate_minimal(
            image,
            vscode_extensions=vscode_extensions,
            post_create_command=post_create_command,
        )
    else:
        raise ValueError(
            "Must provide one of: container_name, spec_path, or image"
        )

    # Save to file
    output_path = output_dir or Path(".devcontainer")
    loader = DevcontainerLoader()
    return loader.save(spec, output_path / "devcontainer.json")
