<?php
namespace boru\boruai\Models\Functions;

use boru\boruai\Models\ToolDefinition;
use boru\boruai\Tools\CodeManager;
use boru\boruai\Tools\Util;
use boru\output\Output;

class Code extends FunctionBase {
    private static $CodeManager;

    public static function init($rootDirectory=null) {
        if(!static::$CodeManager) {
            if($rootDirectory) {
                static::$CodeManager = new CodeManager($rootDirectory);
            } else {
                static::$CodeManager = new CodeManager(getcwd());
            }

        }
        if(static::debug()) {
            Output::outLine(static::class."::init()");
        }
    }
    
    public static function functionDefinitions() {
        $return = [];

        $toolDefinition = new ToolDefinition();
        $toolDefinition->name("get_class_code");
        $toolDefinition->description("This function will return the contents of the class file for the specified class, and sohuld be used to ensure you are referencing the code correctly.");
        $toolDefinition->addString("class", "The class name to get the code for.");
        $toolDefinition->register(function($args) {
            return static::callback("getClassCode",$args);
        });
        $return[] = $toolDefinition;

        // Example for "listFiles"
        $toolDefinition = new ToolDefinition();
        $toolDefinition->name("listFiles");
        $toolDefinition->description("List all files within a given directory in the project root.");
        $toolDefinition->addString("path", "Path relative to the project root. Leave empty for root.");
        $toolDefinition->addBool("recursive", "If true, recurse into subdirectories.");
        $toolDefinition->register(function($args) {
            return static::callback("listFiles",$args);
        });
        $return[] = $toolDefinition;

        // Example for "listDirectories"
        $toolDefinition = new ToolDefinition();
        $toolDefinition->name("listDirectories");
        $toolDefinition->description("List all directories within a given directory in the project root.");
        $toolDefinition->addString("path", "Path relative to the project root. Leave empty for root.");
        $toolDefinition->addBool("recursive", "If true, recurse into subdirectories.");
        $toolDefinition->register(function($args) {
            return static::callback("listDirectories",$args);
        });
        $return[] = $toolDefinition;

        // Example for "getFileContent"
        $toolDefinition = new ToolDefinition();
        $toolDefinition->name("getFileContent");
        $toolDefinition->description("Retrieve the contents of a file as a string.");
        $toolDefinition->addString("filePath", "Path relative to the project root.");
        $toolDefinition->register(function($args) {
            return static::callback("getFileContent",$args);
        });
        $return[] = $toolDefinition;

        // Example for "putFileContent"
        $toolDefinition = new ToolDefinition();
        $toolDefinition->name("putFileContent");
        $toolDefinition->description("Write content to a file, overwriting existing content if present.");
        $toolDefinition->addString("filePath", "Path relative to the project root.");
        $toolDefinition->addString("content", "The content to write to the file.");
        $toolDefinition->register(function($args) {
            return static::callback("putFileContent",$args);
        });
        $return[] = $toolDefinition;

        // Example for "appendFileContent"
        $toolDefinition = new ToolDefinition();
        $toolDefinition->name("appendFileContent");
        $toolDefinition->description("Append content to a file, creating it if it does not exist.");
        $toolDefinition->addString("filePath", "Path relative to the project root.");
        $toolDefinition->addString("content", "The content to append.");
        $toolDefinition->register(function($args) {
            return static::callback("appendFileContent",$args);
        });
        $return[] = $toolDefinition;

        // Example for "deleteFile"
        $toolDefinition = new ToolDefinition();
        $toolDefinition->name("deleteFile");
        $toolDefinition->description("Delete a file from the project.");
        $toolDefinition->addString("filePath", "Path to the file to delete, relative to the project root.");
        $toolDefinition->register(function($args) {
            return static::callback("deleteFile",$args);
        });
        $return[] = $toolDefinition;

        // Example for "searchInFiles"
        $toolDefinition = new ToolDefinition();
        $toolDefinition->name("searchInFiles");
        $toolDefinition->description("Search for a pattern in all files within a directory.");
        $toolDefinition->addString("pattern", "A PCRE pattern to search for (e.g., '/function\\s+(\\w+)/').");
        $toolDefinition->addString("path", "Directory path relative to the project root. Leave empty for root.");
        $toolDefinition->addBool("recursive", "Whether to search recursively.");
        $toolDefinition->register(function($args) {
            return static::callback("searchInFiles",$args);
        });
        $return[] = $toolDefinition;

        // Example for "ensureDirectoryExists"
        $toolDefinition = new ToolDefinition();
        $toolDefinition->name("ensureDirectoryExists");
        $toolDefinition->description("Ensure a directory exists, creating it if necessary.");
        $toolDefinition->addString("path", "Path relative to the project root.");
        $toolDefinition->addInteger("mode", "Permissions for newly created directories (e.g., 0777).");
        $toolDefinition->register(function($args) {
            return static::callback("ensureDirectoryExists",$args);
        });
        $return[] = $toolDefinition;

        $toolDefinition = new ToolDefinition();
        $toolDefinition->name("listClassesInNamespace");
        $toolDefinition->description("List all classes in a given namespace. Useful to get an overview of the classes available in a namespace, and to get an overview of the project structure.");
        $toolDefinition->addString("namespace", "The namespace to search.");
        $toolDefinition->addBool("recursive", "If true, recurse into subnamespaces.");
        $toolDefinition->register(function($args) {
            return static::callback("listClassesInNamespace",$args);
        });
        $return[] = $toolDefinition;
        
        return $return;
    }

    public static function getClassCode($args) {
        $class = $args->get("class");
        static::statusUpdate("Getting code for class: $class");
        return Util::getClassFileContents($class);
    }

    public static function listFiles($args) {
        static::init();
        $path = $args->get("path","");
        $recursive = $args->get("recursive",false);
        static::statusUpdate("Listing files in $path");
        try {
            return static::$CodeManager->listFiles($path,$recursive);
        } catch(\Exception $e) {
            return $e->getMessage();
        }
    }

    public static function listDirectories($args) {
        static::init();
        $path = $args->get("path","");
        $recursive = $args->get("recursive",false);
        static::statusUpdate("Listing directories in $path");
        try {
            return static::$CodeManager->listDirectories($path,$recursive);
        } catch(\Exception $e) {
            return $e->getMessage();
        }
    }

    public static function getFileContent($args) {
        static::init();
        $filePath = $args->get("filePath");
        static::statusUpdate("Getting contents of $filePath");
        try {
            return static::$CodeManager->getFileContent($filePath);
        } catch(\Exception $e) {
            return $e->getMessage();
        }
    }

    public static function putFileContent($args) {
        static::init();
        $filePath = $args->get("filePath");
        $content = $args->get("content");
        static::statusUpdate("Writing to $filePath");
        try {
            return static::$CodeManager->putFileContent($filePath,$content);
        } catch(\Exception $e) {
            return $e->getMessage();
        }
    }

    public static function appendFileContent($args) {
        static::init();
        $filePath = $args->get("filePath");
        $content = $args->get("content");
        static::statusUpdate("Appending to $filePath");
        try {
            return static::$CodeManager->appendFileContent($filePath,$content);
        } catch(\Exception $e) {
            return $e->getMessage();
        }
    }

    public static function deleteFile($args) {
        static::init();
        $filePath = $args->get("filePath");
        static::statusUpdate("Deleting $filePath");
        try {
            return static::$CodeManager->deleteFile($filePath);
        } catch(\Exception $e) {
            return $e->getMessage();
        }
    }

    public static function searchInFiles($args) {
        static::init();
        $pattern = $args->get("pattern");
        $path = $args->get("path","");
        $recursive = $args->get("recursive",true);
        static::statusUpdate("Searching for $pattern in $path");
        try {
            return static::$CodeManager->searchInFiles($pattern,$path,$recursive);
        } catch(\Exception $e) {
            return $e->getMessage();
        }
    }

    public static function ensureDirectoryExists($args) {
        static::init();
        $path = $args->get("path");
        $mode = $args->get("mode",0777);
        static::statusUpdate("Ensuring directory exists: $path");
        try {
            return static::$CodeManager->ensureDirectoryExists($path,$mode);
        } catch(\Exception $e) {
            return $e->getMessage();
        }
    }

    public static function listClassesInNamespace($args) {
        static::init();
        $namespace = $args->get("namespace");
        $recursive = $args->get("recursive",true);
        static::statusUpdate("Listing classes in namespace: $namespace");
        try {
            return static::$CodeManager->listClassesInNamespace($namespace,$recursive);
        } catch(\Exception $e) {
            return $e->getMessage();
        }
    }
}