"""External editor integration for template content editing.

Opens the user's preferred $EDITOR to edit template content,
with fallback to common terminal editors.
"""

import os
import shutil
import subprocess
import tempfile
from pathlib import Path


class EditorError(Exception):
    """Raised when editor operations fail."""


def get_editor() -> str:
    """Get the user's preferred editor.

    Checks in order:
    1. $EDITOR environment variable
    2. $VISUAL environment variable
    3. Common editors on PATH (nano, vim, vi)

    Returns:
        Path/name of editor to use

    Raises:
        EditorError: If no suitable editor is found
    """
    # Check environment variables first
    editor = os.environ.get("EDITOR") or os.environ.get("VISUAL")
    if editor:
        return editor

    # Fall back to common editors
    for fallback in ("nano", "vim", "vi"):
        if shutil.which(fallback):
            return fallback

    raise EditorError(
        "No editor found. Set $EDITOR environment variable or install nano/vim."
    )


def open_editor(initial_content: str = "") -> str | None:
    """Open the user's editor with optional initial content.

    Creates a temporary file, opens it in the editor, waits for the editor
    to close, then reads and returns the file content.

    Args:
        initial_content: Initial content to populate the file with

    Returns:
        The edited content from the file, or None if the editor failed
        or the user quit without saving.

    Raises:
        EditorError: If no editor is available
    """
    editor = get_editor()

    # Create temp file with .jinja2 extension for syntax highlighting
    with tempfile.NamedTemporaryFile(
        mode="w",
        suffix=".jinja2",
        delete=False,
    ) as f:
        f.write(initial_content)
        temp_path = Path(f.name)

    try:
        # Get file modification time before editing
        mtime_before = temp_path.stat().st_mtime

        # Open editor and wait for it to close
        # Shell=False for security, but we need to handle editor args
        editor_parts = editor.split()
        cmd = editor_parts + [str(temp_path)]

        result = subprocess.call(cmd)

        if result != 0:
            return None

        # Check if file was modified
        mtime_after = temp_path.stat().st_mtime
        if mtime_after == mtime_before:
            # File wasn't modified - could mean user quit without saving
            # Still return content in case they just didn't change anything
            pass

        # Read the edited content
        content = temp_path.read_text()
        return content

    finally:
        # Clean up temp file
        try:
            temp_path.unlink()
        except OSError:
            pass  # Best effort cleanup


def open_editor_with_hints(initial_content: str = "") -> str | None:
    """Open editor with helpful comments about macro syntax.

    Adds instructional comments at the top of the file that explain
    the macro syntax. These comments are stripped from the final output.

    Args:
        initial_content: Initial content to populate the file with

    Returns:
        The edited content with hint comments removed, or None if failed
    """
    # Only show hints when content is empty
    if initial_content:
        full_content = initial_content
    else:
        hints = """@fragment(name) - Include fragment
@text(name) - Insert text from a content part
@json(name) - Insert JSON from a content part
@schema(name) - Reference a schema
{{ var }} - Variable interpolation
"""
        full_content = hints

    result = open_editor(full_content)

    if result is None:
        return None

    # Don't strip comments - let user decide what to keep
    # They're valid Jinja2 comments anyway
    return result
