from cecli.tools.utils.base_tool import BaseTool
from cecli.tools.utils.helpers import (
    ToolError,
    apply_change,
    format_tool_result,
    handle_tool_error,
    validate_file_for_edit,
)


class Tool(BaseTool):
    NORM_NAME = "deletelines"
    SCHEMA = {
        "type": "function",
        "function": {
            "name": "DeleteLines",
            "description": "Delete a range of lines from a file.",
            "parameters": {
                "type": "object",
                "properties": {
                    "file_path": {"type": "string"},
                    "start_line": {"type": "integer"},
                    "end_line": {"type": "integer"},
                    "change_id": {"type": "string"},
                    "dry_run": {"type": "boolean", "default": False},
                },
                "required": ["file_path", "start_line", "end_line"],
            },
        },
    }

    @classmethod
    def execute(cls, coder, file_path, start_line, end_line, change_id=None, dry_run=False):
        """
        Delete a range of lines (1-based, inclusive).

        Parameters:
        - coder: The Coder instance
        - file_path: Path to the file to modify
        - start_line: The 1-based starting line number to delete
        - end_line: The 1-based ending line number to delete
        - change_id: Optional ID for tracking the change
        - dry_run: If True, simulate the change without modifying the file

        Returns a result message.
        """
        tool_name = "DeleteLines"
        try:
            # 1. Validate file and get content
            abs_path, rel_path, original_content = validate_file_for_edit(coder, file_path)
            lines = original_content.splitlines()

            # Validate line numbers
            try:
                start_line_int = int(start_line)
                end_line_int = int(end_line)

                if start_line_int < 1 or start_line_int > len(lines):
                    raise ToolError(f"Start line {start_line_int} is out of range (1-{len(lines)})")
                if end_line_int < 1 or end_line_int > len(lines):
                    raise ToolError(f"End line {end_line_int} is out of range (1-{len(lines)})")
                if start_line_int > end_line_int:
                    raise ToolError(
                        f"Start line {start_line_int} cannot be after end line {end_line_int}"
                    )

                start_idx = start_line_int - 1  # Convert to 0-based index
                end_idx = end_line_int - 1  # Convert to 0-based index
            except ValueError:
                raise ToolError(
                    f"Invalid line numbers: '{start_line}', '{end_line}'. Must be integers."
                )

            # Prepare the deletion
            deleted_lines = lines[start_idx : end_idx + 1]
            new_lines = lines[:start_idx] + lines[end_idx + 1 :]
            new_content = "\n".join(new_lines)

            if original_content == new_content:
                coder.io.tool_warning(
                    f"No changes made: deleting lines {start_line_int}-{end_line_int} would not"
                    " change file"
                )
                return (
                    "Warning: No changes made (deleting lines"
                    f" {start_line_int}-{end_line_int} would not change file)"
                )

            # Handle dry run
            if dry_run:
                dry_run_message = (
                    f"Dry run: Would delete lines {start_line_int}-{end_line_int} in {file_path}"
                )
                return format_tool_result(
                    coder,
                    tool_name,
                    "",
                    dry_run=True,
                    dry_run_message=dry_run_message,
                )

            # --- Apply Change (Not dry run) ---
            metadata = {
                "start_line": start_line_int,
                "end_line": end_line_int,
                "deleted_content": "\n".join(deleted_lines),
            }

            final_change_id = apply_change(
                coder,
                abs_path,
                rel_path,
                original_content,
                new_content,
                "deletelines",
                metadata,
                change_id,
            )

            coder.files_edited_by_tools.add(rel_path)
            num_deleted = end_idx - start_idx + 1
            # Format and return result
            success_message = (
                f"Deleted {num_deleted} lines ({start_line_int}-{end_line_int}) in {file_path}"
            )
            return format_tool_result(
                coder,
                tool_name,
                success_message,
                change_id=final_change_id,
            )

        except ToolError as e:
            # Handle errors raised by utility functions (expected errors)
            return handle_tool_error(coder, tool_name, e, add_traceback=False)
        except Exception as e:
            # Handle unexpected errors
            return handle_tool_error(coder, tool_name, e)
