<?php

/**
 * Vvveb
 *
 * Copyright (C) 2022  Ziadin Givan
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 */

/**
 * Manages MCP tools, skills, prompts
 *
 * @package Vvveb
 * @subpackage System
 * @since 0.0.1
 */

namespace Vvveb\System;

use function Vvveb\rrmdir;
use function Vvveb\session;
use Vvveb\System\Extensions\Extensions;

class MCP {
	/**
	 * Get system prompt
	 *
	 * $format api, mcp defaults to mcp
	 * @return array List of tools.
	 */
	 


	 
	static function systemPrompt($append = ''): string {	
		$prompt =  'You are an expert coding assistant operating inside a coding agent harness. You help users by reading files, executing commands, editing code, and writing new files.

Available tools:
- read: Read file contents
- bash: Execute bash commands (ls, grep, find, etc.)
- edit: Make precise file edits with exact text replacement, including multiple disjoint edits in one call
- write: Create or overwrite files
- enqueue_task: Add a task to the deferred task queue for later execution.

In addition to the tools above, you may have access to other custom tools depending on the project.

Guidelines:
- Use bash for file operations like ls, rg, find
- Use read to examine files instead of cat or sed.
- You can inspect PI_* environment variables for current model and session details.
- Use edit for precise changes (edits[].oldText must match exactly)
- When changing multiple separate locations in one file, use one edit call with multiple entries in edits[] instead of multiple edit calls
- Each edits[].oldText is matched against the original file, not after earlier edits are applied. Do not emit overlapping or nested edits. Merge nearby changes into one edit.
- Keep edits[].oldText as small as possible while still being unique in the file. Do not pad with large unchanged regions.
- Use write only for new files or complete rewrites.
- Use enqueue_task only when the user explicitly asks to queue, defer, or save a task for later.
- Do not use enqueue_task for your own internal planning unless the user asked for it.
- Never use enqueue_task for the task that is currently active — work on that task instead.
- Be concise in your responses
- Show file paths clearly when working with files
';		
		$agents  = file_get_contents(DIR_ROOT . 'AGENTS.md') ?: '';
		$context = "\n<project_context>\nProject-specific instructions and guidelines:\n";
		$context .= "<project_instructions path=\"/AGENTS.md\">\n{$agents}\n</project_instructions>";
		
		$skills = self :: skills();
		$skillsText = '';
		if ($skills) {
			$skillsText = "The following skills provide specialized instructions for specific tasks.
Use the read tool to load a skill's file when the task matches its description.
When a skill file references a relative path, resolve it against the skill directory (parent of SKILL.md / dirname of the path) and use that absolute path in tool commands.\n";
			$skillsText = "<available_skills>\n";
			foreach ($skills as $file => $desc) {
				$skillsText .= "\t<skill>\n";
				$skillsText .= "\t\t<name>{$desc['name']}</name>\n";
				$skillsText .= "\t\t<description>{$desc['description']}</description>\n";
				$skillsText .= "\t\t<location>{$desc['location']}</location>\n";
				$skillsText .= "\t</skill>\n";
			}
			$skillsText .= "</available_skills>\n";
		}
		
		$context .= "</project_context>\n";

		
		$prompt .= $append . $context . $skillsText;
		$prompt .= 'Current working directory: ' . DIR_ROOT;
		
		return $prompt;
	}
	/**
	 * Get all available tools .
	 *
	 * $format api, mcp defaults to mcp
	 * @return array List of tools.
	 */
	static function tools(?int $roleId = null, ?string $format = null): array {
		$tools = include DIR_ROOT . 'mcp' . DS . 'tools.php';
		
		if ($format === 'api') {
			$api = [];
			foreach ($tools as $tool) {
				$parameters = [];
		
				if (isset($tool['inputSchema']['properties'])) {
					$parameters = [
						'type' => 'object', 
						'properties' => $tool['inputSchema']['properties'],
						'required'   => $tool['inputSchema']['required']];
				}
				
				$api[] = [
					'type' => 'function',
					'function' => [
						'name' => $tool['name'],
						'description' => $tool['description'],
						'parameters' => $parameters 
					]
				];
			}
			
			return $api;
		}
		
		return $tools;
	}	 
	
	/* Get all available tools from the database.
	 *
	 * @return array List of tools.
	 */
	static function skills(): array {
		$path = DIR_ROOT . 'skills';
		$files = scandir($path);
		$skills = [];
		foreach($files as $file) {
			if ($file[0] === '.') continue;
			$location = DS . 'skills' . DS . $file . DS . 'SKILL.md';
			
			$markdown = file_get_contents(DIR_ROOT . $location, false, null, 0, 500); 
			$params   = [];
			if ($markdown && strncmp($markdown, '---', 3) === 0) {
				if (preg_match('@^\s*---.+?---\s*@ms', $markdown, $matches)) {
					$params = Extensions::getParams($matches[0]);
				}
			}
			
			$skills[$file] = ['name' => $params['name'] ?? $file, 'description' => $params['description'] ?? $file, 'location' => $location];
		}
		
		return $skills;
	}
}