"""
TODO completion task creation utilities for Python code generation.

This module provides functionality for creating LLM tasks that automatically
complete TODO comments in Python source code. It leverages detailed code analysis
and LLM capabilities to generate contextually appropriate code completions.

The module contains the following main components:

* :func:`create_todo_completion_task` - Factory function for creating TODO completion tasks

.. note::
   This module requires a valid LLM model configuration to function properly.
   The TODO completion prompt template is loaded from 'todo_completion.j2'.

Example::

    >>> from hbllmutils.meta.code.todo_completion import create_todo_completion_task
    >>> from hbllmutils.model import load_llm_model
    >>> 
    >>> # Create a TODO completion task
    >>> model = load_llm_model('gpt-4')
    >>> task = create_todo_completion_task(
    ...     model=model,
    ...     show_module_directory_tree=True,
    ...     skip_when_error=False
    ... )
    >>> 
    >>> # Use the task to complete TODOs in a source file
    >>> completed_code = task.ask_then_parse(input_content='path/to/source.py')
    >>> print(completed_code)

"""

import os
import warnings
from typing import Optional, Iterable

from .task import PythonDetailedCodeGenerationLLMTask, PythonCodeGenerationLLMTask
from ...history import LLMHistory
from ...model import LLMModelTyping, load_llm_model
from ...template import PromptTemplate


def create_todo_completion_task(
        model: LLMModelTyping,
        show_module_directory_tree: bool = False,
        skip_when_error: bool = True,
        is_python_code: bool = True,
        force_ast_check: Optional[bool] = None,
        ignore_modules: Optional[Iterable[str]] = None,
        no_ignore_modules: Optional[Iterable[str]] = None
) -> PythonCodeGenerationLLMTask:
    """
    Create a configured LLM task for completing TODO comments in Python code.

    This factory function creates a specialized :class:`PythonDetailedCodeGenerationLLMTask`
    configured specifically for TODO completion. It loads the TODO completion prompt
    template from the module's resource files and initializes the task with appropriate
    settings for code generation.

    The created task will:
    
    - Analyze the source file and its dependencies
    - Identify TODO comments in the code
    - Generate appropriate code completions using the LLM
    - Validate the generated code for Python syntax correctness
    - Optionally display the module directory tree for context
    - Handle import errors gracefully based on skip_when_error setting

    The task uses a pre-defined system prompt from 'todo_completion.j2' that
    instructs the LLM on how to properly complete TODO comments while maintaining
    code quality, consistency, and adherence to existing patterns in the codebase.

    :param model: The LLM model to use for code generation. Can be:
        - A string representing the model name (e.g., 'gpt-4', 'claude-3')
        - An LLMModel instance for direct use
        - None to use the default model from configuration
    :type model: LLMModelTyping
    :param show_module_directory_tree: If True, include a directory tree visualization
        of the module structure in the analysis prompt. This provides additional
        context about the project structure to help the LLM understand the codebase
        organization. Defaults to False.
    :type show_module_directory_tree: bool
    :param skip_when_error: If True, skip imports that fail to load during dependency
        analysis and issue warnings instead of raising exceptions. This allows the
        task to proceed even when some dependencies are unavailable. Defaults to True.
    :type skip_when_error: bool
    :param is_python_code: If True, treat the input as Python code and perform Python-specific
        analysis and validation. If False, treat as generic code without Python-specific
        processing. Defaults to True.
    :type is_python_code: bool
    :param force_ast_check: If True, enforce Python AST validation on the generated
        code to ensure syntactic correctness. If None, defaults to True when is_python_code
        is True, and False otherwise. When is_python_code is False and force_ast_check is
        explicitly set to True, it will be ignored with a warning. Defaults to None.
    :type force_ast_check: Optional[bool]
    :param ignore_modules: Optional iterable of module names that should be explicitly ignored
        during dependency analysis regardless of download count or other criteria.
    :type ignore_modules: Optional[Iterable[str]]
    :param no_ignore_modules: Optional iterable of module names that should never be ignored
        during dependency analysis regardless of download count or other filtering criteria.
    :type no_ignore_modules: Optional[Iterable[str]]

    :return: A configured task instance ready to process Python source files and
        complete TODO comments. The task can be used by calling its ask_then_parse()
        method with a source file path.
    :rtype: PythonCodeGenerationLLMTask

    :raises FileNotFoundError: If the TODO completion prompt template file
        'todo_completion.j2' is not found in the module directory.
    :raises ValueError: If the model parameter is invalid or cannot be loaded.
    :raises TypeError: If model is not a string, LLMModel instance, or None.

    .. note::
       The TODO completion prompt template is loaded from 'todo_completion.j2'
       located in the same directory as this module. Ensure this file exists and
       contains valid prompt instructions for the LLM.

    .. note::
       When is_python_code is False, the task operates in generic code mode without
       Python-specific analysis or AST validation, making it suitable for other
       programming languages or text files with TODO comments.

    .. warning::
       When skip_when_error is False, the task will fail if any import dependencies
       cannot be resolved. Set to True for more robust operation with incomplete
       dependency information.

    .. warning::
       The quality of TODO completions depends heavily on the LLM model used.
       More capable models (e.g., GPT-4, Claude-3) typically produce better results
       than smaller models.

    .. warning::
       When is_python_code is False and force_ast_check is explicitly set to True,
       the AST check will be disabled and a warning will be logged, since AST
       validation is only applicable to Python code.

    Example::

        >>> from hbllmutils.meta.code.todo_completion import create_todo_completion_task
        >>> 
        >>> # Create task with default settings
        >>> task = create_todo_completion_task('gpt-4')
        >>> 
        >>> # Create task with full context and strict error handling
        >>> task = create_todo_completion_task(
        ...     model='gpt-4',
        ...     show_module_directory_tree=True,
        ...     skip_when_error=False,
        ...     force_ast_check=True
        ... )
        >>> 
        >>> # Process a source file with TODOs
        >>> completed_code = task.ask_then_parse(
        ...     input_content='myproject/module_with_todos.py'
        ... )
        >>> 
        >>> # Save the completed code
        >>> with open('myproject/module_completed.py', 'w') as f:
        ...     f.write(completed_code)
        >>> 
        >>> # Use with existing model instance
        >>> from hbllmutils.model import RemoteLLMModel
        >>> custom_model = RemoteLLMModel(
        ...     base_url='https://api.example.com',
        ...     api_token='your-token',
        ...     model_name='custom-model'
        ... )
        >>> task = create_todo_completion_task(
        ...     model=custom_model,
        ...     show_module_directory_tree=False
        ... )
        >>> 
        >>> # Process multiple files
        >>> source_files = [
        ...     'src/utils.py',
        ...     'src/models.py',
        ...     'src/views.py'
        ... ]
        >>> for source_file in source_files:
        ...     try:
        ...         completed = task.ask_then_parse(input_content=source_file)
        ...         with open(source_file, 'w') as f:
        ...             f.write(completed)
        ...         print(f"Completed TODOs in {source_file}")
        ...     except Exception as e:
        ...         print(f"Failed to process {source_file}: {e}")
        >>> 
        >>> # Process non-Python code files
        >>> task = create_todo_completion_task(
        ...     model='gpt-4',
        ...     is_python_code=False
        ... )
        >>> completed_js = task.ask_then_parse(input_content='src/app.js')
        >>> 
        >>> # Use ignore_modules and no_ignore_modules parameters
        >>> task = create_todo_completion_task(
        ...     model='gpt-4',
        ...     ignore_modules=['numpy', 'pandas'],
        ...     no_ignore_modules=['myproject.core']
        ... )

    """
    system_prompt_file = os.path.join(os.path.dirname(__file__), 'todo_completion.j2')
    system_prompt_template = PromptTemplate.from_file(system_prompt_file)
    system_prompt = system_prompt_template.render(is_python_code=is_python_code)

    if is_python_code:
        if force_ast_check is None:
            force_ast_check = True
    else:
        if force_ast_check is None:
            force_ast_check = False
        elif force_ast_check:
            warnings.warn(
                'force_ast_check is set to True but is_python_code is False. '
                'AST validation is only applicable to Python code. '
                'Ignoring force_ast_check and setting it to False.',
                UserWarning,
                stacklevel=2
            )
            force_ast_check = False

    return PythonDetailedCodeGenerationLLMTask(
        model=load_llm_model(model),
        code_name='Code For Task',
        description_text='This is the source code for you to complete the TODOs',
        history=LLMHistory().with_system_prompt(system_prompt),
        show_module_directory_tree=show_module_directory_tree,
        skip_when_error=skip_when_error,
        force_ast_check=force_ast_check,
        ignore_modules=ignore_modules,
        no_ignore_modules=no_ignore_modules,
    )
