from aider.tools.utils.base_tool import BaseTool
from aider.tools.utils.helpers import (
    ToolError,
    format_tool_result,
    generate_unified_diff_snippet,
    handle_tool_error,
)
from aider.tools.utils.output import tool_body_unwrapped, tool_footer, tool_header


class Tool(BaseTool):
    NORM_NAME = "updatetodolist"
    SCHEMA = {
        "type": "function",
        "function": {
            "name": "UpdateTodoList",
            "description": "Update the todo list with new items or modify existing ones.",
            "parameters": {
                "type": "object",
                "properties": {
                    "content": {
                        "type": "string",
                        "description": "The new content for the todo list.",
                    },
                    "append": {
                        "type": "boolean",
                        "description": (
                            "Whether to append to existing content instead of replacing it."
                            " Defaults to False."
                        ),
                    },
                    "change_id": {
                        "type": "string",
                        "description": "Optional change ID for tracking.",
                    },
                    "dry_run": {
                        "type": "boolean",
                        "description": (
                            "Whether to perform a dry run without actually updating the file."
                            " Defaults to False."
                        ),
                    },
                },
                "required": ["content"],
            },
        },
    }

    @classmethod
    def execute(cls, coder, content, append=False, change_id=None, dry_run=False):
        """
        Update the todo list file (.aider.todo.txt) with new content.
        Can either replace the entire content or append to it.
        """
        tool_name = "UpdateTodoList"
        try:
            # Define the todo file path
            todo_file_path = ".aider.todo.txt"
            abs_path = coder.abs_root_path(todo_file_path)

            # Get existing content if appending
            existing_content = ""
            import os

            if os.path.isfile(abs_path):
                existing_content = coder.io.read_text(abs_path) or ""

            # Prepare new content
            if append:
                if existing_content and not existing_content.endswith("\n"):
                    existing_content += "\n"
                new_content = existing_content + content
            else:
                new_content = content

            # Check if content exceeds 4096 characters and warn
            if len(new_content) > 4096:
                coder.io.tool_warning(
                    "⚠️ Todo list content exceeds 4096 characters. Consider summarizing the plan"
                    " before proceeding."
                )

            # Check if content actually changed
            if existing_content == new_content:
                coder.io.tool_warning("No changes made: new content is identical to existing")
                return "Warning: No changes made (content identical to existing)"

            # Generate diff for feedback
            diff_snippet = generate_unified_diff_snippet(
                existing_content, new_content, todo_file_path
            )

            # Handle dry run
            if dry_run:
                action = "append to" if append else "replace"
                dry_run_message = f"Dry run: Would {action} todo list in {todo_file_path}."
                return format_tool_result(
                    coder,
                    tool_name,
                    "",
                    dry_run=True,
                    dry_run_message=dry_run_message,
                    diff_snippet=diff_snippet,
                )

            # Apply change
            metadata = {
                "append": append,
                "existing_length": len(existing_content),
                "new_length": len(new_content),
            }

            # Write the file directly since it's a special file
            coder.io.write_text(abs_path, new_content)

            # Track the change
            final_change_id = coder.change_tracker.track_change(
                file_path=todo_file_path,
                change_type="updatetodolist",
                original_content=existing_content,
                new_content=new_content,
                metadata=metadata,
                change_id=change_id,
            )

            coder.aider_edited_files.add(todo_file_path)

            # Format and return result
            action = "appended to" if append else "updated"
            success_message = f"Successfully {action} todo list in {todo_file_path}"
            return format_tool_result(
                coder,
                tool_name,
                success_message,
                change_id=final_change_id,
                diff_snippet=diff_snippet,
            )

        except ToolError as e:
            return handle_tool_error(coder, tool_name, e, add_traceback=False)
        except Exception as e:
            return handle_tool_error(coder, tool_name, e)

    @classmethod
    def format_output(cls, coder, mcp_server, tool_response):
        tool_header(coder=coder, mcp_server=mcp_server, tool_response=tool_response)
        tool_body_unwrapped(coder=coder, tool_response=tool_response)
        tool_footer(coder=coder, tool_response=tool_response)
