codeprism_mcp/
tools_legacy.rs

1//! MCP Tools implementation - Now using modular architecture
2//!
3//! This module has been restructured as part of Phase 1 enhancement.
4//! The massive monolithic implementation has been broken down into
5//! logical modules for better maintainability.
6
7#![allow(clippy::too_many_arguments)]
8#![allow(clippy::only_used_in_recursion)]
9#![allow(clippy::unnecessary_map_or)]
10#![allow(clippy::items_after_test_module)]
11#![allow(clippy::single_match)]
12#![allow(clippy::assertions_on_constants)]
13#![allow(irrefutable_let_patterns)]
14
15use crate::CodePrismMcpServer;
16use anyhow::Result;
17use serde::{Deserialize, Serialize};
18use serde_json::Value;
19
20// This is the legacy tools implementation that will be phased out
21// The new modular structure is in tools/ directory
22
23/// Tool capabilities as defined by MCP
24#[derive(Debug, Clone, Serialize, Deserialize)]
25pub struct ToolCapabilities {
26    /// Whether the server will emit notifications when the list of available tools changes
27    #[serde(rename = "listChanged")]
28    #[serde(skip_serializing_if = "Option::is_none")]
29    pub list_changed: Option<bool>,
30}
31
32/// MCP Tool definition
33#[derive(Debug, Clone, Serialize, Deserialize)]
34pub struct Tool {
35    /// Unique identifier for the tool
36    pub name: String,
37    /// Optional human-readable title for display purposes
38    #[serde(skip_serializing_if = "Option::is_none")]
39    pub title: Option<String>,
40    /// Human-readable description of the tool's functionality
41    pub description: String,
42    /// JSON Schema defining expected input parameters
43    #[serde(rename = "inputSchema")]
44    pub input_schema: Value,
45}
46
47/// Tool call parameters
48#[derive(Debug, Clone, Serialize, Deserialize)]
49pub struct CallToolParams {
50    /// Name of the tool to call
51    pub name: String,
52    /// Arguments to pass to the tool
53    #[serde(skip_serializing_if = "Option::is_none")]
54    pub arguments: Option<Value>,
55}
56
57/// Tool call result
58#[derive(Debug, Clone, Serialize, Deserialize)]
59pub struct CallToolResult {
60    /// Content returned by the tool
61    pub content: Vec<ToolContent>,
62    /// Whether the tool execution resulted in an error
63    #[serde(rename = "isError")]
64    #[serde(skip_serializing_if = "Option::is_none")]
65    pub is_error: Option<bool>,
66}
67
68/// Tool content types
69#[derive(Debug, Clone, Serialize, Deserialize)]
70#[serde(tag = "type")]
71pub enum ToolContent {
72    /// Text content
73    #[serde(rename = "text")]
74    Text {
75        /// Text content
76        text: String,
77    },
78}
79
80/// Parameters for listing tools
81#[derive(Debug, Clone, Serialize, Deserialize)]
82pub struct ListToolsParams {
83    /// Optional cursor for pagination
84    #[serde(skip_serializing_if = "Option::is_none")]
85    pub cursor: Option<String>,
86}
87
88/// Result of listing tools
89#[derive(Debug, Clone, Serialize, Deserialize)]
90pub struct ListToolsResult {
91    /// List of available tools
92    pub tools: Vec<Tool>,
93    /// Optional cursor for pagination
94    #[serde(rename = "nextCursor")]
95    #[serde(skip_serializing_if = "Option::is_none")]
96    pub next_cursor: Option<String>,
97}
98
99/// Legacy ToolManager - maintains backward compatibility
100/// This maintains backward compatibility while the new modular architecture is being developed
101pub struct ToolManager {
102    server: std::sync::Arc<tokio::sync::RwLock<CodePrismMcpServer>>,
103}
104
105impl ToolManager {
106    /// Create a new tool manager
107    pub fn new(server: std::sync::Arc<tokio::sync::RwLock<CodePrismMcpServer>>) -> Self {
108        Self { server }
109    }
110
111    /// List available tools
112    pub async fn list_tools(&self, _params: ListToolsParams) -> Result<ListToolsResult> {
113        let tools = vec![
114            Tool {
115                name: "repository_stats".to_string(),
116                title: Some("Repository Statistics".to_string()),
117                description: "Get comprehensive statistics about the repository".to_string(),
118                input_schema: serde_json::json!({
119                    "type": "object",
120                    "properties": {}
121                }),
122            },
123            Tool {
124                name: "trace_path".to_string(),
125                title: Some("Trace Execution Path".to_string()),
126                description: "Find the shortest path between two code symbols".to_string(),
127                input_schema: serde_json::json!({
128                    "type": "object",
129                    "properties": {
130                        "source": {
131                            "type": "string",
132                            "description": "Source symbol identifier (node ID)"
133                        },
134                        "target": {
135                            "type": "string",
136                            "description": "Target symbol identifier (node ID)"
137                        },
138                        "max_depth": {
139                            "type": "number",
140                            "description": "Maximum search depth",
141                            "default": 10
142                        }
143                    },
144                    "required": ["source", "target"]
145                }),
146            },
147            Tool {
148                name: "explain_symbol".to_string(),
149                title: Some("Explain Symbol".to_string()),
150                description: "Provide detailed explanation of a code symbol with context".to_string(),
151                input_schema: serde_json::json!({
152                    "type": "object",
153                    "properties": {
154                        "symbol_id": {
155                            "type": "string",
156                            "description": "Symbol identifier (node ID)"
157                        },
158                        "include_dependencies": {
159                            "type": "boolean",
160                            "description": "Include dependency information",
161                            "default": false
162                        },
163                        "include_usages": {
164                            "type": "boolean",
165                            "description": "Include usage information",
166                            "default": false
167                        },
168                        "context_lines": {
169                            "type": "number",
170                            "description": "Number of lines before and after the symbol to include as context",
171                            "default": 4
172                        }
173                    },
174                    "required": ["symbol_id"]
175                }),
176            },
177            Tool {
178                name: "find_dependencies".to_string(),
179                title: Some("Find Dependencies".to_string()),
180                description: "Analyze dependencies for a code symbol or file".to_string(),
181                input_schema: serde_json::json!({
182                    "type": "object",
183                    "properties": {
184                        "target": {
185                            "type": "string",
186                            "description": "Symbol ID or file path to analyze"
187                        },
188                        "dependency_type": {
189                            "type": "string",
190                            "enum": ["direct", "calls", "imports", "reads", "writes"],
191                            "description": "Type of dependencies to find",
192                            "default": "direct"
193                        }
194                    },
195                    "required": ["target"]
196                }),
197            },
198            Tool {
199                name: "find_references".to_string(),
200                title: Some("Find References".to_string()),
201                description: "Find all references to a symbol across the codebase".to_string(),
202                input_schema: serde_json::json!({
203                    "type": "object",
204                    "properties": {
205                        "symbol_id": {
206                            "type": "string",
207                            "description": "Symbol identifier to find references for"
208                        },
209                        "include_definitions": {
210                            "type": "boolean",
211                            "description": "Include symbol definitions",
212                            "default": true
213                        },
214                        "context_lines": {
215                            "type": "number",
216                            "description": "Number of lines before and after the symbol to include as context",
217                            "default": 4
218                        }
219                    },
220                    "required": ["symbol_id"]
221                }),
222            },
223            Tool {
224                name: "search_symbols".to_string(),
225                title: Some("Search Symbols".to_string()),
226                description: "Search for symbols by name pattern with advanced inheritance filtering".to_string(),
227                input_schema: serde_json::json!({
228                    "type": "object",
229                    "properties": {
230                        "pattern": {
231                            "type": "string",
232                            "description": "Search pattern (supports regex)"
233                        },
234                        "symbol_types": {
235                            "type": "array",
236                            "items": {
237                                "type": "string",
238                                "enum": ["function", "class", "variable", "module", "method"]
239                            },
240                            "description": "Filter by symbol types"
241                        },
242                        "inheritance_filters": {
243                            "type": "array",
244                            "items": {
245                                "type": "string"
246                            },
247                            "description": "Filter by inheritance relationships (format: 'inherits_from:ClassName', 'metaclass:MetaclassName', 'uses_mixin:MixinName')"
248                        },
249                        "limit": {
250                            "type": "number",
251                            "description": "Maximum number of results",
252                            "default": 50
253                        },
254                        "context_lines": {
255                            "type": "number",
256                            "description": "Number of lines before and after the symbol to include as context",
257                            "default": 4
258                        }
259                    },
260                    "required": ["pattern"]
261                }),
262            },
263            Tool {
264                name: "search_content".to_string(),
265                title: Some("Search Content".to_string()),
266                description: "Search across all content including documentation, comments, and configuration files".to_string(),
267                input_schema: serde_json::json!({
268                    "type": "object",
269                    "properties": {
270                        "query": {
271                            "type": "string",
272                            "description": "Search query text"
273                        },
274                        "content_types": {
275                            "type": "array",
276                            "items": {
277                                "type": "string",
278                                "enum": ["documentation", "comments", "configuration", "code"]
279                            },
280                            "description": "Types of content to search in"
281                        },
282                        "file_patterns": {
283                            "type": "array",
284                            "items": {
285                                "type": "string"
286                            },
287                            "description": "File patterns to include (regex)"
288                        },
289                        "exclude_patterns": {
290                            "type": "array",
291                            "items": {
292                                "type": "string"
293                            },
294                            "description": "File patterns to exclude (regex)"
295                        },
296                        "max_results": {
297                            "type": "number",
298                            "description": "Maximum number of results",
299                            "default": 50
300                        },
301                        "case_sensitive": {
302                            "type": "boolean",
303                            "description": "Case sensitive search",
304                            "default": false
305                        },
306                        "use_regex": {
307                            "type": "boolean",
308                            "description": "Use regex pattern matching",
309                            "default": false
310                        },
311                        "include_context": {
312                            "type": "boolean",
313                            "description": "Include context around matches",
314                            "default": true
315                        }
316                    },
317                    "required": ["query"]
318                }),
319            },
320            Tool {
321                name: "find_files".to_string(),
322                title: Some("Find Files".to_string()),
323                description: "Find files by name or path pattern".to_string(),
324                input_schema: serde_json::json!({
325                    "type": "object",
326                    "properties": {
327                        "pattern": {
328                            "type": "string",
329                            "description": "File pattern to search for (supports regex)"
330                        }
331                    },
332                    "required": ["pattern"]
333                }),
334            },
335            Tool {
336                name: "content_stats".to_string(),
337                title: Some("Content Statistics".to_string()),
338                description: "Get statistics about indexed content".to_string(),
339                input_schema: serde_json::json!({
340                    "type": "object",
341                    "properties": {}
342                }),
343            },
344            Tool {
345                name: "analyze_complexity".to_string(),
346                title: Some("Analyze Code Complexity".to_string()),
347                description: "Calculate complexity metrics for code elements including cyclomatic, cognitive, and maintainability metrics".to_string(),
348                input_schema: serde_json::json!({
349                    "type": "object",
350                    "properties": {
351                        "target": {
352                            "type": "string",
353                            "description": "File path or symbol ID to analyze"
354                        },
355                        "metrics": {
356                            "type": "array",
357                            "items": {
358                                "type": "string",
359                                "enum": ["cyclomatic", "cognitive", "halstead", "maintainability_index", "all"]
360                            },
361                            "description": "Types of complexity metrics to calculate",
362                            "default": ["all"]
363                        },
364                        "threshold_warnings": {
365                            "type": "boolean",
366                            "description": "Include warnings for metrics exceeding thresholds",
367                            "default": true
368                        }
369                    },
370                    "required": ["target"]
371                }),
372            },
373
374            Tool {
375                name: "detect_patterns".to_string(),
376                title: Some("Detect Design Patterns".to_string()),
377                description: "Identify design patterns, architectural structures, and metaprogramming patterns in the codebase".to_string(),
378                input_schema: serde_json::json!({
379                    "type": "object",
380                    "properties": {
381                        "scope": {
382                            "type": "string",
383                            "description": "Scope for pattern detection (repository, package, or file)",
384                            "default": "repository"
385                        },
386                        "pattern_types": {
387                            "type": "array",
388                            "items": {
389                                "type": "string",
390                                "enum": ["design_patterns", "anti_patterns", "architectural_patterns", "metaprogramming_patterns", "all"]
391                            },
392                            "description": "Types of patterns to detect",
393                            "default": ["all"]
394                        },
395                        "confidence_threshold": {
396                            "type": "number",
397                            "description": "Minimum confidence threshold for pattern detection (0.0 to 1.0)",
398                            "default": 0.8,
399                            "minimum": 0.0,
400                            "maximum": 1.0
401                        },
402                        "include_suggestions": {
403                            "type": "boolean",
404                            "description": "Include improvement suggestions for detected patterns",
405                            "default": true
406                        }
407                    },
408                    "required": []
409                }),
410            },
411            Tool {
412                name: "analyze_transitive_dependencies".to_string(),
413                title: Some("Analyze Transitive Dependencies".to_string()),
414                description: "Analyze complete dependency chains, detect cycles, and map transitive relationships".to_string(),
415                input_schema: serde_json::json!({
416                    "type": "object",
417                    "properties": {
418                        "target": {
419                            "type": "string",
420                            "description": "Symbol ID or file path to analyze"
421                        },
422                        "max_depth": {
423                            "type": "number",
424                            "description": "Maximum depth for transitive analysis",
425                            "default": 5,
426                            "minimum": 1,
427                            "maximum": 20
428                        },
429                        "detect_cycles": {
430                            "type": "boolean",
431                            "description": "Detect circular dependencies",
432                            "default": true
433                        },
434                        "include_external_dependencies": {
435                            "type": "boolean",
436                            "description": "Include external/third-party dependencies",
437                            "default": false
438                        },
439                        "dependency_types": {
440                            "type": "array",
441                            "items": {
442                                "type": "string",
443                                "enum": ["calls", "imports", "reads", "writes", "extends", "implements", "all"]
444                            },
445                            "description": "Types of dependencies to analyze",
446                            "default": ["all"]
447                        }
448                    },
449                    "required": ["target"]
450                }),
451            },
452            Tool {
453                name: "trace_data_flow".to_string(),
454                title: Some("Trace Data Flow".to_string()),
455                description: "Track data flow through the codebase, following variable assignments, function parameters, and transformations".to_string(),
456                input_schema: serde_json::json!({
457                    "type": "object",
458                    "properties": {
459                        "variable_or_parameter": {
460                            "type": "string",
461                            "description": "Symbol ID of variable or parameter to trace"
462                        },
463                        "direction": {
464                            "type": "string",
465                            "enum": ["forward", "backward", "both"],
466                            "description": "Direction to trace data flow",
467                            "default": "forward"
468                        },
469                        "include_transformations": {
470                            "type": "boolean",
471                            "description": "Include data transformations (method calls, assignments)",
472                            "default": true
473                        },
474                        "max_depth": {
475                            "type": "number",
476                            "description": "Maximum depth for data flow tracing",
477                            "default": 10,
478                            "minimum": 1,
479                            "maximum": 50
480                        },
481                        "follow_function_calls": {
482                            "type": "boolean",
483                            "description": "Follow data flow through function calls",
484                            "default": true
485                        },
486                        "include_field_access": {
487                            "type": "boolean",
488                            "description": "Include field access and modifications",
489                            "default": true
490                        }
491                    },
492                    "required": ["variable_or_parameter"]
493                }),
494            },
495
496
497
498
499            Tool {
500                name: "trace_inheritance".to_string(),
501                title: Some("Trace Inheritance Hierarchy".to_string()),
502                description: "Analyze complete inheritance hierarchies, metaclasses, and mixin relationships with detailed visualization".to_string(),
503                input_schema: serde_json::json!({
504                    "type": "object",
505                    "properties": {
506                        "class_name": {
507                            "type": "string",
508                            "description": "Name of the class to analyze (will search for matching classes)"
509                        },
510                        "class_id": {
511                            "type": "string",
512                            "description": "Specific class node ID to analyze (alternative to class_name)"
513                        },
514                        "direction": {
515                            "type": "string",
516                            "enum": ["up", "down", "both"],
517                            "description": "Direction to trace inheritance (up=parents, down=children, both=complete tree)",
518                            "default": "both"
519                        },
520                        "include_metaclasses": {
521                            "type": "boolean",
522                            "description": "Include metaclass relationships and analysis",
523                            "default": true
524                        },
525                        "include_mixins": {
526                            "type": "boolean",
527                            "description": "Include mixin relationships and analysis",
528                            "default": true
529                        },
530                        "include_mro": {
531                            "type": "boolean",
532                            "description": "Include Method Resolution Order analysis",
533                            "default": true
534                        },
535                        "include_dynamic_attributes": {
536                            "type": "boolean",
537                            "description": "Include dynamic attributes created by metaclasses",
538                            "default": true
539                        },
540                        "max_depth": {
541                            "type": "number",
542                            "description": "Maximum depth for inheritance traversal",
543                            "default": 10,
544                            "minimum": 1,
545                            "maximum": 50
546                        },
547                        "include_source_context": {
548                            "type": "boolean",
549                            "description": "Include source code context for inheritance relationships",
550                            "default": false
551                        }
552                    },
553                    "anyOf": [
554                        {"required": ["class_name"]},
555                        {"required": ["class_id"]}
556                    ]
557                }),
558            },
559            Tool {
560                name: "analyze_decorators".to_string(),
561                title: Some("Analyze Decorators".to_string()),
562                description: "Comprehensive decorator analysis and pattern recognition including effects, usage patterns, and framework-specific decorators".to_string(),
563                input_schema: serde_json::json!({
564                    "type": "object",
565                    "properties": {
566                        "decorator_pattern": {
567                            "type": "string",
568                            "description": "Decorator name or pattern to analyze (supports regex)"
569                        },
570                        "decorator_id": {
571                            "type": "string",
572                            "description": "Specific decorator node ID to analyze (alternative to decorator_pattern)"
573                        },
574                        "scope": {
575                            "type": "string",
576                            "enum": ["function", "class", "module", "repository"],
577                            "description": "Scope for decorator analysis",
578                            "default": "repository"
579                        },
580                        "include_factories": {
581                            "type": "boolean",
582                            "description": "Include decorator factory analysis",
583                            "default": true
584                        },
585                        "analyze_effects": {
586                            "type": "boolean",
587                            "description": "Analyze what effects the decorators have on their targets",
588                            "default": true
589                        },
590                        "include_chains": {
591                            "type": "boolean",
592                            "description": "Analyze decorator chains and their interaction",
593                            "default": true
594                        },
595                        "detect_patterns": {
596                            "type": "boolean",
597                            "description": "Detect common decorator patterns (registry, caching, validation, etc.)",
598                            "default": true
599                        },
600                        "include_framework_analysis": {
601                            "type": "boolean",
602                            "description": "Include framework-specific decorator analysis (Flask, Django, FastAPI, etc.)",
603                            "default": true
604                        },
605                        "include_source_context": {
606                            "type": "boolean",
607                            "description": "Include source code context for decorator usage",
608                            "default": false
609                        },
610                        "confidence_threshold": {
611                            "type": "number",
612                            "description": "Minimum confidence threshold for pattern detection (0.0 to 1.0)",
613                            "default": 0.8,
614                            "minimum": 0.0,
615                            "maximum": 1.0
616                        },
617                        "max_results": {
618                            "type": "number",
619                            "description": "Maximum number of decorator usages to analyze",
620                            "default": 100,
621                            "minimum": 1,
622                            "maximum": 500
623                        }
624                    },
625                    "anyOf": [
626                        {"required": ["decorator_pattern"]},
627                        {"required": ["decorator_id"]}
628                    ]
629                }),
630            },
631            Tool {
632                name: "find_duplicates".to_string(),
633                title: Some("Find Code Duplicates".to_string()),
634                description: "Detect duplicate code patterns and similar code blocks".to_string(),
635                input_schema: serde_json::json!({
636                    "type": "object",
637                    "properties": {
638                        "similarity_threshold": {
639                            "type": "number",
640                            "description": "Similarity threshold for detecting duplicates (0.0 to 1.0)",
641                            "default": 0.8,
642                            "minimum": 0.0,
643                            "maximum": 1.0
644                        },
645                        "min_lines": {
646                            "type": "number",
647                            "description": "Minimum number of lines for a duplicate block",
648                            "default": 3,
649                            "minimum": 1
650                        },
651                        "scope": {
652                            "type": "string",
653                            "description": "Scope for duplicate detection",
654                            "default": "repository"
655                        }
656                    },
657                    "required": []
658                }),
659            },
660            Tool {
661                name: "find_unused_code".to_string(),
662                title: Some("Find Unused Code".to_string()),
663                description: "Identify unused functions, classes, variables, and imports".to_string(),
664                input_schema: serde_json::json!({
665                    "type": "object",
666                    "properties": {
667                        "scope": {
668                            "type": "string",
669                            "description": "Scope for unused code analysis",
670                            "default": "repository"
671                        },
672                        "analyze_types": {
673                            "type": "array",
674                            "items": {
675                                "type": "string",
676                                "enum": ["functions", "classes", "variables", "imports", "all"]
677                            },
678                            "description": "Types of code elements to analyze",
679                            "default": ["functions", "classes", "variables", "imports"]
680                        },
681                        "confidence_threshold": {
682                            "type": "number",
683                            "description": "Confidence threshold for unused detection",
684                            "default": 0.7,
685                            "minimum": 0.0,
686                            "maximum": 1.0
687                        },
688                        "consider_external_apis": {
689                            "type": "boolean",
690                            "description": "Consider external API usage",
691                            "default": true
692                        },
693                        "include_dead_code": {
694                            "type": "boolean",
695                            "description": "Include dead code block detection",
696                            "default": true
697                        },
698                        "exclude_patterns": {
699                            "type": "array",
700                            "items": {
701                                "type": "string"
702                            },
703                            "description": "Patterns to exclude from analysis"
704                        }
705                    },
706                    "required": []
707                }),
708            },
709            Tool {
710                name: "analyze_security".to_string(),
711                title: Some("Analyze Security Vulnerabilities".to_string()),
712                description: "Identify security vulnerabilities and potential threats".to_string(),
713                input_schema: serde_json::json!({
714                    "type": "object",
715                    "properties": {
716                        "scope": {
717                            "type": "string",
718                            "description": "Scope for security analysis",
719                            "default": "repository"
720                        },
721                        "vulnerability_types": {
722                            "type": "array",
723                            "items": {
724                                "type": "string",
725                                "enum": ["injection", "authentication", "authorization", "data_exposure", "unsafe_patterns", "crypto", "all"]
726                            },
727                            "description": "Types of vulnerabilities to check",
728                            "default": ["injection", "authentication", "authorization"]
729                        },
730                        "severity_threshold": {
731                            "type": "string",
732                            "enum": ["low", "medium", "high", "critical"],
733                            "description": "Minimum severity level to report",
734                            "default": "medium"
735                        },
736                        "include_data_flow_analysis": {
737                            "type": "boolean",
738                            "description": "Include data flow analysis for vulnerability detection",
739                            "default": false
740                        },
741                        "check_external_dependencies": {
742                            "type": "boolean",
743                            "description": "Check external dependencies for known vulnerabilities",
744                            "default": true
745                        },
746                        "exclude_patterns": {
747                            "type": "array",
748                            "items": {
749                                "type": "string"
750                            },
751                            "description": "Patterns to exclude from analysis"
752                        }
753                    },
754                    "required": []
755                }),
756            },
757            Tool {
758                name: "analyze_performance".to_string(),
759                title: Some("Analyze Performance Issues".to_string()),
760                description: "Identify performance bottlenecks and optimization opportunities".to_string(),
761                input_schema: serde_json::json!({
762                    "type": "object",
763                    "properties": {
764                        "scope": {
765                            "type": "string",
766                            "description": "Scope for performance analysis",
767                            "default": "repository"
768                        },
769                        "analysis_types": {
770                            "type": "array",
771                            "items": {
772                                "type": "string",
773                                "enum": ["time_complexity", "memory_usage", "hot_spots", "anti_patterns", "scalability", "all"]
774                            },
775                            "description": "Types of performance analysis to perform",
776                            "default": ["time_complexity", "memory_usage", "hot_spots"]
777                        },
778                        "complexity_threshold": {
779                            "type": "string",
780                            "enum": ["low", "medium", "high"],
781                            "description": "Complexity threshold for reporting issues",
782                            "default": "medium"
783                        },
784                        "include_algorithmic_analysis": {
785                            "type": "boolean",
786                            "description": "Include algorithmic complexity analysis",
787                            "default": true
788                        },
789                        "detect_bottlenecks": {
790                            "type": "boolean",
791                            "description": "Detect performance bottlenecks",
792                            "default": true
793                        },
794                        "exclude_patterns": {
795                            "type": "array",
796                            "items": {
797                                "type": "string"
798                            },
799                            "description": "Patterns to exclude from analysis"
800                        }
801                    },
802                    "required": []
803                }),
804            },
805            Tool {
806                name: "analyze_api_surface".to_string(),
807                title: Some("Analyze API Surface".to_string()),
808                description: "Analyze public API surface, versioning, and breaking changes".to_string(),
809                input_schema: serde_json::json!({
810                    "type": "object",
811                    "properties": {
812                        "scope": {
813                            "type": "string",
814                            "description": "Scope for API surface analysis",
815                            "default": "repository"
816                        },
817                        "analysis_types": {
818                            "type": "array",
819                            "items": {
820                                "type": "string",
821                                "enum": ["public_api", "versioning", "breaking_changes", "documentation_coverage", "compatibility", "all"]
822                            },
823                            "description": "Types of API analysis to perform",
824                            "default": ["public_api", "versioning", "breaking_changes"]
825                        },
826                        "api_version": {
827                            "type": "string",
828                            "description": "API version to analyze (optional)"
829                        },
830                        "include_private_apis": {
831                            "type": "boolean",
832                            "description": "Include private APIs in analysis",
833                            "default": false
834                        },
835                        "check_documentation_coverage": {
836                            "type": "boolean",
837                            "description": "Check documentation coverage for APIs",
838                            "default": true
839                        },
840                        "detect_breaking_changes": {
841                            "type": "boolean",
842                            "description": "Detect potential breaking changes",
843                            "default": true
844                        },
845                        "exclude_patterns": {
846                            "type": "array",
847                            "items": {
848                                "type": "string"
849                            },
850                            "description": "Patterns to exclude from analysis"
851                        }
852                    },
853                    "required": []
854                }),
855            },
856        ];
857
858        Ok(ListToolsResult {
859            tools,
860            next_cursor: None,
861        })
862    }
863
864    /// Call a specific tool
865    pub async fn call_tool(&self, params: CallToolParams) -> Result<CallToolResult> {
866        let server = self.server.read().await;
867
868        match params.name.as_str() {
869            "repository_stats" => self.repository_stats(&server).await,
870            "trace_path" => self.trace_path(&server, params.arguments).await,
871            "explain_symbol" => self.explain_symbol(&server, params.arguments).await,
872            "find_dependencies" => self.find_dependencies(&server, params.arguments).await,
873            "find_references" => self.find_references(&server, params.arguments).await,
874            "search_symbols" => self.search_symbols(&server, params.arguments).await,
875            "search_content" => self.search_content(&server, params.arguments).await,
876            "find_files" => self.find_files(&server, params.arguments).await,
877            "content_stats" => self.content_stats(&server).await,
878            "analyze_complexity" => self.analyze_complexity(&server, params.arguments).await,
879            "find_duplicates" => self.find_duplicates(&server, params.arguments).await,
880
881            "detect_patterns" => self.detect_patterns(&server, params.arguments).await,
882            "analyze_transitive_dependencies" => {
883                self.analyze_transitive_dependencies(&server, params.arguments)
884                    .await
885            }
886            "trace_data_flow" => self.trace_data_flow(&server, params.arguments).await,
887            "find_unused_code" => self.find_unused_code(&server, params.arguments).await,
888
889            "trace_inheritance" => self.trace_inheritance(&server, params.arguments).await,
890            "analyze_decorators" => self.analyze_decorators(&server, params.arguments).await,
891
892            "analyze_security" => self.analyze_security(&server, params.arguments).await,
893            "analyze_performance" => self.analyze_performance(&server, params.arguments).await,
894            "analyze_api_surface" => self.analyze_api_surface(&server, params.arguments).await,
895            _ => Ok(CallToolResult {
896                content: vec![ToolContent::Text {
897                    text: format!("Unknown tool: {}", params.name),
898                }],
899                is_error: Some(true),
900            }),
901        }
902    }
903
904    /// Get repository statistics
905    async fn repository_stats(&self, server: &CodePrismMcpServer) -> Result<CallToolResult> {
906        let result = if let Some(repo_path) = server.repository_path() {
907            let file_count = server
908                .scanner()
909                .discover_files(repo_path)
910                .map(|files| files.len())
911                .unwrap_or(0);
912
913            let graph_stats = server.graph_store().get_stats();
914
915            serde_json::json!({
916                "repository_path": repo_path.display().to_string(),
917                "total_files": file_count,
918                "total_nodes": graph_stats.total_nodes,
919                "total_edges": graph_stats.total_edges,
920                "nodes_by_kind": graph_stats.nodes_by_kind,
921                "status": "active"
922            })
923        } else {
924            serde_json::json!({
925                "error": "No repository initialized"
926            })
927        };
928
929        Ok(CallToolResult {
930            content: vec![ToolContent::Text {
931                text: serde_json::to_string_pretty(&result)?,
932            }],
933            is_error: Some(false),
934        })
935    }
936
937    /// Trace path between two symbols
938    async fn trace_path(
939        &self,
940        server: &CodePrismMcpServer,
941        arguments: Option<Value>,
942    ) -> Result<CallToolResult> {
943        let args = arguments.ok_or_else(|| anyhow::anyhow!("Missing arguments"))?;
944
945        let source_str = args
946            .get("source")
947            .and_then(|v| v.as_str())
948            .ok_or_else(|| anyhow::anyhow!("Missing source parameter"))?;
949
950        let target_str = args
951            .get("target")
952            .and_then(|v| v.as_str())
953            .ok_or_else(|| anyhow::anyhow!("Missing target parameter"))?;
954
955        let max_depth = args
956            .get("max_depth")
957            .and_then(|v| v.as_u64())
958            .map(|v| v as usize);
959
960        // Parse node IDs from hex strings
961        let source_id = self.parse_node_id(source_str)?;
962        let target_id = self.parse_node_id(target_str)?;
963
964        match server
965            .graph_query()
966            .find_path(&source_id, &target_id, max_depth)?
967        {
968            Some(path_result) => {
969                let result = serde_json::json!({
970                    "found": true,
971                    "source": source_str,
972                    "target": target_str,
973                    "distance": path_result.distance,
974                    "path": path_result.path.iter().map(|id| id.to_hex()).collect::<Vec<_>>(),
975                    "edges": path_result.edges.iter().map(|edge| {
976                        serde_json::json!({
977                            "source": edge.source.to_hex(),
978                            "target": edge.target.to_hex(),
979                            "kind": format!("{:?}", edge.kind)
980                        })
981                    }).collect::<Vec<_>>()
982                });
983
984                Ok(CallToolResult {
985                    content: vec![ToolContent::Text {
986                        text: serde_json::to_string_pretty(&result)?,
987                    }],
988                    is_error: Some(false),
989                })
990            }
991            None => {
992                let result = serde_json::json!({
993                    "found": false,
994                    "source": source_str,
995                    "target": target_str,
996                    "message": "No path found between the specified symbols"
997                });
998
999                Ok(CallToolResult {
1000                    content: vec![ToolContent::Text {
1001                        text: serde_json::to_string_pretty(&result)?,
1002                    }],
1003                    is_error: Some(false),
1004                })
1005            }
1006        }
1007    }
1008
1009    /// Explain a symbol with context
1010    async fn explain_symbol(
1011        &self,
1012        server: &CodePrismMcpServer,
1013        arguments: Option<Value>,
1014    ) -> Result<CallToolResult> {
1015        let args = arguments.ok_or_else(|| anyhow::anyhow!("Missing arguments"))?;
1016
1017        let symbol_id_str = args
1018            .get("symbol_id")
1019            .and_then(|v| v.as_str())
1020            .ok_or_else(|| anyhow::anyhow!("Missing symbol_id parameter"))?;
1021
1022        let include_dependencies = args
1023            .get("include_dependencies")
1024            .and_then(|v| v.as_bool())
1025            .unwrap_or(false);
1026
1027        let include_usages = args
1028            .get("include_usages")
1029            .and_then(|v| v.as_bool())
1030            .unwrap_or(false);
1031
1032        let context_lines = args
1033            .get("context_lines")
1034            .and_then(|v| v.as_u64())
1035            .map(|v| v as usize)
1036            .unwrap_or(4);
1037
1038        let symbol_id = self.parse_node_id(symbol_id_str)?;
1039
1040        if let Some(node) = server.graph_store().get_node(&symbol_id) {
1041            let mut result = serde_json::json!({
1042                "symbol": self.create_node_info_with_context(&node, context_lines)
1043            });
1044
1045            // Enhanced inheritance information for classes
1046            if matches!(node.kind, codeprism_core::NodeKind::Class) {
1047                if let Ok(inheritance_info) = server.graph_query().get_inheritance_info(&symbol_id)
1048                {
1049                    let mut inheritance_data = serde_json::Map::new();
1050
1051                    // Basic inheritance information
1052                    inheritance_data.insert(
1053                        "class_name".to_string(),
1054                        serde_json::Value::String(inheritance_info.class_name),
1055                    );
1056                    inheritance_data.insert(
1057                        "is_metaclass".to_string(),
1058                        serde_json::Value::Bool(inheritance_info.is_metaclass),
1059                    );
1060
1061                    // Base classes
1062                    if !inheritance_info.base_classes.is_empty() {
1063                        let base_classes: Vec<_> = inheritance_info
1064                            .base_classes
1065                            .iter()
1066                            .map(|rel| {
1067                                serde_json::json!({
1068                                    "name": rel.class_name,
1069                                    "relationship_type": rel.relationship_type,
1070                                    "file": rel.file.display().to_string(),
1071                                    "span": {
1072                                        "start_line": rel.span.start_line,
1073                                        "end_line": rel.span.end_line,
1074                                        "start_column": rel.span.start_column,
1075                                        "end_column": rel.span.end_column
1076                                    }
1077                                })
1078                            })
1079                            .collect();
1080                        inheritance_data.insert(
1081                            "base_classes".to_string(),
1082                            serde_json::Value::Array(base_classes),
1083                        );
1084                    }
1085
1086                    // Subclasses
1087                    if !inheritance_info.subclasses.is_empty() {
1088                        let subclasses: Vec<_> = inheritance_info
1089                            .subclasses
1090                            .iter()
1091                            .map(|rel| {
1092                                serde_json::json!({
1093                                    "name": rel.class_name,
1094                                    "file": rel.file.display().to_string(),
1095                                    "span": {
1096                                        "start_line": rel.span.start_line,
1097                                        "end_line": rel.span.end_line,
1098                                        "start_column": rel.span.start_column,
1099                                        "end_column": rel.span.end_column
1100                                    }
1101                                })
1102                            })
1103                            .collect();
1104                        inheritance_data.insert(
1105                            "subclasses".to_string(),
1106                            serde_json::Value::Array(subclasses),
1107                        );
1108                    }
1109
1110                    // Metaclass information
1111                    if let Some(metaclass) = inheritance_info.metaclass {
1112                        inheritance_data.insert(
1113                            "metaclass".to_string(),
1114                            serde_json::json!({
1115                                "name": metaclass.class_name,
1116                                "file": metaclass.file.display().to_string(),
1117                                "span": {
1118                                    "start_line": metaclass.span.start_line,
1119                                    "end_line": metaclass.span.end_line,
1120                                    "start_column": metaclass.span.start_column,
1121                                    "end_column": metaclass.span.end_column
1122                                }
1123                            }),
1124                        );
1125                    }
1126
1127                    // Mixins
1128                    if !inheritance_info.mixins.is_empty() {
1129                        let mixins: Vec<_> = inheritance_info
1130                            .mixins
1131                            .iter()
1132                            .map(|rel| {
1133                                serde_json::json!({
1134                                    "name": rel.class_name,
1135                                    "file": rel.file.display().to_string(),
1136                                    "span": {
1137                                        "start_line": rel.span.start_line,
1138                                        "end_line": rel.span.end_line,
1139                                        "start_column": rel.span.start_column,
1140                                        "end_column": rel.span.end_column
1141                                    }
1142                                })
1143                            })
1144                            .collect();
1145                        inheritance_data
1146                            .insert("mixins".to_string(), serde_json::Value::Array(mixins));
1147                    }
1148
1149                    // Method Resolution Order
1150                    if !inheritance_info.method_resolution_order.is_empty() {
1151                        inheritance_data.insert(
1152                            "method_resolution_order".to_string(),
1153                            serde_json::Value::Array(
1154                                inheritance_info
1155                                    .method_resolution_order
1156                                    .iter()
1157                                    .map(|name| serde_json::Value::String(name.clone()))
1158                                    .collect(),
1159                            ),
1160                        );
1161                    }
1162
1163                    // Dynamic attributes
1164                    if !inheritance_info.dynamic_attributes.is_empty() {
1165                        let dynamic_attrs: Vec<_> = inheritance_info
1166                            .dynamic_attributes
1167                            .iter()
1168                            .map(|attr| {
1169                                serde_json::json!({
1170                                    "name": attr.name,
1171                                    "created_by": attr.created_by,
1172                                    "type": attr.attribute_type
1173                                })
1174                            })
1175                            .collect();
1176                        inheritance_data.insert(
1177                            "dynamic_attributes".to_string(),
1178                            serde_json::Value::Array(dynamic_attrs),
1179                        );
1180                    }
1181
1182                    // Full inheritance chain
1183                    if !inheritance_info.inheritance_chain.is_empty() {
1184                        inheritance_data.insert(
1185                            "inheritance_chain".to_string(),
1186                            serde_json::Value::Array(
1187                                inheritance_info
1188                                    .inheritance_chain
1189                                    .iter()
1190                                    .map(|name| serde_json::Value::String(name.clone()))
1191                                    .collect(),
1192                            ),
1193                        );
1194                    }
1195
1196                    result["inheritance"] = serde_json::Value::Object(inheritance_data);
1197                }
1198            }
1199
1200            if include_dependencies {
1201                let dependencies = server
1202                    .graph_query()
1203                    .find_dependencies(&symbol_id, codeprism_core::graph::DependencyType::Direct)?;
1204
1205                // Filter out invalid Call nodes with malformed names
1206                let valid_dependencies: Vec<_> = dependencies
1207                    .iter()
1208                    .filter(|dep| self.is_valid_dependency_node(&dep.target_node))
1209                    .collect();
1210
1211                result["dependencies"] = serde_json::json!(valid_dependencies
1212                    .iter()
1213                    .map(|dep| {
1214                        let mut dep_info =
1215                            self.create_node_info_with_context(&dep.target_node, context_lines);
1216                        dep_info["edge_kind"] = serde_json::json!(format!("{:?}", dep.edge_kind));
1217                        dep_info
1218                    })
1219                    .collect::<Vec<_>>());
1220            }
1221
1222            if include_usages {
1223                let references = server.graph_query().find_references(&symbol_id)?;
1224                result["usages"] = serde_json::json!(references
1225                    .iter()
1226                    .map(|ref_| {
1227                        let mut usage_info =
1228                            self.create_node_info_with_context(&ref_.source_node, context_lines);
1229                        usage_info["edge_kind"] =
1230                            serde_json::json!(format!("{:?}", ref_.edge_kind));
1231                        usage_info["reference_location"] = serde_json::json!({
1232                            "file": ref_.location.file.display().to_string(),
1233                            "span": {
1234                                "start_line": ref_.location.span.start_line,
1235                                "end_line": ref_.location.span.end_line,
1236                                "start_column": ref_.location.span.start_column,
1237                                "end_column": ref_.location.span.end_column
1238                            }
1239                        });
1240                        usage_info
1241                    })
1242                    .collect::<Vec<_>>());
1243            }
1244
1245            Ok(CallToolResult {
1246                content: vec![ToolContent::Text {
1247                    text: serde_json::to_string_pretty(&result)?,
1248                }],
1249                is_error: Some(false),
1250            })
1251        } else {
1252            Ok(CallToolResult {
1253                content: vec![ToolContent::Text {
1254                    text: format!("Symbol not found: {}", symbol_id_str),
1255                }],
1256                is_error: Some(true),
1257            })
1258        }
1259    }
1260
1261    /// Validate that a dependency node has a valid name
1262    fn is_valid_dependency_node(&self, node: &codeprism_core::Node) -> bool {
1263        // Filter out Call nodes with invalid names
1264        if matches!(node.kind, codeprism_core::NodeKind::Call) {
1265            // Check for common invalid patterns
1266            if node.name.is_empty()
1267                || node.name == ")"
1268                || node.name == "("
1269                || node.name.trim().is_empty()
1270                || node.name.chars().all(|c| !c.is_alphanumeric() && c != '_')
1271            {
1272                return false;
1273            }
1274        }
1275
1276        // All other nodes are considered valid
1277        true
1278    }
1279
1280    /// Find dependencies of a symbol
1281    async fn find_dependencies(
1282        &self,
1283        server: &CodePrismMcpServer,
1284        arguments: Option<Value>,
1285    ) -> Result<CallToolResult> {
1286        let args = arguments.ok_or_else(|| anyhow::anyhow!("Missing arguments"))?;
1287
1288        let target = args
1289            .get("target")
1290            .and_then(|v| v.as_str())
1291            .ok_or_else(|| anyhow::anyhow!("Missing target parameter"))?;
1292
1293        let dependency_type_str = args
1294            .get("dependency_type")
1295            .and_then(|v| v.as_str())
1296            .unwrap_or("direct");
1297
1298        let dependency_type = match dependency_type_str {
1299            "direct" => codeprism_core::graph::DependencyType::Direct,
1300            "calls" => codeprism_core::graph::DependencyType::Calls,
1301            "imports" => codeprism_core::graph::DependencyType::Imports,
1302            "reads" => codeprism_core::graph::DependencyType::Reads,
1303            "writes" => codeprism_core::graph::DependencyType::Writes,
1304            _ => {
1305                return Ok(CallToolResult {
1306                    content: vec![ToolContent::Text {
1307                        text: format!("Invalid dependency type: {}", dependency_type_str),
1308                    }],
1309                    is_error: Some(true),
1310                })
1311            }
1312        };
1313
1314        // Try to parse as node ID first, then as file path
1315        let dependencies = if let Ok(node_id) = self.parse_node_id(target) {
1316            server
1317                .graph_query()
1318                .find_dependencies(&node_id, dependency_type)?
1319        } else {
1320            // Handle file path - find all nodes in the file and get their dependencies
1321            let file_path = std::path::PathBuf::from(target);
1322            let nodes = server.graph_store().get_nodes_in_file(&file_path);
1323            let mut all_deps = Vec::new();
1324            for node in nodes {
1325                let deps = server
1326                    .graph_query()
1327                    .find_dependencies(&node.id, dependency_type.clone())?;
1328                all_deps.extend(deps);
1329            }
1330            all_deps
1331        };
1332
1333        // Filter out invalid Call nodes with malformed names
1334        let valid_dependencies: Vec<_> = dependencies
1335            .iter()
1336            .filter(|dep| self.is_valid_dependency_node(&dep.target_node))
1337            .collect();
1338
1339        let result = serde_json::json!({
1340            "target": target,
1341            "dependency_type": dependency_type_str,
1342            "dependencies": valid_dependencies.iter().map(|dep| {
1343                serde_json::json!({
1344                    "id": dep.target_node.id.to_hex(),
1345                    "name": dep.target_node.name,
1346                    "kind": format!("{:?}", dep.target_node.kind),
1347                    "file": dep.target_node.file.display().to_string(),
1348                    "edge_kind": format!("{:?}", dep.edge_kind)
1349                })
1350            }).collect::<Vec<_>>()
1351        });
1352
1353        Ok(CallToolResult {
1354            content: vec![ToolContent::Text {
1355                text: serde_json::to_string_pretty(&result)?,
1356            }],
1357            is_error: Some(false),
1358        })
1359    }
1360
1361    /// Find references to a symbol
1362    async fn find_references(
1363        &self,
1364        server: &CodePrismMcpServer,
1365        arguments: Option<Value>,
1366    ) -> Result<CallToolResult> {
1367        let args = arguments.ok_or_else(|| anyhow::anyhow!("Missing arguments"))?;
1368
1369        let symbol_id_str = args
1370            .get("symbol_id")
1371            .and_then(|v| v.as_str())
1372            .ok_or_else(|| anyhow::anyhow!("Missing symbol_id parameter"))?;
1373
1374        let _include_definitions = args
1375            .get("include_definitions")
1376            .and_then(|v| v.as_bool())
1377            .unwrap_or(true);
1378
1379        let context_lines = args
1380            .get("context_lines")
1381            .and_then(|v| v.as_u64())
1382            .map(|v| v as usize)
1383            .unwrap_or(4);
1384
1385        let symbol_id = self.parse_node_id(symbol_id_str)?;
1386        let references = server.graph_query().find_references(&symbol_id)?;
1387
1388        let result = serde_json::json!({
1389            "symbol_id": symbol_id_str,
1390            "references": references.iter().map(|ref_| {
1391                let mut ref_info = self.create_node_info_with_context(&ref_.source_node, context_lines);
1392                ref_info["edge_kind"] = serde_json::json!(format!("{:?}", ref_.edge_kind));
1393                ref_info["reference_location"] = serde_json::json!({
1394                    "file": ref_.location.file.display().to_string(),
1395                    "span": {
1396                        "start_line": ref_.location.span.start_line,
1397                        "end_line": ref_.location.span.end_line,
1398                        "start_column": ref_.location.span.start_column,
1399                        "end_column": ref_.location.span.end_column
1400                    }
1401                });
1402                ref_info
1403            }).collect::<Vec<_>>()
1404        });
1405
1406        Ok(CallToolResult {
1407            content: vec![ToolContent::Text {
1408                text: serde_json::to_string_pretty(&result)?,
1409            }],
1410            is_error: Some(false),
1411        })
1412    }
1413
1414    /// Search symbols by pattern
1415    async fn search_symbols(
1416        &self,
1417        server: &CodePrismMcpServer,
1418        arguments: Option<Value>,
1419    ) -> Result<CallToolResult> {
1420        let args = arguments.ok_or_else(|| anyhow::anyhow!("Missing arguments"))?;
1421
1422        let pattern = args
1423            .get("pattern")
1424            .and_then(|v| v.as_str())
1425            .ok_or_else(|| anyhow::anyhow!("Missing pattern parameter"))?;
1426
1427        let symbol_types = args
1428            .get("symbol_types")
1429            .and_then(|v| v.as_array())
1430            .map(|arr| {
1431                arr.iter()
1432                    .filter_map(|v| v.as_str())
1433                    .filter_map(|s| match s {
1434                        "function" => Some(codeprism_core::NodeKind::Function),
1435                        "class" => Some(codeprism_core::NodeKind::Class),
1436                        "variable" => Some(codeprism_core::NodeKind::Variable),
1437                        "module" => Some(codeprism_core::NodeKind::Module),
1438                        "method" => Some(codeprism_core::NodeKind::Method),
1439                        _ => None,
1440                    })
1441                    .collect::<Vec<_>>()
1442            });
1443
1444        let inheritance_filters = args
1445            .get("inheritance_filters")
1446            .and_then(|v| v.as_array())
1447            .map(|arr| {
1448                arr.iter()
1449                    .filter_map(|v| v.as_str())
1450                    .filter_map(|s| self.parse_inheritance_filter(s))
1451                    .collect::<Vec<_>>()
1452            });
1453
1454        let limit = args
1455            .get("limit")
1456            .and_then(|v| v.as_u64())
1457            .map(|v| v as usize);
1458
1459        let context_lines = args
1460            .get("context_lines")
1461            .and_then(|v| v.as_u64())
1462            .map(|v| v as usize)
1463            .unwrap_or(4);
1464
1465        // Use enhanced search with inheritance filters if provided
1466        let results = if let Some(ref filters) = inheritance_filters {
1467            server.graph_query().search_symbols_with_inheritance(
1468                pattern,
1469                symbol_types,
1470                Some(filters.clone()),
1471                limit,
1472            )?
1473        } else {
1474            server
1475                .graph_query()
1476                .search_symbols(pattern, symbol_types, limit)?
1477        };
1478
1479        let result = serde_json::json!({
1480            "pattern": pattern,
1481            "inheritance_filters_applied": inheritance_filters.is_some(),
1482            "results": results.iter().map(|symbol| {
1483                let mut symbol_info = self.create_node_info_with_context(&symbol.node, context_lines);
1484                symbol_info["references_count"] = serde_json::json!(symbol.references_count);
1485                symbol_info["dependencies_count"] = serde_json::json!(symbol.dependencies_count);
1486
1487                // Add inheritance info for classes when inheritance filters are used
1488                if matches!(symbol.node.kind, codeprism_core::NodeKind::Class) && inheritance_filters.is_some() {
1489                    if let Ok(inheritance_info) = server.graph_query().get_inheritance_info(&symbol.node.id) {
1490                        symbol_info["inheritance_summary"] = serde_json::json!({
1491                            "is_metaclass": inheritance_info.is_metaclass,
1492                            "base_classes": inheritance_info.base_classes.iter().map(|rel| rel.class_name.clone()).collect::<Vec<_>>(),
1493                            "mixins": inheritance_info.mixins.iter().map(|rel| rel.class_name.clone()).collect::<Vec<_>>(),
1494                            "metaclass": inheritance_info.metaclass.as_ref().map(|mc| mc.class_name.clone())
1495                        });
1496                    }
1497                }
1498
1499                symbol_info
1500            }).collect::<Vec<_>>()
1501        });
1502
1503        Ok(CallToolResult {
1504            content: vec![ToolContent::Text {
1505                text: serde_json::to_string_pretty(&result)?,
1506            }],
1507            is_error: Some(false),
1508        })
1509    }
1510
1511    /// Parse inheritance filter string into InheritanceFilter enum
1512    fn parse_inheritance_filter(
1513        &self,
1514        filter_str: &str,
1515    ) -> Option<codeprism_core::InheritanceFilter> {
1516        if let Some(colon_pos) = filter_str.find(':') {
1517            let filter_type = &filter_str[..colon_pos];
1518            let class_name = &filter_str[colon_pos + 1..];
1519
1520            match filter_type {
1521                "inherits_from" => Some(codeprism_core::InheritanceFilter::InheritsFrom(
1522                    class_name.to_string(),
1523                )),
1524                "metaclass" => Some(codeprism_core::InheritanceFilter::HasMetaclass(
1525                    class_name.to_string(),
1526                )),
1527                "uses_mixin" => Some(codeprism_core::InheritanceFilter::UsesMixin(
1528                    class_name.to_string(),
1529                )),
1530                _ => None,
1531            }
1532        } else {
1533            None
1534        }
1535    }
1536
1537    /// Parse a node ID from a hex string
1538    fn parse_node_id(&self, hex_str: &str) -> Result<codeprism_core::NodeId> {
1539        codeprism_core::NodeId::from_hex(hex_str)
1540            .map_err(|e| anyhow::anyhow!("Invalid node ID format: {}", e))
1541    }
1542
1543    /// Extract source context around a line number from a file
1544    fn extract_source_context(
1545        &self,
1546        file_path: &std::path::Path,
1547        line_number: usize,
1548        context_lines: usize,
1549    ) -> Option<serde_json::Value> {
1550        // Read the file content
1551        let content = match std::fs::read_to_string(file_path) {
1552            Ok(content) => content,
1553            Err(_) => return None,
1554        };
1555
1556        let lines: Vec<&str> = content.lines().collect();
1557        let total_lines = lines.len();
1558
1559        if line_number == 0 || line_number > total_lines {
1560            return None;
1561        }
1562
1563        // Convert to 0-based indexing
1564        let target_line_idx = line_number - 1;
1565
1566        // Calculate context range (with bounds checking)
1567        let start_idx = target_line_idx.saturating_sub(context_lines);
1568        let end_idx = std::cmp::min(target_line_idx + context_lines, total_lines - 1);
1569
1570        // Extract context lines with line numbers
1571        let mut context_lines_with_numbers = Vec::new();
1572        for (i, _) in lines.iter().enumerate().take(end_idx + 1).skip(start_idx) {
1573            context_lines_with_numbers.push(serde_json::json!({
1574                "line_number": i + 1,
1575                "content": lines[i],
1576                "is_target": i == target_line_idx
1577            }));
1578        }
1579
1580        Some(serde_json::json!({
1581            "target_line": line_number,
1582            "context_range": {
1583                "start_line": start_idx + 1,
1584                "end_line": end_idx + 1
1585            },
1586            "lines": context_lines_with_numbers
1587        }))
1588    }
1589
1590    /// Create enhanced node information with source context
1591    fn create_node_info_with_context(
1592        &self,
1593        node: &codeprism_core::Node,
1594        context_lines: usize,
1595    ) -> serde_json::Value {
1596        let mut node_info = serde_json::json!({
1597            "id": node.id.to_hex(),
1598            "name": node.name,
1599            "kind": format!("{:?}", node.kind),
1600            "language": format!("{:?}", node.lang),
1601            "file": node.file.display().to_string(),
1602            "span": {
1603                "start_line": node.span.start_line,
1604                "end_line": node.span.end_line,
1605                "start_column": node.span.start_column,
1606                "end_column": node.span.end_column
1607            },
1608            "signature": node.signature
1609        });
1610
1611        // Add source context around the symbol location
1612        if let Some(context) =
1613            self.extract_source_context(&node.file, node.span.start_line, context_lines)
1614        {
1615            node_info["source_context"] = context;
1616        }
1617
1618        node_info
1619    }
1620
1621    /// Search content across repository
1622    async fn search_content(
1623        &self,
1624        server: &CodePrismMcpServer,
1625        arguments: Option<Value>,
1626    ) -> Result<CallToolResult> {
1627        let args = arguments.ok_or_else(|| anyhow::anyhow!("Missing arguments"))?;
1628
1629        let query = args
1630            .get("query")
1631            .and_then(|v| v.as_str())
1632            .ok_or_else(|| anyhow::anyhow!("Missing query parameter"))?;
1633
1634        let content_types = args
1635            .get("content_types")
1636            .and_then(|v| v.as_array())
1637            .map(|arr| {
1638                arr.iter()
1639                    .filter_map(|v| v.as_str())
1640                    .map(|s| s.to_string())
1641                    .collect::<Vec<_>>()
1642            })
1643            .unwrap_or_default();
1644
1645        let file_patterns = args
1646            .get("file_patterns")
1647            .and_then(|v| v.as_array())
1648            .map(|arr| {
1649                arr.iter()
1650                    .filter_map(|v| v.as_str())
1651                    .map(|s| s.to_string())
1652                    .collect::<Vec<_>>()
1653            })
1654            .unwrap_or_default();
1655
1656        let exclude_patterns = args
1657            .get("exclude_patterns")
1658            .and_then(|v| v.as_array())
1659            .map(|arr| {
1660                arr.iter()
1661                    .filter_map(|v| v.as_str())
1662                    .map(|s| s.to_string())
1663                    .collect::<Vec<_>>()
1664            })
1665            .unwrap_or_default();
1666
1667        let max_results = args
1668            .get("max_results")
1669            .and_then(|v| v.as_u64())
1670            .map(|v| v as usize)
1671            .unwrap_or(50);
1672
1673        let case_sensitive = args
1674            .get("case_sensitive")
1675            .and_then(|v| v.as_bool())
1676            .unwrap_or(false);
1677
1678        let use_regex = args
1679            .get("use_regex")
1680            .and_then(|v| v.as_bool())
1681            .unwrap_or(false);
1682
1683        let include_context = args
1684            .get("include_context")
1685            .and_then(|v| v.as_bool())
1686            .unwrap_or(true);
1687
1688        // Check if content is indexed
1689        let stats = server.content_search().get_stats();
1690        if stats.total_files == 0 {
1691            let result = serde_json::json!({
1692                "query": query,
1693                "results": [],
1694                "total_results": 0,
1695                "status": "no_content_indexed",
1696                "message": "Content search is not yet indexed. This feature requires repository content to be indexed first.",
1697                "suggestion": "Repository indexing may still be in progress. Try again in a few moments."
1698            });
1699
1700            return Ok(CallToolResult {
1701                content: vec![ToolContent::Text {
1702                    text: serde_json::to_string_pretty(&result)?,
1703                }],
1704                is_error: Some(false),
1705            });
1706        }
1707
1708        match server
1709            .content_search()
1710            .simple_search(query, Some(max_results))
1711        {
1712            Ok(search_results) => {
1713                let result = serde_json::json!({
1714                    "query": query,
1715                    "content_types": content_types,
1716                    "file_patterns": file_patterns,
1717                    "exclude_patterns": exclude_patterns,
1718                    "max_results": max_results,
1719                    "case_sensitive": case_sensitive,
1720                    "use_regex": use_regex,
1721                    "include_context": include_context,
1722                    "total_results": search_results.len(),
1723                    "results": search_results.iter().map(|result| {
1724                        serde_json::json!({
1725                            "file": result.chunk.file_path.display().to_string(),
1726                            "content_type": format!("{:?}", result.chunk.content_type),
1727                            "score": result.score,
1728                            "matches": result.matches.iter().map(|m| {
1729                                serde_json::json!({
1730                                    "text": m.text,
1731                                    "line": m.line_number,
1732                                    "column": m.column_number,
1733                                    "context_before": m.context_before,
1734                                    "context_after": m.context_after
1735                                })
1736                            }).collect::<Vec<_>>(),
1737                            "chunk_content_preview": if result.chunk.content.len() > 200 {
1738                                format!("{}...", &result.chunk.content[..200])
1739                            } else {
1740                                result.chunk.content.clone()
1741                            }
1742                        })
1743                    }).collect::<Vec<_>>()
1744                });
1745
1746                Ok(CallToolResult {
1747                    content: vec![ToolContent::Text {
1748                        text: serde_json::to_string_pretty(&result)?,
1749                    }],
1750                    is_error: Some(false),
1751                })
1752            }
1753            Err(e) => Ok(CallToolResult {
1754                content: vec![ToolContent::Text {
1755                    text: format!("Content search error: {}", e),
1756                }],
1757                is_error: Some(true),
1758            }),
1759        }
1760    }
1761
1762    /// Find files by pattern
1763    async fn find_files(
1764        &self,
1765        server: &CodePrismMcpServer,
1766        arguments: Option<Value>,
1767    ) -> Result<CallToolResult> {
1768        let args = arguments.ok_or_else(|| anyhow::anyhow!("Missing arguments"))?;
1769
1770        let pattern = args
1771            .get("pattern")
1772            .and_then(|v| v.as_str())
1773            .ok_or_else(|| anyhow::anyhow!("Missing pattern parameter"))?;
1774
1775        // Check if content is indexed
1776        let stats = server.content_search().get_stats();
1777        if stats.total_files == 0 {
1778            // Fall back to scanning the repository directly
1779            if let Some(repo_path) = server.repository_path() {
1780                match server.scanner().discover_files(repo_path) {
1781                    Ok(all_files) => {
1782                        let pattern_regex = match regex::Regex::new(pattern) {
1783                            Ok(regex) => regex,
1784                            Err(_) => {
1785                                // Fall back to glob-style matching
1786                                let glob_pattern = pattern.replace("*", ".*").replace("?", ".");
1787                                match regex::Regex::new(&glob_pattern) {
1788                                    Ok(regex) => regex,
1789                                    Err(e) => {
1790                                        return Ok(CallToolResult {
1791                                            content: vec![ToolContent::Text {
1792                                                text: format!(
1793                                                    "Invalid pattern '{}': {}",
1794                                                    pattern, e
1795                                                ),
1796                                            }],
1797                                            is_error: Some(true),
1798                                        });
1799                                    }
1800                                }
1801                            }
1802                        };
1803
1804                        let matching_files: Vec<_> = all_files
1805                            .iter()
1806                            .filter(|path| pattern_regex.is_match(&path.to_string_lossy()))
1807                            .collect();
1808
1809                        let result = serde_json::json!({
1810                            "pattern": pattern,
1811                            "total_files": matching_files.len(),
1812                            "source": "repository_scan",
1813                            "files": matching_files.iter().map(|path| {
1814                                serde_json::json!({
1815                                    "path": path.display().to_string(),
1816                                    "name": path.file_name()
1817                                        .and_then(|n| n.to_str())
1818                                        .unwrap_or(""),
1819                                    "extension": path.extension()
1820                                        .and_then(|ext| ext.to_str())
1821                                        .unwrap_or("")
1822                                })
1823                            }).collect::<Vec<_>>()
1824                        });
1825
1826                        return Ok(CallToolResult {
1827                            content: vec![ToolContent::Text {
1828                                text: serde_json::to_string_pretty(&result)?,
1829                            }],
1830                            is_error: Some(false),
1831                        });
1832                    }
1833                    Err(e) => {
1834                        return Ok(CallToolResult {
1835                            content: vec![ToolContent::Text {
1836                                text: format!("Failed to scan repository for files: {}", e),
1837                            }],
1838                            is_error: Some(true),
1839                        });
1840                    }
1841                }
1842            } else {
1843                let result = serde_json::json!({
1844                    "pattern": pattern,
1845                    "total_files": 0,
1846                    "source": "no_repository",
1847                    "files": [],
1848                    "message": "No repository is currently loaded"
1849                });
1850
1851                return Ok(CallToolResult {
1852                    content: vec![ToolContent::Text {
1853                        text: serde_json::to_string_pretty(&result)?,
1854                    }],
1855                    is_error: Some(false),
1856                });
1857            }
1858        }
1859
1860        match server.content_search().find_files(pattern) {
1861            Ok(files) => {
1862                let result = serde_json::json!({
1863                    "pattern": pattern,
1864                    "total_files": files.len(),
1865                    "source": "content_index",
1866                    "files": files.iter().map(|path| {
1867                        serde_json::json!({
1868                            "path": path.display().to_string(),
1869                            "name": path.file_name()
1870                                .and_then(|n| n.to_str())
1871                                .unwrap_or(""),
1872                            "extension": path.extension()
1873                                .and_then(|ext| ext.to_str())
1874                                .unwrap_or("")
1875                        })
1876                    }).collect::<Vec<_>>()
1877                });
1878
1879                Ok(CallToolResult {
1880                    content: vec![ToolContent::Text {
1881                        text: serde_json::to_string_pretty(&result)?,
1882                    }],
1883                    is_error: Some(false),
1884                })
1885            }
1886            Err(e) => Ok(CallToolResult {
1887                content: vec![ToolContent::Text {
1888                    text: format!("File search error: {}", e),
1889                }],
1890                is_error: Some(true),
1891            }),
1892        }
1893    }
1894
1895    /// Get content statistics
1896    async fn content_stats(&self, server: &CodePrismMcpServer) -> Result<CallToolResult> {
1897        let stats = server.content_search().get_stats();
1898
1899        let result = if stats.total_files == 0 {
1900            serde_json::json!({
1901                "total_files": 0,
1902                "total_chunks": 0,
1903                "total_tokens": 0,
1904                "content_by_type": {},
1905                "size_distribution": {},
1906                "status": "no_content_indexed",
1907                "message": "Content indexing has not been performed yet. Only code symbol analysis is available.",
1908                "suggestion": "Content indexing for documentation, configuration files, and comments may still be in progress."
1909            })
1910        } else {
1911            serde_json::json!({
1912                "total_files": stats.total_files,
1913                "total_chunks": stats.total_chunks,
1914                "total_tokens": stats.total_tokens,
1915                "content_by_type": stats.content_by_type,
1916                "size_distribution": stats.size_distribution,
1917                "computed_at": stats.computed_at.duration_since(std::time::UNIX_EPOCH)
1918                    .unwrap_or_default()
1919                    .as_secs(),
1920                "status": "indexed"
1921            })
1922        };
1923
1924        Ok(CallToolResult {
1925            content: vec![ToolContent::Text {
1926                text: serde_json::to_string_pretty(&result)?,
1927            }],
1928            is_error: Some(false),
1929        })
1930    }
1931
1932    /// Analyze code complexity
1933    async fn analyze_complexity(
1934        &self,
1935        server: &CodePrismMcpServer,
1936        arguments: Option<Value>,
1937    ) -> Result<CallToolResult> {
1938        let args = arguments.unwrap_or_default();
1939
1940        let target = match args.get("target").and_then(|v| v.as_str()) {
1941            Some(t) => t,
1942            None => {
1943                return Ok(CallToolResult {
1944                    content: vec![ToolContent::Text {
1945                        text: "Missing required parameter: target".to_string(),
1946                    }],
1947                    is_error: Some(true),
1948                });
1949            }
1950        };
1951
1952        let metrics = args
1953            .get("metrics")
1954            .and_then(|v| v.as_array())
1955            .map(|arr| {
1956                arr.iter()
1957                    .filter_map(|v| v.as_str())
1958                    .map(|s| s.to_string())
1959                    .collect::<Vec<_>>()
1960            })
1961            .unwrap_or_else(|| vec!["all".to_string()]);
1962
1963        let threshold_warnings = args
1964            .get("threshold_warnings")
1965            .and_then(|v| v.as_bool())
1966            .unwrap_or(true);
1967
1968        // Determine if target is a file path or symbol ID
1969        let mut complexity_results = Vec::new();
1970
1971        if target.starts_with('/') || target.contains('.') {
1972            // Treat as file path
1973            if let Some(repo_path) = server.repository_path() {
1974                let file_path = if std::path::Path::new(target).is_absolute() {
1975                    std::path::PathBuf::from(target)
1976                } else {
1977                    repo_path.join(target)
1978                };
1979
1980                if file_path.exists() {
1981                    let file_complexity =
1982                        self.analyze_file_complexity(&file_path, &metrics, threshold_warnings)?;
1983                    complexity_results.push(file_complexity);
1984                } else {
1985                    return Ok(CallToolResult {
1986                        content: vec![ToolContent::Text {
1987                            text: format!("File not found: {}", target),
1988                        }],
1989                        is_error: Some(true),
1990                    });
1991                }
1992            }
1993        } else {
1994            // Treat as symbol ID
1995            if let Ok(symbol_id) = self.parse_node_id(target) {
1996                if let Some(node) = server.graph_store().get_node(&symbol_id) {
1997                    let symbol_complexity =
1998                        self.analyze_symbol_complexity(&node, &metrics, threshold_warnings)?;
1999                    complexity_results.push(symbol_complexity);
2000                } else {
2001                    return Ok(CallToolResult {
2002                        content: vec![ToolContent::Text {
2003                            text: format!("Symbol not found: {}", target),
2004                        }],
2005                        is_error: Some(true),
2006                    });
2007                }
2008            } else {
2009                return Ok(CallToolResult {
2010                    content: vec![ToolContent::Text {
2011                        text: format!("Invalid target format: {}", target),
2012                    }],
2013                    is_error: Some(true),
2014                });
2015            }
2016        }
2017
2018        let result = serde_json::json!({
2019            "target": target,
2020            "metrics_requested": metrics,
2021            "threshold_warnings": threshold_warnings,
2022            "results": complexity_results,
2023            "summary": {
2024                "total_analyzed": complexity_results.len(),
2025                "high_complexity_items": complexity_results.iter()
2026                    .filter(|r| r.get("warnings").and_then(|w| w.as_array()).map(|arr| !arr.is_empty()).unwrap_or(false))
2027                    .count()
2028            }
2029        });
2030
2031        Ok(CallToolResult {
2032            content: vec![ToolContent::Text {
2033                text: serde_json::to_string_pretty(&result)?,
2034            }],
2035            is_error: Some(false),
2036        })
2037    }
2038
2039    /// Analyze complexity for a file
2040    fn analyze_file_complexity(
2041        &self,
2042        file_path: &std::path::Path,
2043        metrics: &[String],
2044        threshold_warnings: bool,
2045    ) -> Result<serde_json::Value> {
2046        // Read file content
2047        let content = std::fs::read_to_string(file_path)
2048            .map_err(|e| anyhow::anyhow!("Failed to read file {}: {}", file_path.display(), e))?;
2049
2050        let lines = content.lines().collect::<Vec<_>>();
2051        let total_lines = lines.len();
2052
2053        // Basic complexity metrics calculation
2054        let mut complexity_metrics = serde_json::json!({
2055            "file": file_path.display().to_string(),
2056            "total_lines": total_lines,
2057            "non_empty_lines": lines.iter().filter(|line| !line.trim().is_empty()).count(),
2058            "metrics": {}
2059        });
2060
2061        let mut warnings = Vec::new();
2062
2063        // Calculate requested metrics
2064        let _include_all = metrics.contains(&"all".to_string());
2065        for metric in metrics {
2066            match metric.as_str() {
2067                "cyclomatic" => {
2068                    let cyclomatic = self.calculate_cyclomatic_complexity(&content);
2069                    complexity_metrics["metrics"]["cyclomatic_complexity"] = serde_json::json!({
2070                        "value": cyclomatic,
2071                        "description": "Number of linearly independent paths through the code"
2072                    });
2073
2074                    if threshold_warnings && cyclomatic > 10 {
2075                        warnings.push(format!(
2076                            "High cyclomatic complexity: {} (threshold: 10)",
2077                            cyclomatic
2078                        ));
2079                    }
2080                }
2081                "cognitive" => {
2082                    let cognitive = self.calculate_cognitive_complexity(&content);
2083                    complexity_metrics["metrics"]["cognitive_complexity"] = serde_json::json!({
2084                        "value": cognitive,
2085                        "description": "Measure of how hard the code is to understand"
2086                    });
2087
2088                    if threshold_warnings && cognitive > 15 {
2089                        warnings.push(format!(
2090                            "High cognitive complexity: {} (threshold: 15)",
2091                            cognitive
2092                        ));
2093                    }
2094                }
2095                "halstead" => {
2096                    let (volume, difficulty, effort) = self.calculate_halstead_metrics(&content);
2097                    complexity_metrics["metrics"]["halstead"] = serde_json::json!({
2098                        "volume": volume,
2099                        "difficulty": difficulty,
2100                        "effort": effort,
2101                        "description": "Halstead complexity metrics based on operators and operands"
2102                    });
2103                }
2104                "maintainability_index" => {
2105                    let mi = self.calculate_maintainability_index(&content, total_lines);
2106                    complexity_metrics["metrics"]["maintainability_index"] = serde_json::json!({
2107                        "value": mi,
2108                        "description": "Maintainability index (0-100, higher is better)"
2109                    });
2110
2111                    if threshold_warnings && mi < 20.0 {
2112                        warnings.push(format!(
2113                            "Low maintainability index: {:.1} (threshold: 20)",
2114                            mi
2115                        ));
2116                    }
2117                }
2118                "all" => {
2119                    // Calculate all metrics
2120                    let cyclomatic = self.calculate_cyclomatic_complexity(&content);
2121                    complexity_metrics["metrics"]["cyclomatic_complexity"] = serde_json::json!({
2122                        "value": cyclomatic,
2123                        "description": "Number of linearly independent paths through the code"
2124                    });
2125                    if threshold_warnings && cyclomatic > 10 {
2126                        warnings.push(format!(
2127                            "High cyclomatic complexity: {} (threshold: 10)",
2128                            cyclomatic
2129                        ));
2130                    }
2131
2132                    let cognitive = self.calculate_cognitive_complexity(&content);
2133                    complexity_metrics["metrics"]["cognitive_complexity"] = serde_json::json!({
2134                        "value": cognitive,
2135                        "description": "Measure of how hard the code is to understand"
2136                    });
2137                    if threshold_warnings && cognitive > 15 {
2138                        warnings.push(format!(
2139                            "High cognitive complexity: {} (threshold: 15)",
2140                            cognitive
2141                        ));
2142                    }
2143
2144                    let (volume, difficulty, effort) = self.calculate_halstead_metrics(&content);
2145                    complexity_metrics["metrics"]["halstead"] = serde_json::json!({
2146                        "volume": volume,
2147                        "difficulty": difficulty,
2148                        "effort": effort,
2149                        "description": "Halstead complexity metrics based on operators and operands"
2150                    });
2151
2152                    let mi = self.calculate_maintainability_index(&content, total_lines);
2153                    complexity_metrics["metrics"]["maintainability_index"] = serde_json::json!({
2154                        "value": mi,
2155                        "description": "Maintainability index (0-100, higher is better)"
2156                    });
2157                    if threshold_warnings && mi < 20.0 {
2158                        warnings.push(format!(
2159                            "Low maintainability index: {:.1} (threshold: 20)",
2160                            mi
2161                        ));
2162                    }
2163                }
2164                _ => {
2165                    // Skip unknown metrics
2166                }
2167            }
2168        }
2169
2170        if !warnings.is_empty() {
2171            complexity_metrics["warnings"] = serde_json::json!(warnings);
2172        }
2173
2174        Ok(complexity_metrics)
2175    }
2176
2177    /// Analyze complexity for a specific symbol
2178    fn analyze_symbol_complexity(
2179        &self,
2180        node: &codeprism_core::Node,
2181        metrics: &[String],
2182        threshold_warnings: bool,
2183    ) -> Result<serde_json::Value> {
2184        // Read the file containing the symbol
2185        let content = std::fs::read_to_string(&node.file)
2186            .map_err(|e| anyhow::anyhow!("Failed to read file {}: {}", node.file.display(), e))?;
2187
2188        // Extract symbol's content based on span
2189        let lines = content.lines().collect::<Vec<_>>();
2190        let symbol_content = if node.span.start_line <= lines.len()
2191            && node.span.end_line <= lines.len()
2192        {
2193            lines[(node.span.start_line - 1).max(0)..node.span.end_line.min(lines.len())].join("\n")
2194        } else {
2195            content.clone()
2196        };
2197
2198        let symbol_lines = node.span.end_line - node.span.start_line + 1;
2199
2200        let mut complexity_metrics = serde_json::json!({
2201            "symbol": {
2202                "id": node.id.to_hex(),
2203                "name": node.name,
2204                "kind": format!("{:?}", node.kind),
2205                "file": node.file.display().to_string(),
2206                "span": {
2207                    "start_line": node.span.start_line,
2208                    "end_line": node.span.end_line,
2209                    "lines": symbol_lines
2210                }
2211            },
2212            "metrics": {}
2213        });
2214
2215        let mut warnings = Vec::new();
2216
2217        // Calculate requested metrics for the symbol
2218        for metric in metrics {
2219            match metric.as_str() {
2220                "cyclomatic" => {
2221                    let cyclomatic = self.calculate_cyclomatic_complexity(&symbol_content);
2222                    complexity_metrics["metrics"]["cyclomatic_complexity"] = serde_json::json!({
2223                        "value": cyclomatic,
2224                        "description": "Number of linearly independent paths through the symbol"
2225                    });
2226
2227                    if threshold_warnings && cyclomatic > 10 {
2228                        warnings.push(format!(
2229                            "High cyclomatic complexity: {} (threshold: 10)",
2230                            cyclomatic
2231                        ));
2232                    }
2233                }
2234                "cognitive" => {
2235                    let cognitive = self.calculate_cognitive_complexity(&symbol_content);
2236                    complexity_metrics["metrics"]["cognitive_complexity"] = serde_json::json!({
2237                        "value": cognitive,
2238                        "description": "Measure of how hard the symbol is to understand"
2239                    });
2240
2241                    if threshold_warnings && cognitive > 15 {
2242                        warnings.push(format!(
2243                            "High cognitive complexity: {} (threshold: 15)",
2244                            cognitive
2245                        ));
2246                    }
2247                }
2248                "halstead" => {
2249                    let (volume, difficulty, effort) =
2250                        self.calculate_halstead_metrics(&symbol_content);
2251                    complexity_metrics["metrics"]["halstead"] = serde_json::json!({
2252                        "volume": volume,
2253                        "difficulty": difficulty,
2254                        "effort": effort,
2255                        "description": "Halstead complexity metrics for the symbol"
2256                    });
2257                }
2258                "maintainability_index" => {
2259                    let mi = self.calculate_maintainability_index(&symbol_content, symbol_lines);
2260                    complexity_metrics["metrics"]["maintainability_index"] = serde_json::json!({
2261                        "value": mi,
2262                        "description": "Maintainability index for the symbol (0-100, higher is better)"
2263                    });
2264
2265                    if threshold_warnings && mi < 20.0 {
2266                        warnings.push(format!(
2267                            "Low maintainability index: {:.1} (threshold: 20)",
2268                            mi
2269                        ));
2270                    }
2271                }
2272                "all" => {
2273                    // Calculate all metrics for the symbol
2274                    let cyclomatic = self.calculate_cyclomatic_complexity(&symbol_content);
2275                    complexity_metrics["metrics"]["cyclomatic_complexity"] = serde_json::json!({
2276                        "value": cyclomatic,
2277                        "description": "Number of linearly independent paths through the symbol"
2278                    });
2279                    if threshold_warnings && cyclomatic > 10 {
2280                        warnings.push(format!(
2281                            "High cyclomatic complexity: {} (threshold: 10)",
2282                            cyclomatic
2283                        ));
2284                    }
2285
2286                    let cognitive = self.calculate_cognitive_complexity(&symbol_content);
2287                    complexity_metrics["metrics"]["cognitive_complexity"] = serde_json::json!({
2288                        "value": cognitive,
2289                        "description": "Measure of how hard the symbol is to understand"
2290                    });
2291                    if threshold_warnings && cognitive > 15 {
2292                        warnings.push(format!(
2293                            "High cognitive complexity: {} (threshold: 15)",
2294                            cognitive
2295                        ));
2296                    }
2297
2298                    let (volume, difficulty, effort) =
2299                        self.calculate_halstead_metrics(&symbol_content);
2300                    complexity_metrics["metrics"]["halstead"] = serde_json::json!({
2301                        "volume": volume,
2302                        "difficulty": difficulty,
2303                        "effort": effort,
2304                        "description": "Halstead complexity metrics for the symbol"
2305                    });
2306
2307                    let mi = self.calculate_maintainability_index(&symbol_content, symbol_lines);
2308                    complexity_metrics["metrics"]["maintainability_index"] = serde_json::json!({
2309                        "value": mi,
2310                        "description": "Maintainability index for the symbol (0-100, higher is better)"
2311                    });
2312                    if threshold_warnings && mi < 20.0 {
2313                        warnings.push(format!(
2314                            "Low maintainability index: {:.1} (threshold: 20)",
2315                            mi
2316                        ));
2317                    }
2318                }
2319                _ => {
2320                    // Skip unknown metrics
2321                }
2322            }
2323        }
2324
2325        if !warnings.is_empty() {
2326            complexity_metrics["warnings"] = serde_json::json!(warnings);
2327        }
2328
2329        Ok(complexity_metrics)
2330    }
2331
2332    /// Calculate cyclomatic complexity (simplified)
2333    fn calculate_cyclomatic_complexity(&self, content: &str) -> usize {
2334        let mut complexity = 1; // Base complexity
2335
2336        // Count decision points (simplified heuristic)
2337        let decision_keywords = [
2338            "if", "else if", "elif", "while", "for", "foreach", "switch", "case", "catch",
2339            "except", "?", "&&", "||", "and", "or",
2340        ];
2341
2342        for keyword in &decision_keywords {
2343            complexity += content.matches(keyword).count();
2344        }
2345
2346        complexity
2347    }
2348
2349    /// Calculate cognitive complexity (simplified)
2350    fn calculate_cognitive_complexity(&self, content: &str) -> usize {
2351        let mut complexity = 0;
2352        let mut nesting_level: usize = 0;
2353
2354        let lines = content.lines();
2355        for line in lines {
2356            let trimmed = line.trim();
2357
2358            // Increment nesting for certain constructs
2359            if trimmed.contains('{')
2360                || trimmed.starts_with("if ")
2361                || trimmed.starts_with("for ")
2362                || trimmed.starts_with("while ")
2363                || trimmed.starts_with("try ")
2364                || trimmed.starts_with("def ")
2365                || trimmed.starts_with("function ")
2366            {
2367                nesting_level += 1;
2368            }
2369
2370            // Decrement nesting
2371            if trimmed.contains('}') {
2372                nesting_level = nesting_level.saturating_sub(1usize);
2373            }
2374
2375            // Add complexity based on constructs
2376            if trimmed.contains("if ") || trimmed.contains("elif ") || trimmed.contains("else if") {
2377                complexity += 1 + nesting_level;
2378            }
2379            if trimmed.contains("while ") || trimmed.contains("for ") {
2380                complexity += 1 + nesting_level;
2381            }
2382            if trimmed.contains("catch ") || trimmed.contains("except ") {
2383                complexity += 1 + nesting_level;
2384            }
2385        }
2386
2387        complexity
2388    }
2389
2390    /// Calculate Halstead complexity metrics (simplified)
2391    fn calculate_halstead_metrics(&self, content: &str) -> (f64, f64, f64) {
2392        // Simplified Halstead calculation
2393        let operators = [
2394            "=", "+", "-", "*", "/", "==", "!=", "<", ">", "<=", ">=", "&&", "||",
2395        ];
2396        let mut unique_operators = std::collections::HashSet::new();
2397        let mut total_operators = 0;
2398
2399        for op in &operators {
2400            let count = content.matches(op).count();
2401            if count > 0 {
2402                unique_operators.insert(op);
2403                total_operators += count;
2404            }
2405        }
2406
2407        // Rough operand estimation (identifiers, literals)
2408        let words: Vec<&str> = content.split_whitespace().collect();
2409        let mut unique_operands = std::collections::HashSet::new();
2410        let mut total_operands = 0;
2411
2412        for word in words {
2413            if word.chars().any(|c| c.is_alphanumeric()) {
2414                unique_operands.insert(word);
2415                total_operands += 1;
2416            }
2417        }
2418
2419        let n1 = unique_operators.len().max(1) as f64; // Minimum 1 operator
2420        let n2 = unique_operands.len().max(1) as f64; // Minimum 1 operand
2421        let big_n1 = total_operators.max(1) as f64; // Minimum 1 operator usage
2422        let big_n2 = total_operands.max(1) as f64; // Minimum 1 operand usage
2423
2424        let vocabulary = n1 + n2;
2425        let length = big_n1 + big_n2;
2426
2427        // Ensure vocabulary is at least 2 to avoid log2(1) = 0
2428        let safe_vocabulary = vocabulary.max(2.0);
2429        let volume = length * safe_vocabulary.log2();
2430
2431        // Safe difficulty calculation
2432        let difficulty = (n1 / 2.0) * (big_n2 / n2);
2433        let effort = difficulty * volume;
2434
2435        (volume, difficulty, effort)
2436    }
2437
2438    /// Calculate maintainability index (simplified)
2439    fn calculate_maintainability_index(&self, content: &str, lines_count: usize) -> f64 {
2440        let (volume, difficulty, _effort) = self.calculate_halstead_metrics(content);
2441        let cyclomatic = self.calculate_cyclomatic_complexity(content) as f64;
2442        let loc = lines_count.max(1) as f64; // Minimum 1 line
2443
2444        // Ensure volume is meaningful for logarithm
2445        let safe_volume = volume.max(1.0);
2446        let safe_loc = loc.max(1.0);
2447
2448        // Adjusted maintainability index formula to be more sensitive
2449        // Based on the standard formula but with adjusted coefficients for this simplified implementation
2450        // Higher volume, complexity, and difficulty should decrease maintainability more significantly
2451        let volume_penalty = safe_volume.ln() * 8.0; // Increased from 5.2
2452        let complexity_penalty = cyclomatic * 5.0; // Increased from 0.23
2453        let loc_penalty = safe_loc.ln() * 20.0; // Increased from 16.2
2454        let difficulty_penalty = difficulty * 2.0; // Add difficulty factor
2455
2456        let mi = 171.0 - volume_penalty - complexity_penalty - loc_penalty - difficulty_penalty;
2457
2458        // Ensure result is in valid range
2459        mi.clamp(0.0, 100.0)
2460    }
2461
2462    /// Calculate content similarity between two text blocks (simplified)
2463    fn _calculate_content_similarity(&self, content1: &str, content2: &str) -> f64 {
2464        let lines1: Vec<String> = content1
2465            .lines()
2466            .map(|s| s.trim().to_string())
2467            .filter(|s| !s.is_empty())
2468            .collect();
2469        let lines2: Vec<String> = content2
2470            .lines()
2471            .map(|s| s.trim().to_string())
2472            .filter(|s| !s.is_empty())
2473            .collect();
2474
2475        if lines1.is_empty() || lines2.is_empty() {
2476            return 0.0;
2477        }
2478
2479        // Simple line-based similarity using Jaccard coefficient
2480        let set1: std::collections::HashSet<String> = lines1.into_iter().collect();
2481        let set2: std::collections::HashSet<String> = lines2.into_iter().collect();
2482
2483        if set1.is_empty() && set2.is_empty() {
2484            return 1.0;
2485        }
2486
2487        let intersection = set1.intersection(&set2).count();
2488        let union = set1.union(&set2).count();
2489
2490        if union == 0 {
2491            0.0
2492        } else {
2493            intersection as f64 / union as f64
2494        }
2495    }
2496
2497    /// Detect design patterns in the codebase
2498    async fn detect_patterns(
2499        &self,
2500        server: &CodePrismMcpServer,
2501        arguments: Option<Value>,
2502    ) -> Result<CallToolResult> {
2503        let args = arguments.unwrap_or_default();
2504
2505        let scope = args
2506            .get("scope")
2507            .and_then(|v| v.as_str())
2508            .unwrap_or("repository");
2509
2510        let pattern_types: Vec<String> = args
2511            .get("pattern_types")
2512            .and_then(|v| v.as_array())
2513            .map(|arr| {
2514                arr.iter()
2515                    .filter_map(|v| v.as_str())
2516                    .map(|s| s.to_string())
2517                    .collect()
2518            })
2519            .unwrap_or_else(|| vec!["all".to_string()]);
2520
2521        let confidence_threshold = args
2522            .get("confidence_threshold")
2523            .and_then(|v| v.as_f64())
2524            .unwrap_or(0.8);
2525
2526        let include_suggestions = args
2527            .get("include_suggestions")
2528            .and_then(|v| v.as_bool())
2529            .unwrap_or(true);
2530
2531        let result = if let Some(_repo_path) = server.repository_path() {
2532            let detected_patterns = self
2533                .analyze_design_patterns(
2534                    server,
2535                    &pattern_types,
2536                    confidence_threshold,
2537                    include_suggestions,
2538                )
2539                .await?;
2540
2541            serde_json::json!({
2542                "scope": scope,
2543                "patterns": detected_patterns,
2544                "summary": {
2545                    "total_patterns_detected": detected_patterns.len(),
2546                    "confidence_threshold": confidence_threshold,
2547                    "pattern_types_analyzed": pattern_types
2548                },
2549                "analysis_successful": true
2550            })
2551        } else {
2552            serde_json::json!({
2553                "error": "No repository initialized",
2554                "analysis_successful": false
2555            })
2556        };
2557
2558        Ok(CallToolResult {
2559            content: vec![ToolContent::Text {
2560                text: serde_json::to_string_pretty(&result)?,
2561            }],
2562            is_error: Some(false),
2563        })
2564    }
2565
2566    /// Analyze transitive dependencies
2567    async fn analyze_transitive_dependencies(
2568        &self,
2569        server: &CodePrismMcpServer,
2570        arguments: Option<Value>,
2571    ) -> Result<CallToolResult> {
2572        let args = arguments.ok_or_else(|| anyhow::anyhow!("Missing arguments"))?;
2573
2574        let target = args
2575            .get("target")
2576            .and_then(|v| v.as_str())
2577            .ok_or_else(|| anyhow::anyhow!("Missing target parameter"))?;
2578
2579        let max_depth = args
2580            .get("max_depth")
2581            .and_then(|v| v.as_u64())
2582            .map(|v| v as usize)
2583            .unwrap_or(5);
2584
2585        let detect_cycles = args
2586            .get("detect_cycles")
2587            .and_then(|v| v.as_bool())
2588            .unwrap_or(true);
2589
2590        let include_external = args
2591            .get("include_external_dependencies")
2592            .and_then(|v| v.as_bool())
2593            .unwrap_or(false);
2594
2595        let dependency_types: Vec<String> = args
2596            .get("dependency_types")
2597            .and_then(|v| v.as_array())
2598            .map(|arr| {
2599                arr.iter()
2600                    .filter_map(|v| v.as_str())
2601                    .map(|s| s.to_string())
2602                    .collect()
2603            })
2604            .unwrap_or_else(|| vec!["all".to_string()]);
2605
2606        let result = if let Some(_repo_path) = server.repository_path() {
2607            let analysis = self
2608                .perform_transitive_analysis(
2609                    server,
2610                    target,
2611                    max_depth,
2612                    detect_cycles,
2613                    include_external,
2614                    &dependency_types,
2615                )
2616                .await?;
2617
2618            serde_json::json!({
2619                "target": target,
2620                "analysis": analysis,
2621                "parameters": {
2622                    "max_depth": max_depth,
2623                    "detect_cycles": detect_cycles,
2624                    "include_external": include_external,
2625                    "dependency_types": dependency_types
2626                },
2627                "analysis_successful": true
2628            })
2629        } else {
2630            serde_json::json!({
2631                "error": "No repository initialized",
2632                "analysis_successful": false
2633            })
2634        };
2635
2636        Ok(CallToolResult {
2637            content: vec![ToolContent::Text {
2638                text: serde_json::to_string_pretty(&result)?,
2639            }],
2640            is_error: Some(false),
2641        })
2642    }
2643
2644    /// Trace data flow through the codebase
2645    async fn trace_data_flow(
2646        &self,
2647        server: &CodePrismMcpServer,
2648        arguments: Option<Value>,
2649    ) -> Result<CallToolResult> {
2650        let args = arguments.ok_or_else(|| anyhow::anyhow!("Missing arguments"))?;
2651
2652        let variable_or_parameter = args
2653            .get("variable_or_parameter")
2654            .and_then(|v| v.as_str())
2655            .ok_or_else(|| anyhow::anyhow!("Missing variable_or_parameter parameter"))?;
2656
2657        let direction = args
2658            .get("direction")
2659            .and_then(|v| v.as_str())
2660            .unwrap_or("forward");
2661
2662        let include_transformations = args
2663            .get("include_transformations")
2664            .and_then(|v| v.as_bool())
2665            .unwrap_or(true);
2666
2667        let max_depth = args
2668            .get("max_depth")
2669            .and_then(|v| v.as_u64())
2670            .map(|v| v as usize)
2671            .unwrap_or(10);
2672
2673        let follow_function_calls = args
2674            .get("follow_function_calls")
2675            .and_then(|v| v.as_bool())
2676            .unwrap_or(true);
2677
2678        let include_field_access = args
2679            .get("include_field_access")
2680            .and_then(|v| v.as_bool())
2681            .unwrap_or(true);
2682
2683        let symbol_id = self.parse_node_id(variable_or_parameter)?;
2684
2685        let data_flow_result = self
2686            .perform_data_flow_analysis(
2687                server,
2688                &symbol_id,
2689                direction,
2690                include_transformations,
2691                max_depth,
2692                follow_function_calls,
2693                include_field_access,
2694            )
2695            .await?;
2696
2697        Ok(CallToolResult {
2698            content: vec![ToolContent::Text {
2699                text: serde_json::to_string_pretty(&data_flow_result)?,
2700            }],
2701            is_error: Some(false),
2702        })
2703    }
2704
2705    /// Trace complete inheritance hierarchy for a class
2706    async fn trace_inheritance(
2707        &self,
2708        server: &CodePrismMcpServer,
2709        arguments: Option<Value>,
2710    ) -> Result<CallToolResult> {
2711        let args = arguments.ok_or_else(|| anyhow::anyhow!("Missing arguments"))?;
2712
2713        // Get target class - either by name or ID
2714        let target_classes =
2715            if let Some(class_name) = args.get("class_name").and_then(|v| v.as_str()) {
2716                // Search for classes by name
2717                let symbol_types = Some(vec![codeprism_core::NodeKind::Class]);
2718                let limit = Some(10);
2719                let search_results =
2720                    server
2721                        .graph_query()
2722                        .search_symbols(class_name, symbol_types, limit)?;
2723
2724                if search_results.is_empty() {
2725                    return Ok(CallToolResult {
2726                        content: vec![ToolContent::Text {
2727                            text: format!("No classes found matching pattern: {}", class_name),
2728                        }],
2729                        is_error: Some(true),
2730                    });
2731                }
2732
2733                // Convert SymbolInfo to classes
2734                search_results
2735                    .into_iter()
2736                    .filter_map(|symbol| server.graph_store().get_node(&symbol.node.id))
2737                    .filter(|node| matches!(node.kind, codeprism_core::NodeKind::Class))
2738                    .collect::<Vec<_>>()
2739            } else if let Some(class_id_str) = args.get("class_id").and_then(|v| v.as_str()) {
2740                // Use specific class ID
2741                let class_id = self.parse_node_id(class_id_str)?;
2742                if let Some(node) = server.graph_store().get_node(&class_id) {
2743                    if matches!(node.kind, codeprism_core::NodeKind::Class) {
2744                        vec![node]
2745                    } else {
2746                        return Ok(CallToolResult {
2747                            content: vec![ToolContent::Text {
2748                                text: format!("Node {} is not a class", class_id_str),
2749                            }],
2750                            is_error: Some(true),
2751                        });
2752                    }
2753                } else {
2754                    return Ok(CallToolResult {
2755                        content: vec![ToolContent::Text {
2756                            text: format!("Class not found: {}", class_id_str),
2757                        }],
2758                        is_error: Some(true),
2759                    });
2760                }
2761            } else {
2762                return Ok(CallToolResult {
2763                    content: vec![ToolContent::Text {
2764                        text: "Either class_name or class_id parameter is required".to_string(),
2765                    }],
2766                    is_error: Some(true),
2767                });
2768            };
2769
2770        // Parse options
2771        let direction = args
2772            .get("direction")
2773            .and_then(|v| v.as_str())
2774            .unwrap_or("both");
2775
2776        let include_metaclasses = args
2777            .get("include_metaclasses")
2778            .and_then(|v| v.as_bool())
2779            .unwrap_or(true);
2780
2781        let include_mixins = args
2782            .get("include_mixins")
2783            .and_then(|v| v.as_bool())
2784            .unwrap_or(true);
2785
2786        let include_mro = args
2787            .get("include_mro")
2788            .and_then(|v| v.as_bool())
2789            .unwrap_or(true);
2790
2791        let include_dynamic_attributes = args
2792            .get("include_dynamic_attributes")
2793            .and_then(|v| v.as_bool())
2794            .unwrap_or(true);
2795
2796        let max_depth = args
2797            .get("max_depth")
2798            .and_then(|v| v.as_u64())
2799            .map(|v| v as usize)
2800            .unwrap_or(10);
2801
2802        let include_source_context = args
2803            .get("include_source_context")
2804            .and_then(|v| v.as_bool())
2805            .unwrap_or(false);
2806
2807        // Analyze each target class
2808        let mut analysis_results = Vec::new();
2809
2810        for target_class in &target_classes {
2811            let inheritance_info = server
2812                .graph_query()
2813                .get_inheritance_info(&target_class.id)?;
2814
2815            // Build inheritance tree visualization
2816            let inheritance_tree = self
2817                .build_inheritance_tree(
2818                    server,
2819                    &target_class.id,
2820                    direction,
2821                    max_depth,
2822                    include_source_context,
2823                )
2824                .await?;
2825
2826            // Metaclass analysis
2827            let metaclass_analysis = if include_metaclasses && inheritance_info.metaclass.is_some()
2828            {
2829                Some(
2830                    self.analyze_metaclass_impact(server, &inheritance_info)
2831                        .await?,
2832                )
2833            } else {
2834                None
2835            };
2836
2837            // Mixin analysis
2838            let mixin_analysis = if include_mixins && !inheritance_info.mixins.is_empty() {
2839                Some(
2840                    self.analyze_mixin_relationships(server, &inheritance_info)
2841                        .await?,
2842                )
2843            } else {
2844                None
2845            };
2846
2847            // Method Resolution Order
2848            let mro_analysis =
2849                if include_mro && !inheritance_info.method_resolution_order.is_empty() {
2850                    Some(
2851                        self.analyze_method_resolution_order(server, &inheritance_info)
2852                            .await?,
2853                    )
2854                } else {
2855                    None
2856                };
2857
2858            // Dynamic attributes analysis
2859            let dynamic_attributes_analysis =
2860                if include_dynamic_attributes && !inheritance_info.dynamic_attributes.is_empty() {
2861                    Some(
2862                        self.analyze_dynamic_attributes(server, &inheritance_info)
2863                            .await?,
2864                    )
2865                } else {
2866                    None
2867                };
2868
2869            // Diamond inheritance detection
2870            let diamond_inheritance = self
2871                .detect_diamond_inheritance(server, &target_class.id)
2872                .await?;
2873
2874            let mut analysis = serde_json::json!({
2875                "target_class": {
2876                    "id": target_class.id.to_hex(),
2877                    "name": target_class.name,
2878                    "file": target_class.file.display().to_string(),
2879                    "span": {
2880                        "start_line": target_class.span.start_line,
2881                        "end_line": target_class.span.end_line,
2882                        "start_column": target_class.span.start_column,
2883                        "end_column": target_class.span.end_column
2884                    }
2885                },
2886                "inheritance_tree": inheritance_tree,
2887                "diamond_inheritance": diamond_inheritance,
2888                "basic_inheritance_info": {
2889                    "is_metaclass": inheritance_info.is_metaclass,
2890                    "base_classes_count": inheritance_info.base_classes.len(),
2891                    "subclasses_count": inheritance_info.subclasses.len(),
2892                    "inheritance_depth": inheritance_info.inheritance_chain.len() - 1
2893                }
2894            });
2895
2896            // Add optional analyses
2897            if let Some(metaclass) = metaclass_analysis {
2898                analysis["metaclass_analysis"] = metaclass;
2899            }
2900
2901            if let Some(mixins) = mixin_analysis {
2902                analysis["mixin_analysis"] = mixins;
2903            }
2904
2905            if let Some(mro) = mro_analysis {
2906                analysis["method_resolution_order"] = mro;
2907            }
2908
2909            if let Some(dynamic_attrs) = dynamic_attributes_analysis {
2910                analysis["dynamic_attributes_analysis"] = dynamic_attrs;
2911            }
2912
2913            analysis_results.push(analysis);
2914        }
2915
2916        let result = serde_json::json!({
2917            "analysis_results": analysis_results,
2918            "summary": {
2919                "classes_analyzed": target_classes.len(),
2920                "direction": direction,
2921                "max_depth": max_depth,
2922                "options": {
2923                    "include_metaclasses": include_metaclasses,
2924                    "include_mixins": include_mixins,
2925                    "include_mro": include_mro,
2926                    "include_dynamic_attributes": include_dynamic_attributes,
2927                    "include_source_context": include_source_context
2928                }
2929            }
2930        });
2931
2932        Ok(CallToolResult {
2933            content: vec![ToolContent::Text {
2934                text: serde_json::to_string_pretty(&result)?,
2935            }],
2936            is_error: Some(false),
2937        })
2938    }
2939
2940    /// Build complete inheritance tree visualization
2941    async fn build_inheritance_tree(
2942        &self,
2943        server: &CodePrismMcpServer,
2944        class_id: &codeprism_core::NodeId,
2945        direction: &str,
2946        max_depth: usize,
2947        include_source_context: bool,
2948    ) -> Result<serde_json::Value> {
2949        let mut tree = serde_json::Map::new();
2950        let mut visited = std::collections::HashSet::new();
2951
2952        // Build tree recursively
2953        self.build_tree_recursive(
2954            server,
2955            class_id,
2956            &mut tree,
2957            &mut visited,
2958            direction,
2959            0,
2960            max_depth,
2961            include_source_context,
2962        )
2963        .await?;
2964
2965        Ok(serde_json::Value::Object(tree))
2966    }
2967
2968    /// Recursive helper for building inheritance tree
2969    fn build_tree_recursive<'a>(
2970        &'a self,
2971        server: &'a CodePrismMcpServer,
2972        class_id: &'a codeprism_core::NodeId,
2973        tree: &'a mut serde_json::Map<String, serde_json::Value>,
2974        visited: &'a mut std::collections::HashSet<codeprism_core::NodeId>,
2975        direction: &'a str,
2976        current_depth: usize,
2977        max_depth: usize,
2978        include_source_context: bool,
2979    ) -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<()>> + 'a>> {
2980        Box::pin(async move {
2981            // Prevent infinite recursion and excessive depth
2982            if current_depth >= max_depth || visited.contains(class_id) {
2983                return Ok(());
2984            }
2985
2986            visited.insert(*class_id);
2987
2988            if let Some(class_node) = server.graph_store().get_node(class_id) {
2989                if let Ok(inheritance_info) = server.graph_query().get_inheritance_info(class_id) {
2990                    let mut class_data = serde_json::Map::new();
2991
2992                    // Basic class information
2993                    class_data.insert(
2994                        "id".to_string(),
2995                        serde_json::Value::String(class_id.to_hex()),
2996                    );
2997                    class_data.insert(
2998                        "name".to_string(),
2999                        serde_json::Value::String(class_node.name.clone()),
3000                    );
3001                    class_data.insert(
3002                        "file".to_string(),
3003                        serde_json::Value::String(class_node.file.display().to_string()),
3004                    );
3005                    class_data.insert(
3006                        "is_metaclass".to_string(),
3007                        serde_json::Value::Bool(inheritance_info.is_metaclass),
3008                    );
3009
3010                    // Add source context if requested
3011                    if include_source_context {
3012                        if let Some(context) = self.extract_source_context(
3013                            &class_node.file,
3014                            class_node.span.start_line,
3015                            3,
3016                        ) {
3017                            class_data.insert("source_context".to_string(), context);
3018                        }
3019                    }
3020
3021                    // Metaclass information
3022                    if let Some(metaclass) = &inheritance_info.metaclass {
3023                        class_data.insert(
3024                            "metaclass".to_string(),
3025                            serde_json::json!({
3026                                "name": metaclass.class_name,
3027                                "file": metaclass.file.display().to_string()
3028                            }),
3029                        );
3030                    }
3031
3032                    // Process parent classes (up direction)
3033                    if direction == "up" || direction == "both" {
3034                        let mut parents = serde_json::Map::new();
3035                        for base_class in &inheritance_info.base_classes {
3036                            // Try to find the actual base class node
3037                            let base_classes = server
3038                                .graph_store()
3039                                .get_nodes_by_kind(codeprism_core::NodeKind::Class);
3040                            if let Some(base_node) = base_classes
3041                                .iter()
3042                                .find(|node| node.name == base_class.class_name)
3043                            {
3044                                self.build_tree_recursive(
3045                                    server,
3046                                    &base_node.id,
3047                                    &mut parents,
3048                                    visited,
3049                                    direction,
3050                                    current_depth + 1,
3051                                    max_depth,
3052                                    include_source_context,
3053                                )
3054                                .await?;
3055                            } else {
3056                                // External class (not in our codebase)
3057                                parents.insert(
3058                                    base_class.class_name.clone(),
3059                                    serde_json::json!({
3060                                        "name": base_class.class_name,
3061                                        "external": true,
3062                                        "relationship_type": base_class.relationship_type
3063                                    }),
3064                                );
3065                            }
3066                        }
3067                        if !parents.is_empty() {
3068                            class_data.insert(
3069                                "parent_classes".to_string(),
3070                                serde_json::Value::Object(parents),
3071                            );
3072                        }
3073                    }
3074
3075                    // Process child classes (down direction)
3076                    if direction == "down" || direction == "both" {
3077                        let mut children = serde_json::Map::new();
3078                        for subclass in &inheritance_info.subclasses {
3079                            // Try to find the actual subclass node
3080                            let subclasses = server
3081                                .graph_store()
3082                                .get_nodes_by_kind(codeprism_core::NodeKind::Class);
3083                            if let Some(sub_node) = subclasses
3084                                .iter()
3085                                .find(|node| node.name == subclass.class_name)
3086                            {
3087                                self.build_tree_recursive(
3088                                    server,
3089                                    &sub_node.id,
3090                                    &mut children,
3091                                    visited,
3092                                    direction,
3093                                    current_depth + 1,
3094                                    max_depth,
3095                                    include_source_context,
3096                                )
3097                                .await?;
3098                            }
3099                        }
3100                        if !children.is_empty() {
3101                            class_data.insert(
3102                                "child_classes".to_string(),
3103                                serde_json::Value::Object(children),
3104                            );
3105                        }
3106                    }
3107
3108                    // Add mixins if any
3109                    if !inheritance_info.mixins.is_empty() {
3110                        let mixins: Vec<_> = inheritance_info
3111                            .mixins
3112                            .iter()
3113                            .map(|mixin| {
3114                                serde_json::json!({
3115                                    "name": mixin.class_name,
3116                                    "file": mixin.file.display().to_string()
3117                                })
3118                            })
3119                            .collect();
3120                        class_data.insert("mixins".to_string(), serde_json::Value::Array(mixins));
3121                    }
3122
3123                    tree.insert(
3124                        class_node.name.clone(),
3125                        serde_json::Value::Object(class_data),
3126                    );
3127                }
3128            }
3129
3130            Ok(())
3131        })
3132    }
3133
3134    /// Analyze metaclass impact on inheritance hierarchy
3135    async fn analyze_metaclass_impact(
3136        &self,
3137        server: &CodePrismMcpServer,
3138        inheritance_info: &codeprism_core::InheritanceInfo,
3139    ) -> Result<serde_json::Value> {
3140        if let Some(metaclass) = &inheritance_info.metaclass {
3141            // Find all classes affected by this metaclass
3142            let all_classes = server
3143                .graph_store()
3144                .get_nodes_by_kind(codeprism_core::NodeKind::Class);
3145            let mut affected_classes = Vec::new();
3146
3147            for class in all_classes {
3148                if let Ok(class_inheritance) = server.graph_query().get_inheritance_info(&class.id)
3149                {
3150                    if let Some(class_metaclass) = &class_inheritance.metaclass {
3151                        if class_metaclass.class_name == metaclass.class_name {
3152                            affected_classes.push(serde_json::json!({
3153                                "name": class.name,
3154                                "file": class.file.display().to_string(),
3155                                "dynamic_attributes": class_inheritance.dynamic_attributes
3156                            }));
3157                        }
3158                    }
3159                }
3160            }
3161
3162            Ok(serde_json::json!({
3163                "metaclass": {
3164                    "name": metaclass.class_name,
3165                    "file": metaclass.file.display().to_string()
3166                },
3167                "affected_classes_count": affected_classes.len(),
3168                "affected_classes": affected_classes,
3169                "creates_dynamic_attributes": !inheritance_info.dynamic_attributes.is_empty(),
3170                "dynamic_attributes": inheritance_info.dynamic_attributes,
3171                "behavior_modifications": [
3172                    "class_creation",
3173                    "attribute_access",
3174                    "method_registration"
3175                ]
3176            }))
3177        } else {
3178            Ok(serde_json::json!(null))
3179        }
3180    }
3181
3182    /// Analyze mixin relationships and their effects
3183    async fn analyze_mixin_relationships(
3184        &self,
3185        server: &CodePrismMcpServer,
3186        inheritance_info: &codeprism_core::InheritanceInfo,
3187    ) -> Result<serde_json::Value> {
3188        let mut mixin_analysis = Vec::new();
3189
3190        for mixin in &inheritance_info.mixins {
3191            // Find the mixin class and analyze its methods
3192            let mixin_classes = server
3193                .graph_store()
3194                .get_nodes_by_kind(codeprism_core::NodeKind::Class);
3195            if let Some(mixin_node) = mixin_classes
3196                .iter()
3197                .find(|node| node.name == mixin.class_name)
3198            {
3199                let mixin_methods = server
3200                    .graph_store()
3201                    .get_outgoing_edges(&mixin_node.id)
3202                    .iter()
3203                    .filter_map(|edge| server.graph_store().get_node(&edge.target))
3204                    .filter(|node| matches!(node.kind, codeprism_core::NodeKind::Method))
3205                    .map(|method| {
3206                        serde_json::json!({
3207                            "name": method.name,
3208                            "file": method.file.display().to_string()
3209                        })
3210                    })
3211                    .collect::<Vec<_>>();
3212
3213                mixin_analysis.push(serde_json::json!({
3214                    "name": mixin.class_name,
3215                    "file": mixin.file.display().to_string(),
3216                    "methods_provided": mixin_methods,
3217                    "method_count": mixin_methods.len(),
3218                    "mixin_type": if mixin.class_name.ends_with("Mixin") { "explicit" } else { "implicit" }
3219                }));
3220            }
3221        }
3222
3223        Ok(serde_json::json!({
3224            "mixins": mixin_analysis,
3225            "total_mixins": mixin_analysis.len(),
3226            "mixin_pattern_usage": "multiple_inheritance"
3227        }))
3228    }
3229
3230    /// Analyze Method Resolution Order in detail
3231    async fn analyze_method_resolution_order(
3232        &self,
3233        _server: &CodePrismMcpServer,
3234        inheritance_info: &codeprism_core::InheritanceInfo,
3235    ) -> Result<serde_json::Value> {
3236        let mro = &inheritance_info.method_resolution_order;
3237
3238        let mut mro_analysis = Vec::new();
3239        for (index, class_name) in mro.iter().enumerate() {
3240            mro_analysis.push(serde_json::json!({
3241                "order": index,
3242                "class_name": class_name,
3243                "is_root": class_name == "object",
3244                "is_base": index == mro.len() - 1 || class_name == "object",
3245                "is_target": index == 0
3246            }));
3247        }
3248
3249        Ok(serde_json::json!({
3250            "method_resolution_order": mro_analysis,
3251            "mro_length": mro.len(),
3252            "linearization": mro,
3253            "complexity": if mro.len() > 5 { "complex" } else if mro.len() > 3 { "moderate" } else { "simple" },
3254            "has_diamond_pattern": mro.len() > 4 && mro.iter().any(|name| name.contains("Mixin"))
3255        }))
3256    }
3257
3258    /// Analyze dynamic attributes created by metaclasses
3259    async fn analyze_dynamic_attributes(
3260        &self,
3261        _server: &CodePrismMcpServer,
3262        inheritance_info: &codeprism_core::InheritanceInfo,
3263    ) -> Result<serde_json::Value> {
3264        let dynamic_attrs = &inheritance_info.dynamic_attributes;
3265
3266        let mut attribute_analysis = Vec::new();
3267        let mut creation_sources = std::collections::HashMap::new();
3268
3269        for attr in dynamic_attrs {
3270            attribute_analysis.push(serde_json::json!({
3271                "name": attr.name,
3272                "created_by": attr.created_by,
3273                "type": attr.attribute_type,
3274                "creation_source": if attr.created_by.starts_with("metaclass:") { "metaclass" } else { "decorator" }
3275            }));
3276
3277            let source = if attr.created_by.starts_with("metaclass:") {
3278                "metaclass"
3279            } else {
3280                "decorator"
3281            };
3282            *creation_sources.entry(source).or_insert(0) += 1;
3283        }
3284
3285        Ok(serde_json::json!({
3286            "dynamic_attributes": attribute_analysis,
3287            "total_dynamic_attributes": dynamic_attrs.len(),
3288            "creation_sources": creation_sources,
3289            "attribute_types": dynamic_attrs.iter().map(|attr| &attr.attribute_type).collect::<std::collections::HashSet<_>>(),
3290            "patterns": {
3291                "registry_pattern": dynamic_attrs.iter().any(|attr| attr.name.contains("registry") || attr.name.contains("_processors")),
3292                "injection_pattern": dynamic_attrs.iter().any(|attr| attr.created_by.starts_with("metaclass:")),
3293                "decorator_pattern": dynamic_attrs.iter().any(|attr| attr.created_by.starts_with("decorator:"))
3294            }
3295        }))
3296    }
3297
3298    /// Detect diamond inheritance patterns
3299    async fn detect_diamond_inheritance(
3300        &self,
3301        server: &CodePrismMcpServer,
3302        class_id: &codeprism_core::NodeId,
3303    ) -> Result<serde_json::Value> {
3304        let inheritance_info = server.graph_query().get_inheritance_info(class_id)?;
3305
3306        // Diamond inheritance occurs when a class inherits from multiple classes
3307        // that share a common ancestor
3308        let mut diamond_patterns = Vec::new();
3309
3310        if inheritance_info.base_classes.len() > 1 {
3311            // Check if any base classes share common ancestors
3312            for i in 0..inheritance_info.base_classes.len() {
3313                for j in (i + 1)..inheritance_info.base_classes.len() {
3314                    let base1 = &inheritance_info.base_classes[i];
3315                    let base2 = &inheritance_info.base_classes[j];
3316
3317                    // Find the actual base class nodes
3318                    let all_classes = server
3319                        .graph_store()
3320                        .get_nodes_by_kind(codeprism_core::NodeKind::Class);
3321                    if let (Some(base1_node), Some(base2_node)) = (
3322                        all_classes
3323                            .iter()
3324                            .find(|node| node.name == base1.class_name),
3325                        all_classes
3326                            .iter()
3327                            .find(|node| node.name == base2.class_name),
3328                    ) {
3329                        if let (Ok(base1_info), Ok(base2_info)) = (
3330                            server.graph_query().get_inheritance_info(&base1_node.id),
3331                            server.graph_query().get_inheritance_info(&base2_node.id),
3332                        ) {
3333                            // Check for common ancestors
3334                            let common_ancestors: Vec<_> = base1_info
3335                                .inheritance_chain
3336                                .iter()
3337                                .filter(|ancestor| base2_info.inheritance_chain.contains(ancestor))
3338                                .cloned()
3339                                .collect();
3340
3341                            if !common_ancestors.is_empty() {
3342                                diamond_patterns.push(serde_json::json!({
3343                                    "base_classes": [base1.class_name.clone(), base2.class_name.clone()],
3344                                    "common_ancestors": common_ancestors,
3345                                    "diamond_type": if common_ancestors.len() > 1 { "complex" } else { "simple" }
3346                                }));
3347                            }
3348                        }
3349                    }
3350                }
3351            }
3352        }
3353
3354        Ok(serde_json::json!({
3355            "has_diamond_inheritance": !diamond_patterns.is_empty(),
3356            "diamond_patterns": diamond_patterns,
3357            "multiple_inheritance_count": inheritance_info.base_classes.len(),
3358            "potential_mro_conflicts": diamond_patterns.len() > 1
3359        }))
3360    }
3361
3362    /// Analyze decorators comprehensively
3363    async fn analyze_decorators(
3364        &self,
3365        server: &CodePrismMcpServer,
3366        arguments: Option<Value>,
3367    ) -> Result<CallToolResult> {
3368        let args = arguments.ok_or_else(|| anyhow::anyhow!("Missing arguments"))?;
3369
3370        // Get target decorators - either by pattern or ID
3371        let target_decorators = if let Some(decorator_pattern) =
3372            args.get("decorator_pattern").and_then(|v| v.as_str())
3373        {
3374            // Search for decorators by pattern
3375            let symbol_types = Some(vec![
3376                codeprism_core::NodeKind::Function,
3377                codeprism_core::NodeKind::Call,
3378            ]);
3379            let limit = args
3380                .get("max_results")
3381                .and_then(|v| v.as_u64())
3382                .map(|v| v as usize)
3383                .unwrap_or(100);
3384
3385            let search_results = server.graph_query().search_symbols(
3386                decorator_pattern,
3387                symbol_types,
3388                Some(limit),
3389            )?;
3390
3391            if search_results.is_empty() {
3392                return Ok(CallToolResult {
3393                    content: vec![ToolContent::Text {
3394                        text: format!(
3395                            "No decorators found matching pattern: {}",
3396                            decorator_pattern
3397                        ),
3398                    }],
3399                    is_error: Some(true),
3400                });
3401            }
3402
3403            // Filter for decorator-like symbols
3404            search_results
3405                .into_iter()
3406                .filter_map(|symbol| server.graph_store().get_node(&symbol.node.id))
3407                .filter(|node| self.is_decorator_node(node))
3408                .collect::<Vec<_>>()
3409        } else if let Some(decorator_id_str) = args.get("decorator_id").and_then(|v| v.as_str()) {
3410            // Use specific decorator ID
3411            let decorator_id = self.parse_node_id(decorator_id_str)?;
3412            if let Some(node) = server.graph_store().get_node(&decorator_id) {
3413                if self.is_decorator_node(&node) {
3414                    vec![node]
3415                } else {
3416                    return Ok(CallToolResult {
3417                        content: vec![ToolContent::Text {
3418                            text: format!("Node {} is not a decorator", decorator_id_str),
3419                        }],
3420                        is_error: Some(true),
3421                    });
3422                }
3423            } else {
3424                return Ok(CallToolResult {
3425                    content: vec![ToolContent::Text {
3426                        text: format!("Decorator not found: {}", decorator_id_str),
3427                    }],
3428                    is_error: Some(true),
3429                });
3430            }
3431        } else {
3432            return Ok(CallToolResult {
3433                content: vec![ToolContent::Text {
3434                    text: "Either decorator_pattern or decorator_id parameter is required"
3435                        .to_string(),
3436                }],
3437                is_error: Some(true),
3438            });
3439        };
3440
3441        // Parse options
3442        let scope = args
3443            .get("scope")
3444            .and_then(|v| v.as_str())
3445            .unwrap_or("repository");
3446
3447        let include_factories = args
3448            .get("include_factories")
3449            .and_then(|v| v.as_bool())
3450            .unwrap_or(true);
3451
3452        let analyze_effects = args
3453            .get("analyze_effects")
3454            .and_then(|v| v.as_bool())
3455            .unwrap_or(true);
3456
3457        let include_chains = args
3458            .get("include_chains")
3459            .and_then(|v| v.as_bool())
3460            .unwrap_or(true);
3461
3462        let detect_patterns = args
3463            .get("detect_patterns")
3464            .and_then(|v| v.as_bool())
3465            .unwrap_or(true);
3466
3467        let include_framework_analysis = args
3468            .get("include_framework_analysis")
3469            .and_then(|v| v.as_bool())
3470            .unwrap_or(true);
3471
3472        let include_source_context = args
3473            .get("include_source_context")
3474            .and_then(|v| v.as_bool())
3475            .unwrap_or(false);
3476
3477        let confidence_threshold = args
3478            .get("confidence_threshold")
3479            .and_then(|v| v.as_f64())
3480            .unwrap_or(0.8);
3481
3482        // Analyze each target decorator
3483        let mut analysis_results = Vec::new();
3484
3485        for target_decorator in &target_decorators {
3486            // Basic decorator analysis
3487            let decorator_usage = self
3488                .analyze_decorator_usage(server, &target_decorator.id, scope)
3489                .await?;
3490
3491            // Decorator effects analysis
3492            let effects_analysis = if analyze_effects {
3493                Some(
3494                    self.analyze_decorator_effects(server, &target_decorator.id)
3495                        .await?,
3496                )
3497            } else {
3498                None
3499            };
3500
3501            // Decorator factory analysis
3502            let factory_analysis = if include_factories {
3503                Some(
3504                    self.analyze_decorator_factory(server, &target_decorator.id)
3505                        .await?,
3506                )
3507            } else {
3508                None
3509            };
3510
3511            // Decorator chain analysis
3512            let chain_analysis = if include_chains {
3513                Some(
3514                    self.analyze_decorator_chains(server, &target_decorator.id)
3515                        .await?,
3516                )
3517            } else {
3518                None
3519            };
3520
3521            // Framework-specific analysis
3522            let framework_analysis = if include_framework_analysis {
3523                Some(
3524                    self.analyze_framework_decorators(server, &target_decorator.id)
3525                        .await?,
3526                )
3527            } else {
3528                None
3529            };
3530
3531            // Pattern detection
3532            let pattern_analysis = if detect_patterns {
3533                Some(
3534                    self.detect_decorator_patterns(
3535                        server,
3536                        &target_decorator.id,
3537                        confidence_threshold,
3538                    )
3539                    .await?,
3540                )
3541            } else {
3542                None
3543            };
3544
3545            let mut analysis = serde_json::json!({
3546                "target_decorator": {
3547                    "id": target_decorator.id.to_hex(),
3548                    "name": target_decorator.name,
3549                    "file": target_decorator.file.display().to_string(),
3550                    "span": {
3551                        "start_line": target_decorator.span.start_line,
3552                        "end_line": target_decorator.span.end_line,
3553                        "start_column": target_decorator.span.start_column,
3554                        "end_column": target_decorator.span.end_column
3555                    }
3556                },
3557                "usage_analysis": decorator_usage
3558            });
3559
3560            // Add source context if requested
3561            if include_source_context {
3562                if let Some(context) = self.extract_source_context(
3563                    &target_decorator.file,
3564                    target_decorator.span.start_line,
3565                    3,
3566                ) {
3567                    analysis["source_context"] = context;
3568                }
3569            }
3570
3571            // Add optional analyses
3572            if let Some(effects) = effects_analysis {
3573                analysis["effects_analysis"] = effects;
3574            }
3575
3576            if let Some(factory) = factory_analysis {
3577                analysis["factory_analysis"] = factory;
3578            }
3579
3580            if let Some(chains) = chain_analysis {
3581                analysis["chain_analysis"] = chains;
3582            }
3583
3584            if let Some(framework) = framework_analysis {
3585                analysis["framework_analysis"] = framework;
3586            }
3587
3588            if let Some(patterns) = pattern_analysis {
3589                analysis["pattern_analysis"] = patterns;
3590            }
3591
3592            analysis_results.push(analysis);
3593        }
3594
3595        let result = serde_json::json!({
3596            "analysis_results": analysis_results,
3597            "summary": {
3598                "decorators_analyzed": target_decorators.len(),
3599                "scope": scope,
3600                "options": {
3601                    "include_factories": include_factories,
3602                    "analyze_effects": analyze_effects,
3603                    "include_chains": include_chains,
3604                    "detect_patterns": detect_patterns,
3605                    "include_framework_analysis": include_framework_analysis,
3606                    "include_source_context": include_source_context,
3607                    "confidence_threshold": confidence_threshold
3608                }
3609            }
3610        });
3611
3612        Ok(CallToolResult {
3613            content: vec![ToolContent::Text {
3614                text: serde_json::to_string_pretty(&result)?,
3615            }],
3616            is_error: Some(false),
3617        })
3618    }
3619
3620    /// Check if a node represents a decorator
3621    fn is_decorator_node(&self, node: &codeprism_core::Node) -> bool {
3622        // Check if it's a function that could be a decorator
3623        if matches!(node.kind, codeprism_core::NodeKind::Function) {
3624            // Common decorator naming patterns
3625            if node.name.starts_with("_") && node.name.len() > 1 {
3626                return false; // Likely private function
3627            }
3628
3629            // Check for common decorator patterns
3630            let decorator_indicators = [
3631                "decorator",
3632                "wrap",
3633                "cache",
3634                "validate",
3635                "auth",
3636                "property",
3637                "classmethod",
3638                "staticmethod",
3639                "lru_cache",
3640                "route",
3641                "app",
3642                "requires",
3643                "check",
3644                "log",
3645                "retry",
3646                "timeout",
3647                "rate_limit",
3648            ];
3649
3650            return decorator_indicators
3651                .iter()
3652                .any(|&indicator| node.name.to_lowercase().contains(indicator));
3653        }
3654
3655        // Check if it's a call that could be a decorator usage
3656        if matches!(node.kind, codeprism_core::NodeKind::Call) {
3657            // Look for @decorator syntax patterns
3658            return node.name.starts_with("@")
3659                || node.name.contains("decorator")
3660                || node.name.contains("property")
3661                || node.name.contains("classmethod")
3662                || node.name.contains("staticmethod");
3663        }
3664
3665        false
3666    }
3667
3668    /// Analyze decorator usage patterns
3669    async fn analyze_decorator_usage(
3670        &self,
3671        server: &CodePrismMcpServer,
3672        decorator_id: &codeprism_core::NodeId,
3673        scope: &str,
3674    ) -> Result<serde_json::Value> {
3675        // Find all references to this decorator
3676        let references = server.graph_query().find_references(decorator_id)?;
3677
3678        let mut usage_locations = Vec::new();
3679        let mut decorated_functions = Vec::new();
3680        let mut decorated_classes = Vec::new();
3681        let mut usage_files = std::collections::HashSet::new();
3682
3683        for reference in &references {
3684            usage_files.insert(reference.location.file.clone());
3685
3686            usage_locations.push(serde_json::json!({
3687                "file": reference.location.file.display().to_string(),
3688                "line": reference.location.span.start_line,
3689                "target_name": reference.source_node.name,
3690                "target_type": format!("{:?}", reference.source_node.kind)
3691            }));
3692
3693            // Categorize what's being decorated
3694            match reference.source_node.kind {
3695                codeprism_core::NodeKind::Function | codeprism_core::NodeKind::Method => {
3696                    decorated_functions.push(serde_json::json!({
3697                        "name": reference.source_node.name,
3698                        "file": reference.source_node.file.display().to_string(),
3699                        "type": format!("{:?}", reference.source_node.kind)
3700                    }));
3701                }
3702                codeprism_core::NodeKind::Class => {
3703                    decorated_classes.push(serde_json::json!({
3704                        "name": reference.source_node.name,
3705                        "file": reference.source_node.file.display().to_string()
3706                    }));
3707                }
3708                _ => {}
3709            }
3710        }
3711
3712        Ok(serde_json::json!({
3713            "usage_count": references.len(),
3714            "files_count": usage_files.len(),
3715            "decorated_functions": decorated_functions,
3716            "decorated_classes": decorated_classes,
3717            "usage_locations": usage_locations,
3718            "scope_coverage": match scope {
3719                "repository" => "full_repository",
3720                "module" => "single_module",
3721                "function" => "function_level",
3722                "class" => "class_level",
3723                _ => "unknown"
3724            }
3725        }))
3726    }
3727
3728    /// Analyze decorator effects on targets
3729    async fn analyze_decorator_effects(
3730        &self,
3731        server: &CodePrismMcpServer,
3732        decorator_id: &codeprism_core::NodeId,
3733    ) -> Result<serde_json::Value> {
3734        let decorator_node = server
3735            .graph_store()
3736            .get_node(decorator_id)
3737            .ok_or_else(|| anyhow::anyhow!("Decorator node not found"))?;
3738
3739        // Analyze what the decorator function does
3740        let mut effects = Vec::new();
3741        let mut modifies_signature = false;
3742        let adds_metadata = false;
3743        let mut creates_wrapper = false;
3744        let mut registers_function = false;
3745
3746        // Look for common decorator patterns in the function body
3747        // This is a simplified analysis - in a real implementation, you'd parse the AST
3748        let decorator_name = &decorator_node.name.to_lowercase();
3749
3750        if decorator_name.contains("wrapper") || decorator_name.contains("wrap") {
3751            creates_wrapper = true;
3752            effects.push("Creates wrapper function");
3753        }
3754
3755        if decorator_name.contains("property") {
3756            modifies_signature = true;
3757            effects.push("Converts method to property");
3758        }
3759
3760        if decorator_name.contains("cache") || decorator_name.contains("lru") {
3761            effects.push("Adds caching behavior");
3762        }
3763
3764        if decorator_name.contains("validate") {
3765            effects.push("Adds input validation");
3766        }
3767
3768        if decorator_name.contains("auth") || decorator_name.contains("require") {
3769            effects.push("Adds authorization checks");
3770        }
3771
3772        if decorator_name.contains("route") || decorator_name.contains("endpoint") {
3773            registers_function = true;
3774            effects.push("Registers as web endpoint");
3775        }
3776
3777        if decorator_name.contains("log") {
3778            effects.push("Adds logging functionality");
3779        }
3780
3781        if decorator_name.contains("retry") {
3782            effects.push("Adds retry mechanism");
3783        }
3784
3785        if decorator_name.contains("timeout") {
3786            effects.push("Adds timeout handling");
3787        }
3788
3789        if decorator_name.contains("classmethod") || decorator_name.contains("staticmethod") {
3790            modifies_signature = true;
3791            effects.push("Changes method binding");
3792        }
3793
3794        Ok(serde_json::json!({
3795            "effects": effects,
3796            "modifies_signature": modifies_signature,
3797            "adds_metadata": adds_metadata,
3798            "creates_wrapper": creates_wrapper,
3799            "registers_function": registers_function,
3800            "effect_categories": {
3801                "behavioral": effects.iter().any(|e| e.contains("behavior") || e.contains("mechanism")),
3802                "structural": modifies_signature || creates_wrapper,
3803                "registration": registers_function,
3804                "validation": effects.iter().any(|e| e.contains("validation") || e.contains("auth")),
3805                "performance": effects.iter().any(|e| e.contains("cache") || e.contains("timeout"))
3806            }
3807        }))
3808    }
3809
3810    /// Analyze if decorator is a factory pattern
3811    async fn analyze_decorator_factory(
3812        &self,
3813        server: &CodePrismMcpServer,
3814        decorator_id: &codeprism_core::NodeId,
3815    ) -> Result<serde_json::Value> {
3816        let decorator_node = server
3817            .graph_store()
3818            .get_node(decorator_id)
3819            .ok_or_else(|| anyhow::anyhow!("Decorator node not found"))?;
3820
3821        // Check if this function returns another function (decorator factory pattern)
3822        let outgoing_edges = server.graph_store().get_outgoing_edges(decorator_id);
3823        let has_inner_function = outgoing_edges.iter().any(|edge| {
3824            if let Some(target_node) = server.graph_store().get_node(&edge.target) {
3825                matches!(target_node.kind, codeprism_core::NodeKind::Function)
3826            } else {
3827                false
3828            }
3829        });
3830
3831        let is_factory = has_inner_function
3832            || decorator_node.name.to_lowercase().contains("factory")
3833            || decorator_node.name.ends_with("_decorator")
3834            || decorator_node.name.starts_with("make_");
3835
3836        let mut factory_parameters = Vec::new();
3837        if is_factory {
3838            // In a real implementation, you'd parse the function signature
3839            // For now, we'll use naming heuristics
3840            if decorator_node.name.to_lowercase().contains("cache") {
3841                factory_parameters.push("maxsize");
3842            }
3843            if decorator_node.name.to_lowercase().contains("retry") {
3844                factory_parameters.push("attempts");
3845                factory_parameters.push("delay");
3846            }
3847            if decorator_node.name.to_lowercase().contains("timeout") {
3848                factory_parameters.push("seconds");
3849            }
3850        }
3851
3852        Ok(serde_json::json!({
3853            "is_factory": is_factory,
3854            "has_inner_function": has_inner_function,
3855            "factory_parameters": factory_parameters,
3856            "factory_type": if is_factory {
3857                if decorator_node.name.to_lowercase().contains("param") { "parameterized" }
3858                else if has_inner_function { "closure_based" }
3859                else { "configuration_based" }
3860            } else { "simple_decorator" }
3861        }))
3862    }
3863
3864    /// Analyze decorator chains
3865    async fn analyze_decorator_chains(
3866        &self,
3867        server: &CodePrismMcpServer,
3868        decorator_id: &codeprism_core::NodeId,
3869    ) -> Result<serde_json::Value> {
3870        // Find functions/classes that use this decorator and see if they have other decorators
3871        let references = server.graph_query().find_references(decorator_id)?;
3872        let mut chain_analysis = Vec::new();
3873
3874        for reference in &references {
3875            // Look for other decorators on the same target
3876            let target_dependencies = server.graph_query().find_dependencies(
3877                &reference.source_node.id,
3878                codeprism_core::graph::DependencyType::Direct,
3879            )?;
3880
3881            let other_decorators: Vec<_> = target_dependencies
3882                .iter()
3883                .filter(|dep| self.is_decorator_node(&dep.target_node))
3884                .filter(|dep| dep.target_node.id != *decorator_id)
3885                .map(|dep| {
3886                    serde_json::json!({
3887                        "name": dep.target_node.name,
3888                        "id": dep.target_node.id.to_hex(),
3889                        "file": dep.target_node.file.display().to_string()
3890                    })
3891                })
3892                .collect();
3893
3894            if !other_decorators.is_empty() {
3895                chain_analysis.push(serde_json::json!({
3896                    "target": {
3897                        "name": reference.source_node.name,
3898                        "type": format!("{:?}", reference.source_node.kind),
3899                        "file": reference.source_node.file.display().to_string()
3900                    },
3901                    "decorators_in_chain": other_decorators,
3902                    "chain_length": other_decorators.len() + 1
3903                }));
3904            }
3905        }
3906
3907        Ok(serde_json::json!({
3908            "chains_found": chain_analysis.len(),
3909            "decorator_chains": chain_analysis,
3910            "has_complex_chains": chain_analysis.iter().any(|chain|
3911                chain["chain_length"].as_u64().unwrap_or(0) > 2
3912            )
3913        }))
3914    }
3915
3916    /// Analyze framework-specific decorator patterns
3917    async fn analyze_framework_decorators(
3918        &self,
3919        _server: &CodePrismMcpServer,
3920        decorator_id: &codeprism_core::NodeId,
3921    ) -> Result<serde_json::Value> {
3922        let decorator_node = _server
3923            .graph_store()
3924            .get_node(decorator_id)
3925            .ok_or_else(|| anyhow::anyhow!("Decorator node not found"))?;
3926
3927        let decorator_name = &decorator_node.name.to_lowercase();
3928        let mut framework_info = serde_json::Map::new();
3929
3930        // Flask framework patterns
3931        if decorator_name.contains("route") || decorator_name.contains("app.") {
3932            framework_info.insert(
3933                "framework".to_string(),
3934                serde_json::Value::String("Flask".to_string()),
3935            );
3936            framework_info.insert(
3937                "pattern_type".to_string(),
3938                serde_json::Value::String("routing".to_string()),
3939            );
3940            framework_info.insert(
3941                "creates_endpoint".to_string(),
3942                serde_json::Value::Bool(true),
3943            );
3944        }
3945        // Django framework patterns
3946        else if decorator_name.contains("csrf")
3947            || decorator_name.contains("login_required")
3948            || decorator_name.contains("permission_required")
3949        {
3950            framework_info.insert(
3951                "framework".to_string(),
3952                serde_json::Value::String("Django".to_string()),
3953            );
3954            framework_info.insert(
3955                "pattern_type".to_string(),
3956                serde_json::Value::String("security".to_string()),
3957            );
3958        }
3959        // FastAPI framework patterns
3960        else if decorator_name.contains("depends") || decorator_name.contains("security") {
3961            framework_info.insert(
3962                "framework".to_string(),
3963                serde_json::Value::String("FastAPI".to_string()),
3964            );
3965            framework_info.insert(
3966                "pattern_type".to_string(),
3967                serde_json::Value::String("dependency_injection".to_string()),
3968            );
3969        }
3970        // Pytest framework patterns
3971        else if decorator_name.contains("fixture")
3972            || decorator_name.contains("mark")
3973            || decorator_name.contains("parametrize")
3974        {
3975            framework_info.insert(
3976                "framework".to_string(),
3977                serde_json::Value::String("pytest".to_string()),
3978            );
3979            framework_info.insert(
3980                "pattern_type".to_string(),
3981                serde_json::Value::String("testing".to_string()),
3982            );
3983        }
3984        // SQLAlchemy ORM patterns
3985        else if decorator_name.contains("hybrid") || decorator_name.contains("validates") {
3986            framework_info.insert(
3987                "framework".to_string(),
3988                serde_json::Value::String("SQLAlchemy".to_string()),
3989            );
3990            framework_info.insert(
3991                "pattern_type".to_string(),
3992                serde_json::Value::String("orm".to_string()),
3993            );
3994        }
3995        // Celery task patterns
3996        else if decorator_name.contains("task") || decorator_name.contains("periodic") {
3997            framework_info.insert(
3998                "framework".to_string(),
3999                serde_json::Value::String("Celery".to_string()),
4000            );
4001            framework_info.insert(
4002                "pattern_type".to_string(),
4003                serde_json::Value::String("task_queue".to_string()),
4004            );
4005        }
4006        // Generic patterns
4007        else {
4008            framework_info.insert(
4009                "framework".to_string(),
4010                serde_json::Value::String("unknown".to_string()),
4011            );
4012            framework_info.insert(
4013                "pattern_type".to_string(),
4014                serde_json::Value::String("custom".to_string()),
4015            );
4016        }
4017
4018        Ok(serde_json::Value::Object(framework_info))
4019    }
4020
4021    /// Detect common decorator patterns
4022    async fn detect_decorator_patterns(
4023        &self,
4024        server: &CodePrismMcpServer,
4025        decorator_id: &codeprism_core::NodeId,
4026        confidence_threshold: f64,
4027    ) -> Result<serde_json::Value> {
4028        let decorator_node = server
4029            .graph_store()
4030            .get_node(decorator_id)
4031            .ok_or_else(|| anyhow::anyhow!("Decorator node not found"))?;
4032
4033        let decorator_name = &decorator_node.name.to_lowercase();
4034        let mut detected_patterns = Vec::new();
4035
4036        // Registry pattern
4037        if decorator_name.contains("register") || decorator_name.contains("route") {
4038            detected_patterns.push(serde_json::json!({
4039                "pattern": "Registry Pattern",
4040                "confidence": 0.9,
4041                "description": "Decorator registers functions in a central registry",
4042                "indicators": ["register", "route", "endpoint"],
4043                "benefits": ["centralized_management", "automatic_discovery", "loose_coupling"]
4044            }));
4045        }
4046
4047        // Caching pattern
4048        if decorator_name.contains("cache")
4049            || decorator_name.contains("memoize")
4050            || decorator_name.contains("lru")
4051        {
4052            detected_patterns.push(serde_json::json!({
4053                "pattern": "Caching Pattern",
4054                "confidence": 0.95,
4055                "description": "Decorator adds caching to function results",
4056                "indicators": ["cache", "memoize", "lru"],
4057                "benefits": ["performance_improvement", "reduced_computation", "memory_optimization"]
4058            }));
4059        }
4060
4061        // Validation pattern
4062        if decorator_name.contains("validate")
4063            || decorator_name.contains("check")
4064            || decorator_name.contains("verify")
4065        {
4066            detected_patterns.push(serde_json::json!({
4067                "pattern": "Validation Pattern",
4068                "confidence": 0.85,
4069                "description": "Decorator adds input/output validation",
4070                "indicators": ["validate", "check", "verify"],
4071                "benefits": ["data_integrity", "error_prevention", "security"]
4072            }));
4073        }
4074
4075        // Authorization pattern
4076        if decorator_name.contains("auth")
4077            || decorator_name.contains("require")
4078            || decorator_name.contains("permission")
4079        {
4080            detected_patterns.push(serde_json::json!({
4081                "pattern": "Authorization Pattern",
4082                "confidence": 0.9,
4083                "description": "Decorator adds access control",
4084                "indicators": ["auth", "require", "permission", "login"],
4085                "benefits": ["security", "access_control", "separation_of_concerns"]
4086            }));
4087        }
4088
4089        // Retry pattern
4090        if decorator_name.contains("retry") || decorator_name.contains("attempt") {
4091            detected_patterns.push(serde_json::json!({
4092                "pattern": "Retry Pattern",
4093                "confidence": 0.8,
4094                "description": "Decorator adds retry logic for failed operations",
4095                "indicators": ["retry", "attempt", "resilience"],
4096                "benefits": ["fault_tolerance", "reliability", "error_recovery"]
4097            }));
4098        }
4099
4100        // Logging pattern
4101        if decorator_name.contains("log")
4102            || decorator_name.contains("trace")
4103            || decorator_name.contains("audit")
4104        {
4105            detected_patterns.push(serde_json::json!({
4106                "pattern": "Logging Pattern",
4107                "confidence": 0.8,
4108                "description": "Decorator adds logging/auditing functionality",
4109                "indicators": ["log", "trace", "audit"],
4110                "benefits": ["observability", "debugging", "compliance"]
4111            }));
4112        }
4113
4114        // Timing/Performance pattern
4115        if decorator_name.contains("time")
4116            || decorator_name.contains("measure")
4117            || decorator_name.contains("profile")
4118        {
4119            detected_patterns.push(serde_json::json!({
4120                "pattern": "Performance Monitoring Pattern",
4121                "confidence": 0.85,
4122                "description": "Decorator measures execution time and performance",
4123                "indicators": ["time", "measure", "profile"],
4124                "benefits": ["performance_monitoring", "optimization", "benchmarking"]
4125            }));
4126        }
4127
4128        // Filter by confidence threshold
4129        let filtered_patterns: Vec<_> = detected_patterns
4130            .into_iter()
4131            .filter(|pattern| pattern["confidence"].as_f64().unwrap_or(0.0) >= confidence_threshold)
4132            .collect();
4133
4134        Ok(serde_json::json!({
4135            "detected_patterns": filtered_patterns,
4136            "pattern_count": filtered_patterns.len(),
4137            "confidence_threshold": confidence_threshold,
4138            "recommendations": self.get_decorator_recommendations(&filtered_patterns)
4139        }))
4140    }
4141
4142    /// Get recommendations for decorator usage
4143    fn get_decorator_recommendations(&self, patterns: &[serde_json::Value]) -> Vec<String> {
4144        let mut recommendations = Vec::new();
4145
4146        if patterns.is_empty() {
4147            recommendations.push(
4148                "Consider adding more descriptive names to better identify decorator patterns"
4149                    .to_string(),
4150            );
4151            recommendations.push("Document the decorator's purpose and effects".to_string());
4152        } else {
4153            recommendations.push("Well-identified decorator patterns found".to_string());
4154
4155            if patterns
4156                .iter()
4157                .any(|p| p["pattern"].as_str().unwrap_or("").contains("Caching"))
4158            {
4159                recommendations.push(
4160                    "Consider cache invalidation strategy for caching decorators".to_string(),
4161                );
4162            }
4163
4164            if patterns.iter().any(|p| {
4165                p["pattern"]
4166                    .as_str()
4167                    .unwrap_or("")
4168                    .contains("Authorization")
4169            }) {
4170                recommendations.push("Ensure authorization decorators are applied consistently across similar endpoints".to_string());
4171            }
4172
4173            if patterns
4174                .iter()
4175                .any(|p| p["pattern"].as_str().unwrap_or("").contains("Validation"))
4176            {
4177                recommendations
4178                    .push("Consider combining validation patterns with error handling".to_string());
4179            }
4180
4181            if patterns.len() > 3 {
4182                recommendations.push("Consider creating a decorator composition utility for complex decorator chains".to_string());
4183            }
4184        }
4185
4186        recommendations
4187    }
4188
4189    /// Find duplicate code patterns
4190    async fn find_duplicates(
4191        &self,
4192        _server: &CodePrismMcpServer,
4193        arguments: Option<Value>,
4194    ) -> Result<CallToolResult> {
4195        let args = arguments.unwrap_or_default();
4196
4197        let similarity_threshold = args
4198            .get("similarity_threshold")
4199            .and_then(|v| v.as_f64())
4200            .unwrap_or(0.8);
4201
4202        let min_lines = args
4203            .get("min_lines")
4204            .and_then(|v| v.as_u64())
4205            .map(|v| v as usize)
4206            .unwrap_or(3);
4207
4208        let scope = args
4209            .get("scope")
4210            .and_then(|v| v.as_str())
4211            .unwrap_or("repository");
4212
4213        // Placeholder implementation - call to analysis crate
4214        let result = serde_json::json!({
4215            "scope": scope,
4216            "parameters": {
4217                "similarity_threshold": similarity_threshold,
4218                "min_lines": min_lines
4219            },
4220            "duplicates": [],
4221            "summary": {
4222                "total_duplicates": 0,
4223                "files_analyzed": 0,
4224                "lines_duplicated": 0
4225            },
4226            "analysis_successful": true
4227        });
4228
4229        Ok(CallToolResult {
4230            content: vec![ToolContent::Text {
4231                text: serde_json::to_string_pretty(&result)?,
4232            }],
4233            is_error: Some(false),
4234        })
4235    }
4236
4237    /// Find unused code
4238    async fn find_unused_code(
4239        &self,
4240        server: &CodePrismMcpServer,
4241        arguments: Option<Value>,
4242    ) -> Result<CallToolResult> {
4243        let args = arguments.unwrap_or_default();
4244
4245        let scope = args
4246            .get("scope")
4247            .and_then(|v| v.as_str())
4248            .unwrap_or("repository");
4249
4250        let analyze_types = args
4251            .get("analyze_types")
4252            .and_then(|v| v.as_array())
4253            .map(|arr| {
4254                arr.iter()
4255                    .filter_map(|v| v.as_str().map(|s| s.to_string()))
4256                    .collect::<Vec<_>>()
4257            })
4258            .unwrap_or_else(|| {
4259                vec![
4260                    "functions".to_string(),
4261                    "classes".to_string(),
4262                    "variables".to_string(),
4263                    "imports".to_string(),
4264                ]
4265            });
4266
4267        let confidence_threshold = args
4268            .get("confidence_threshold")
4269            .and_then(|v| v.as_f64())
4270            .unwrap_or(0.7);
4271
4272        let consider_external_apis = args
4273            .get("consider_external_apis")
4274            .and_then(|v| v.as_bool())
4275            .unwrap_or(true);
4276
4277        let include_dead_code = args
4278            .get("include_dead_code")
4279            .and_then(|v| v.as_bool())
4280            .unwrap_or(true);
4281
4282        let exclude_patterns = args
4283            .get("exclude_patterns")
4284            .and_then(|v| v.as_array())
4285            .map(|arr| {
4286                arr.iter()
4287                    .filter_map(|v| v.as_str().map(|s| s.to_string()))
4288                    .collect::<Vec<_>>()
4289            })
4290            .unwrap_or_default();
4291
4292        let analysis_result = self
4293            .perform_unused_code_analysis(
4294                server,
4295                scope,
4296                include_dead_code,
4297                consider_external_apis,
4298                confidence_threshold,
4299                &analyze_types,
4300                &exclude_patterns,
4301            )
4302            .await?;
4303
4304        Ok(CallToolResult {
4305            content: vec![ToolContent::Text {
4306                text: serde_json::to_string_pretty(&analysis_result)?,
4307            }],
4308            is_error: Some(false),
4309        })
4310    }
4311
4312    /// Analyze security vulnerabilities
4313    async fn analyze_security(
4314        &self,
4315        server: &CodePrismMcpServer,
4316        arguments: Option<Value>,
4317    ) -> Result<CallToolResult> {
4318        let args = arguments.unwrap_or_default();
4319
4320        let scope = args
4321            .get("scope")
4322            .and_then(|v| v.as_str())
4323            .unwrap_or("repository");
4324
4325        let vulnerability_types = args
4326            .get("vulnerability_types")
4327            .and_then(|v| v.as_array())
4328            .map(|arr| {
4329                arr.iter()
4330                    .filter_map(|v| v.as_str().map(|s| s.to_string()))
4331                    .collect::<Vec<_>>()
4332            })
4333            .unwrap_or_else(|| {
4334                vec![
4335                    "injection".to_string(),
4336                    "authentication".to_string(),
4337                    "authorization".to_string(),
4338                ]
4339            });
4340
4341        let severity_threshold = args
4342            .get("severity_threshold")
4343            .and_then(|v| v.as_str())
4344            .unwrap_or("medium");
4345
4346        let include_data_flow_analysis = args
4347            .get("include_data_flow_analysis")
4348            .and_then(|v| v.as_bool())
4349            .unwrap_or(false);
4350
4351        let check_external_dependencies = args
4352            .get("check_external_dependencies")
4353            .and_then(|v| v.as_bool())
4354            .unwrap_or(true);
4355
4356        let exclude_patterns = args
4357            .get("exclude_patterns")
4358            .and_then(|v| v.as_array())
4359            .map(|arr| {
4360                arr.iter()
4361                    .filter_map(|v| v.as_str().map(|s| s.to_string()))
4362                    .collect::<Vec<_>>()
4363            })
4364            .unwrap_or_default();
4365
4366        let analysis_result = self
4367            .perform_security_analysis(
4368                server,
4369                scope,
4370                &vulnerability_types,
4371                severity_threshold,
4372                include_data_flow_analysis,
4373                check_external_dependencies,
4374                &exclude_patterns,
4375            )
4376            .await?;
4377
4378        Ok(CallToolResult {
4379            content: vec![ToolContent::Text {
4380                text: serde_json::to_string_pretty(&analysis_result)?,
4381            }],
4382            is_error: Some(false),
4383        })
4384    }
4385
4386    /// Analyze performance issues
4387    async fn analyze_performance(
4388        &self,
4389        server: &CodePrismMcpServer,
4390        arguments: Option<Value>,
4391    ) -> Result<CallToolResult> {
4392        let args = arguments.unwrap_or_default();
4393
4394        let scope = args
4395            .get("scope")
4396            .and_then(|v| v.as_str())
4397            .unwrap_or("repository");
4398
4399        let analysis_types = args
4400            .get("analysis_types")
4401            .and_then(|v| v.as_array())
4402            .map(|arr| {
4403                arr.iter()
4404                    .filter_map(|v| v.as_str().map(|s| s.to_string()))
4405                    .collect::<Vec<_>>()
4406            })
4407            .unwrap_or_else(|| {
4408                vec![
4409                    "time_complexity".to_string(),
4410                    "memory_usage".to_string(),
4411                    "hot_spots".to_string(),
4412                ]
4413            });
4414
4415        let complexity_threshold = args
4416            .get("complexity_threshold")
4417            .and_then(|v| v.as_str())
4418            .unwrap_or("medium");
4419
4420        let include_algorithmic_analysis = args
4421            .get("include_algorithmic_analysis")
4422            .and_then(|v| v.as_bool())
4423            .unwrap_or(true);
4424
4425        let detect_bottlenecks = args
4426            .get("detect_bottlenecks")
4427            .and_then(|v| v.as_bool())
4428            .unwrap_or(true);
4429
4430        let exclude_patterns = args
4431            .get("exclude_patterns")
4432            .and_then(|v| v.as_array())
4433            .map(|arr| {
4434                arr.iter()
4435                    .filter_map(|v| v.as_str().map(|s| s.to_string()))
4436                    .collect::<Vec<_>>()
4437            })
4438            .unwrap_or_default();
4439
4440        let analysis_result = self
4441            .perform_performance_analysis(
4442                server,
4443                scope,
4444                &analysis_types,
4445                complexity_threshold,
4446                include_algorithmic_analysis,
4447                detect_bottlenecks,
4448                &exclude_patterns,
4449            )
4450            .await?;
4451
4452        Ok(CallToolResult {
4453            content: vec![ToolContent::Text {
4454                text: serde_json::to_string_pretty(&analysis_result)?,
4455            }],
4456            is_error: Some(false),
4457        })
4458    }
4459
4460    /// Analyze API surface
4461    async fn analyze_api_surface(
4462        &self,
4463        server: &CodePrismMcpServer,
4464        arguments: Option<Value>,
4465    ) -> Result<CallToolResult> {
4466        let args = arguments.unwrap_or_default();
4467
4468        let scope = args
4469            .get("scope")
4470            .and_then(|v| v.as_str())
4471            .unwrap_or("repository");
4472
4473        let analysis_types = args
4474            .get("analysis_types")
4475            .and_then(|v| v.as_array())
4476            .map(|arr| {
4477                arr.iter()
4478                    .filter_map(|v| v.as_str().map(|s| s.to_string()))
4479                    .collect::<Vec<_>>()
4480            })
4481            .unwrap_or_else(|| {
4482                vec![
4483                    "public_api".to_string(),
4484                    "versioning".to_string(),
4485                    "breaking_changes".to_string(),
4486                ]
4487            });
4488
4489        let api_version = args.get("api_version").and_then(|v| v.as_str());
4490
4491        let include_private_apis = args
4492            .get("include_private_apis")
4493            .and_then(|v| v.as_bool())
4494            .unwrap_or(false);
4495
4496        let check_documentation_coverage = args
4497            .get("check_documentation_coverage")
4498            .and_then(|v| v.as_bool())
4499            .unwrap_or(true);
4500
4501        let detect_breaking_changes = args
4502            .get("detect_breaking_changes")
4503            .and_then(|v| v.as_bool())
4504            .unwrap_or(true);
4505
4506        let exclude_patterns = args
4507            .get("exclude_patterns")
4508            .and_then(|v| v.as_array())
4509            .map(|arr| {
4510                arr.iter()
4511                    .filter_map(|v| v.as_str().map(|s| s.to_string()))
4512                    .collect::<Vec<_>>()
4513            })
4514            .unwrap_or_default();
4515
4516        let analysis_result = self
4517            .perform_api_surface_analysis(
4518                server,
4519                scope,
4520                &analysis_types,
4521                api_version,
4522                include_private_apis,
4523                check_documentation_coverage,
4524                detect_breaking_changes,
4525                &exclude_patterns,
4526            )
4527            .await?;
4528
4529        Ok(CallToolResult {
4530            content: vec![ToolContent::Text {
4531                text: serde_json::to_string_pretty(&analysis_result)?,
4532            }],
4533            is_error: Some(false),
4534        })
4535    }
4536}
4537
4538#[cfg(test)]
4539mod tests {
4540    use super::*;
4541    use crate::CodePrismMcpServer;
4542    use std::fs;
4543    use std::sync::Arc;
4544    use tempfile::TempDir;
4545    use tokio::sync::RwLock;
4546
4547    async fn create_test_server() -> Arc<RwLock<CodePrismMcpServer>> {
4548        let temp_dir = TempDir::new().expect("Failed to create temp dir");
4549        let repo_path = temp_dir.path();
4550
4551        // Create test Python files
4552        fs::write(
4553            repo_path.join("main.py"),
4554            r#"
4555class User:
4556    def __init__(self, name: str):
4557        self.name = name
4558    
4559    def get_greeting(self) -> str:
4560        return format_greeting(self.name)
4561
4562def format_greeting(name: str) -> str:
4563    return f"Hello, {name}!"
4564
4565if __name__ == "__main__":
4566    user = User("Alice")
4567    print(user.get_greeting())
4568"#,
4569        )
4570        .unwrap();
4571
4572        fs::write(
4573            repo_path.join("utils.py"),
4574            r#"
4575def validate_input(data: str) -> bool:
4576    return len(data) > 0
4577
4578def process_data(input_data: str) -> str:
4579    if validate_input(input_data):
4580        return input_data.upper()
4581    return ""
4582"#,
4583        )
4584        .unwrap();
4585
4586        let mut server = CodePrismMcpServer::new().expect("Failed to create server");
4587        server
4588            .initialize_with_repository(repo_path)
4589            .await
4590            .expect("Failed to initialize repository");
4591
4592        // Keep temp_dir alive
4593        std::mem::forget(temp_dir);
4594
4595        Arc::new(RwLock::new(server))
4596    }
4597
4598    #[tokio::test]
4599    async fn test_tool_manager_creation() {
4600        let server = create_test_server().await;
4601        let _tool_manager = ToolManager::new(server);
4602
4603        // Tool manager should be created successfully
4604    }
4605
4606    #[tokio::test]
4607    async fn test_list_tools() {
4608        let server = create_test_server().await;
4609        let tool_manager = ToolManager::new(server);
4610
4611        let result = tool_manager
4612            .list_tools(ListToolsParams { cursor: None })
4613            .await;
4614        assert!(result.is_ok());
4615
4616        let tools_result = result.unwrap();
4617        assert_eq!(tools_result.tools.len(), 20); // All implemented tools including API surface analysis
4618        assert!(tools_result.next_cursor.is_none());
4619
4620        // Verify all expected tools are present
4621        let tool_names: Vec<String> = tools_result.tools.iter().map(|t| t.name.clone()).collect();
4622        assert!(tool_names.contains(&"repository_stats".to_string()));
4623        assert!(tool_names.contains(&"trace_path".to_string()));
4624        assert!(tool_names.contains(&"explain_symbol".to_string()));
4625        assert!(tool_names.contains(&"find_dependencies".to_string()));
4626        assert!(tool_names.contains(&"find_references".to_string()));
4627        assert!(tool_names.contains(&"search_symbols".to_string()));
4628        assert!(tool_names.contains(&"search_content".to_string()));
4629        assert!(tool_names.contains(&"find_files".to_string()));
4630        assert!(tool_names.contains(&"content_stats".to_string()));
4631    }
4632
4633    #[tokio::test]
4634    async fn test_repository_stats_tool() {
4635        let server = create_test_server().await;
4636        let tool_manager = ToolManager::new(server);
4637
4638        let params = CallToolParams {
4639            name: "repository_stats".to_string(),
4640            arguments: Some(serde_json::json!({})),
4641        };
4642
4643        let result = tool_manager.call_tool(params).await;
4644        assert!(result.is_ok());
4645
4646        let tool_result = result.unwrap();
4647        assert_eq!(tool_result.is_error, Some(false));
4648        assert_eq!(tool_result.content.len(), 1);
4649
4650        let ToolContent::Text { text } = &tool_result.content[0];
4651        let stats: serde_json::Value = serde_json::from_str(text).unwrap();
4652        assert!(stats["total_files"].as_u64().unwrap() > 0);
4653        assert!(stats["total_nodes"].as_u64().unwrap() > 0);
4654        assert!(stats["status"].as_str().unwrap() == "active");
4655    }
4656
4657    #[tokio::test]
4658    async fn test_search_symbols_tool() {
4659        let server = create_test_server().await;
4660        let tool_manager = ToolManager::new(server);
4661
4662        let params = CallToolParams {
4663            name: "search_symbols".to_string(),
4664            arguments: Some(serde_json::json!({
4665                "pattern": "User",
4666                "symbol_types": ["class"],
4667                "limit": 10
4668            })),
4669        };
4670
4671        let result = tool_manager.call_tool(params).await;
4672        assert!(result.is_ok());
4673
4674        let tool_result = result.unwrap();
4675        assert_eq!(tool_result.is_error, Some(false));
4676
4677        if let ToolContent::Text { text } = &tool_result.content[0] {
4678            let search_result: serde_json::Value = serde_json::from_str(text).unwrap();
4679            assert_eq!(search_result["pattern"].as_str().unwrap(), "User");
4680            assert!(search_result["results"].is_array());
4681        }
4682    }
4683
4684    #[tokio::test]
4685    async fn test_search_symbols_with_regex_pattern() {
4686        let server = create_test_server().await;
4687        let tool_manager = ToolManager::new(server);
4688
4689        let params = CallToolParams {
4690            name: "search_symbols".to_string(),
4691            arguments: Some(serde_json::json!({
4692                "pattern": "get_",
4693                "symbol_types": ["function", "method"],
4694                "limit": 50
4695            })),
4696        };
4697
4698        let result = tool_manager.call_tool(params).await;
4699        assert!(result.is_ok());
4700
4701        let tool_result = result.unwrap();
4702        assert_eq!(tool_result.is_error, Some(false));
4703    }
4704
4705    #[tokio::test]
4706    async fn test_unknown_tool() {
4707        let server = create_test_server().await;
4708        let tool_manager = ToolManager::new(server);
4709
4710        let params = CallToolParams {
4711            name: "unknown_tool".to_string(),
4712            arguments: Some(serde_json::json!({})),
4713        };
4714
4715        let result = tool_manager.call_tool(params).await;
4716        assert!(result.is_ok());
4717
4718        let tool_result = result.unwrap();
4719        assert_eq!(tool_result.is_error, Some(true));
4720
4721        if let ToolContent::Text { text } = &tool_result.content[0] {
4722            assert!(text.contains("Unknown tool: unknown_tool"));
4723        }
4724    }
4725
4726    #[tokio::test]
4727    async fn test_trace_path_missing_arguments() {
4728        let server = create_test_server().await;
4729        let tool_manager = ToolManager::new(server);
4730
4731        let params = CallToolParams {
4732            name: "trace_path".to_string(),
4733            arguments: Some(serde_json::json!({})), // Missing required args
4734        };
4735
4736        let result = tool_manager.call_tool(params).await;
4737        assert!(result.is_err()); // Should fail due to missing arguments
4738    }
4739
4740    #[tokio::test]
4741    async fn test_explain_symbol_missing_arguments() {
4742        let server = create_test_server().await;
4743        let tool_manager = ToolManager::new(server);
4744
4745        let params = CallToolParams {
4746            name: "explain_symbol".to_string(),
4747            arguments: Some(serde_json::json!({})), // Missing required args
4748        };
4749
4750        let result = tool_manager.call_tool(params).await;
4751        assert!(result.is_err()); // Should fail due to missing arguments
4752    }
4753
4754    #[tokio::test]
4755    async fn test_find_dependencies_invalid_dependency_type() {
4756        let server = create_test_server().await;
4757        let tool_manager = ToolManager::new(server);
4758
4759        let params = CallToolParams {
4760            name: "find_dependencies".to_string(),
4761            arguments: Some(serde_json::json!({
4762                "target": "fake_target",
4763                "dependency_type": "invalid_type"
4764            })),
4765        };
4766
4767        let result = tool_manager.call_tool(params).await;
4768        assert!(result.is_ok());
4769
4770        let tool_result = result.unwrap();
4771        assert_eq!(tool_result.is_error, Some(true));
4772
4773        if let ToolContent::Text { text } = &tool_result.content[0] {
4774            assert!(text.contains("Invalid dependency type"));
4775        }
4776    }
4777
4778    #[tokio::test]
4779    async fn test_find_references_missing_arguments() {
4780        let server = create_test_server().await;
4781        let tool_manager = ToolManager::new(server);
4782
4783        let params = CallToolParams {
4784            name: "find_references".to_string(),
4785            arguments: Some(serde_json::json!({})), // Missing required args
4786        };
4787
4788        let result = tool_manager.call_tool(params).await;
4789        assert!(result.is_err()); // Should fail due to missing arguments
4790    }
4791
4792    #[tokio::test]
4793    async fn test_search_symbols_missing_pattern() {
4794        let server = create_test_server().await;
4795        let tool_manager = ToolManager::new(server);
4796
4797        let params = CallToolParams {
4798            name: "search_symbols".to_string(),
4799            arguments: Some(serde_json::json!({})), // Missing required pattern
4800        };
4801
4802        let result = tool_manager.call_tool(params).await;
4803        assert!(result.is_err()); // Should fail due to missing pattern
4804    }
4805
4806    #[tokio::test]
4807    async fn test_tool_input_schemas() {
4808        let server = create_test_server().await;
4809        let tool_manager = ToolManager::new(server);
4810
4811        let tools_result = tool_manager
4812            .list_tools(ListToolsParams { cursor: None })
4813            .await
4814            .unwrap();
4815
4816        for tool in tools_result.tools {
4817            // Every tool should have a valid JSON schema
4818            assert!(tool.input_schema.is_object());
4819
4820            let schema = tool.input_schema.as_object().unwrap();
4821            assert_eq!(schema.get("type").unwrap().as_str().unwrap(), "object");
4822
4823            // Tools should have properties defined
4824            if tool.name != "repository_stats" {
4825                // repository_stats has empty properties
4826                assert!(schema.contains_key("properties"));
4827            }
4828
4829            // Verify required fields for tools that have them
4830            match tool.name.as_str() {
4831                "trace_path" => {
4832                    let required = schema.get("required").unwrap().as_array().unwrap();
4833                    assert!(required.contains(&serde_json::Value::String("source".to_string())));
4834                    assert!(required.contains(&serde_json::Value::String("target".to_string())));
4835                }
4836                "explain_symbol" | "find_references" => {
4837                    let required = schema.get("required").unwrap().as_array().unwrap();
4838                    assert!(required.contains(&serde_json::Value::String("symbol_id".to_string())));
4839                }
4840                "find_dependencies" => {
4841                    let required = schema.get("required").unwrap().as_array().unwrap();
4842                    assert!(required.contains(&serde_json::Value::String("target".to_string())));
4843                }
4844                "search_symbols" => {
4845                    let required = schema.get("required").unwrap().as_array().unwrap();
4846                    assert!(required.contains(&serde_json::Value::String("pattern".to_string())));
4847                }
4848                _ => {} // repository_stats has no required fields
4849            }
4850        }
4851    }
4852
4853    #[tokio::test]
4854    async fn test_tool_capabilities_serialization() {
4855        let capabilities = ToolCapabilities {
4856            list_changed: Some(true),
4857        };
4858
4859        let json = serde_json::to_string(&capabilities).unwrap();
4860        let deserialized: ToolCapabilities = serde_json::from_str(&json).unwrap();
4861
4862        assert_eq!(capabilities.list_changed, deserialized.list_changed);
4863    }
4864
4865    #[tokio::test]
4866    async fn test_call_tool_params_serialization() {
4867        let params = CallToolParams {
4868            name: "test_tool".to_string(),
4869            arguments: Some(serde_json::json!({"key": "value"})),
4870        };
4871
4872        let json = serde_json::to_string(&params).unwrap();
4873        let deserialized: CallToolParams = serde_json::from_str(&json).unwrap();
4874
4875        assert_eq!(params.name, deserialized.name);
4876        assert_eq!(params.arguments, deserialized.arguments);
4877    }
4878
4879    #[tokio::test]
4880    async fn test_call_tool_result_serialization() {
4881        let result = CallToolResult {
4882            content: vec![ToolContent::Text {
4883                text: "Test result".to_string(),
4884            }],
4885            is_error: Some(false),
4886        };
4887
4888        let json = serde_json::to_string(&result).unwrap();
4889        let deserialized: CallToolResult = serde_json::from_str(&json).unwrap();
4890
4891        assert_eq!(result.content.len(), deserialized.content.len());
4892        assert_eq!(result.is_error, deserialized.is_error);
4893    }
4894
4895    #[test]
4896    fn test_parse_node_id_valid() {
4897        let server = Arc::new(RwLock::new(CodePrismMcpServer::new().unwrap()));
4898        let tool_manager = ToolManager::new(server);
4899
4900        // Test with a valid hex string (assuming NodeId::from_hex works with this format)
4901        let valid_hex = "deadbeef12345678";
4902        let result = tool_manager.parse_node_id(valid_hex);
4903
4904        // This test may need adjustment based on actual NodeId::from_hex implementation
4905        // For now, just test that it doesn't panic
4906        match result {
4907            Ok(_) => {}
4908            Err(_) => {} // May fail if format is wrong, but shouldn't panic
4909        }
4910    }
4911
4912    #[tokio::test]
4913    async fn test_parse_node_id_invalid() {
4914        let tool_manager = ToolManager::new(create_test_server().await);
4915
4916        // Test invalid hex string
4917        let result = tool_manager.parse_node_id("invalid-hex");
4918        assert!(result.is_err());
4919
4920        // Test wrong length
4921        let result = tool_manager.parse_node_id("abc123");
4922        assert!(result.is_err());
4923    }
4924
4925    #[tokio::test]
4926    async fn test_source_context_extraction() {
4927        use std::fs;
4928        use std::path::Path;
4929        use tempfile::TempDir;
4930
4931        let temp_dir = TempDir::new().expect("Failed to create temp dir");
4932        let test_file = temp_dir.path().join("test.py");
4933
4934        // Create a test file with known content
4935        fs::write(
4936            &test_file,
4937            r#"# Line 1: Header comment
4938class TestClass:
4939    """Test class docstring."""
4940    
4941    def test_method(self):
4942        """Test method docstring."""
4943        return "Hello, World!"
4944    
4945    def another_method(self):
4946        return 42
4947# Line 11: Footer comment"#,
4948        )
4949        .unwrap();
4950
4951        let server = create_test_server().await;
4952        let tool_manager = ToolManager::new(server);
4953
4954        // Test context extraction around line 5 (the test_method definition)
4955        let context = tool_manager.extract_source_context(&test_file, 5, 2);
4956        assert!(context.is_some());
4957
4958        let context_value = context.unwrap();
4959        assert_eq!(context_value["target_line"], 5);
4960        assert_eq!(context_value["context_range"]["start_line"], 3);
4961        assert_eq!(context_value["context_range"]["end_line"], 7);
4962
4963        let lines = context_value["lines"].as_array().unwrap();
4964        assert_eq!(lines.len(), 5); // Lines 3-7
4965
4966        // Check that the target line is marked correctly
4967        let target_line = lines.iter().find(|line| line["is_target"] == true).unwrap();
4968        assert_eq!(target_line["line_number"], 5);
4969        assert!(target_line["content"]
4970            .as_str()
4971            .unwrap()
4972            .contains("def test_method"));
4973
4974        // Test edge case: line near beginning of file
4975        let context = tool_manager.extract_source_context(&test_file, 1, 3);
4976        assert!(context.is_some());
4977
4978        let context_value = context.unwrap();
4979        assert_eq!(context_value["context_range"]["start_line"], 1);
4980
4981        // Test edge case: line near end of file
4982        let context = tool_manager.extract_source_context(&test_file, 11, 3);
4983        assert!(context.is_some());
4984
4985        let context_value = context.unwrap();
4986        assert_eq!(context_value["context_range"]["end_line"], 11);
4987
4988        // Test invalid line number
4989        let context = tool_manager.extract_source_context(&test_file, 100, 2);
4990        assert!(context.is_none());
4991
4992        // Test nonexistent file
4993        let context = tool_manager.extract_source_context(Path::new("/nonexistent/file.py"), 1, 2);
4994        assert!(context.is_none());
4995    }
4996
4997    #[tokio::test]
4998    async fn test_context_lines_parameter_validation() {
4999        use std::fs;
5000        use tempfile::TempDir;
5001
5002        let temp_dir = TempDir::new().expect("Failed to create temp dir");
5003        let test_file = temp_dir.path().join("test.py");
5004
5005        // Create a test file
5006        fs::write(
5007            &test_file,
5008            r#"# Test file
5009def example_function():
5010    """An example function."""
5011    return "hello"
5012
5013def another_function():
5014    return 42
5015"#,
5016        )
5017        .unwrap();
5018
5019        let server_arc = create_test_server().await;
5020        let tool_manager = ToolManager::new(server_arc);
5021
5022        // Test context extraction with different parameter values
5023
5024        // Test with context_lines = 0
5025        let context = tool_manager.extract_source_context(&test_file, 2, 0);
5026        assert!(context.is_some());
5027        let context_value = context.unwrap();
5028        let lines = context_value["lines"].as_array().unwrap();
5029        assert_eq!(lines.len(), 1); // Only the target line
5030
5031        // Test with normal context_lines
5032        let context = tool_manager.extract_source_context(&test_file, 2, 2);
5033        assert!(context.is_some());
5034        let context_value = context.unwrap();
5035        let lines = context_value["lines"].as_array().unwrap();
5036        assert!(lines.len() > 1); // Should have context lines
5037
5038        // Test with large context_lines value (should be bounded by file length)
5039        let context = tool_manager.extract_source_context(&test_file, 2, 100);
5040        assert!(context.is_some());
5041        let context_value = context.unwrap();
5042        let lines = context_value["lines"].as_array().unwrap();
5043        assert!(lines.len() <= 7); // File only has 7 lines
5044    }
5045
5046    #[tokio::test]
5047    async fn test_context_with_small_files() {
5048        use std::fs;
5049        use tempfile::TempDir;
5050
5051        let temp_dir = TempDir::new().expect("Failed to create temp dir");
5052        let small_file = temp_dir.path().join("small.py");
5053
5054        // Create a very small file
5055        fs::write(&small_file, "x = 1\ny = 2").unwrap();
5056
5057        let server_arc = create_test_server().await;
5058        let tool_manager = ToolManager::new(server_arc);
5059
5060        // Test context extraction on small file
5061        let context = tool_manager.extract_source_context(&small_file, 1, 5);
5062        assert!(context.is_some());
5063
5064        let context_value = context.unwrap();
5065        assert_eq!(context_value["target_line"], 1);
5066
5067        let lines = context_value["lines"].as_array().unwrap();
5068        assert_eq!(lines.len(), 2); // Should only return actual file lines
5069
5070        // Test context extraction on second line
5071        let context = tool_manager.extract_source_context(&small_file, 2, 5);
5072        assert!(context.is_some());
5073
5074        let context_value = context.unwrap();
5075        assert_eq!(context_value["target_line"], 2);
5076
5077        let lines = context_value["lines"].as_array().unwrap();
5078        assert_eq!(lines.len(), 2); // Should return both lines
5079    }
5080
5081    #[tokio::test]
5082    async fn test_context_edge_cases() {
5083        use std::fs;
5084        use tempfile::TempDir;
5085
5086        let temp_dir = TempDir::new().expect("Failed to create temp dir");
5087        let server_arc = create_test_server().await;
5088        let tool_manager = ToolManager::new(server_arc);
5089
5090        // Test with empty file
5091        let empty_file = temp_dir.path().join("empty.py");
5092        fs::write(&empty_file, "").unwrap();
5093
5094        let context = tool_manager.extract_source_context(&empty_file, 1, 2);
5095        assert!(context.is_none()); // Empty file should return None
5096
5097        // Test with line number 0
5098        let normal_file = temp_dir.path().join("normal.py");
5099        fs::write(&normal_file, "line1\nline2\nline3").unwrap();
5100
5101        let context = tool_manager.extract_source_context(&normal_file, 0, 2);
5102        assert!(context.is_none()); // Line 0 is invalid
5103
5104        // Test with unreadable file (permission denied) - Unix only
5105        #[cfg(unix)]
5106        {
5107            use std::os::unix::fs::PermissionsExt;
5108
5109            let restricted_file = temp_dir.path().join("restricted.py");
5110            fs::write(&restricted_file, "secret content").unwrap();
5111
5112            // Remove read permissions
5113            let mut perms = fs::metadata(&restricted_file).unwrap().permissions();
5114            perms.set_mode(0o000);
5115            fs::set_permissions(&restricted_file, perms).unwrap();
5116
5117            let context = tool_manager.extract_source_context(&restricted_file, 1, 2);
5118            assert!(context.is_none()); // Should handle permission errors gracefully
5119
5120            // Restore permissions for cleanup
5121            let mut perms = fs::metadata(&restricted_file).unwrap().permissions();
5122            perms.set_mode(0o644);
5123            fs::set_permissions(&restricted_file, perms).unwrap();
5124        }
5125
5126        // For Windows, test with a nonexistent file (simpler permission test)
5127        #[cfg(windows)]
5128        {
5129            let nonexistent_file = temp_dir.path().join("nonexistent.py");
5130            let context = tool_manager.extract_source_context(&nonexistent_file, 1, 2);
5131            assert!(context.is_none()); // Should handle file not found gracefully
5132        }
5133    }
5134
5135    #[tokio::test]
5136    async fn test_node_info_with_context_creation() {
5137        use std::fs;
5138        use tempfile::TempDir;
5139
5140        let temp_dir = TempDir::new().expect("Failed to create temp dir");
5141        let test_file = temp_dir.path().join("test.py");
5142
5143        // Create a test file
5144        fs::write(
5145            &test_file,
5146            r#"# Test file
5147def example_function():
5148    """An example function."""
5149    return "hello"
5150"#,
5151        )
5152        .unwrap();
5153
5154        let server_arc = create_test_server().await;
5155        let tool_manager = ToolManager::new(server_arc);
5156
5157        // Create a mock node
5158        let span = codeprism_core::ast::Span::new(0, 20, 2, 2, 1, 21);
5159        let node = codeprism_core::ast::Node::new(
5160            "test_repo",
5161            codeprism_core::ast::NodeKind::Function,
5162            "example_function".to_string(),
5163            codeprism_core::ast::Language::Python,
5164            test_file.clone(),
5165            span,
5166        );
5167
5168        // Test node info creation with context
5169        let node_info = tool_manager.create_node_info_with_context(&node, 2);
5170
5171        // Verify basic node info
5172        assert_eq!(node_info["name"], "example_function");
5173        assert_eq!(node_info["kind"], "Function");
5174        assert_eq!(node_info["language"], "Python");
5175
5176        // Verify context is included
5177        assert!(node_info["source_context"].is_object());
5178        assert_eq!(node_info["source_context"]["target_line"], 2);
5179
5180        let lines = node_info["source_context"]["lines"].as_array().unwrap();
5181        assert!(!lines.is_empty());
5182
5183        // Should have target line marked
5184        let has_target = lines.iter().any(|line| line["is_target"] == true);
5185        assert!(has_target);
5186    }
5187
5188    #[tokio::test]
5189    async fn test_new_tools_edge_cases() {
5190        let server = create_test_server().await;
5191        let manager = ToolManager::new(server);
5192
5193        // Test with empty file
5194        let empty_context =
5195            manager.extract_source_context(std::path::Path::new("nonexistent.txt"), 1, 5);
5196        assert!(empty_context.is_none());
5197
5198        // Test with line number 0
5199        let invalid_context = manager.extract_source_context(std::path::Path::new("test.py"), 0, 5);
5200        assert!(invalid_context.is_none());
5201    }
5202
5203    #[tokio::test]
5204    async fn test_analyze_complexity_tool() {
5205        let server = create_test_server().await;
5206        let manager = ToolManager::new(server.clone());
5207
5208        // Test with valid file path
5209        let args = serde_json::json!({
5210            "target": "test_file.py",
5211            "metrics": ["cyclomatic"],
5212            "threshold_warnings": true
5213        });
5214
5215        let result = manager
5216            .analyze_complexity(&*server.read().await, Some(args))
5217            .await;
5218        assert!(result.is_ok());
5219
5220        let call_result = result.unwrap();
5221        assert_eq!(call_result.is_error, Some(true)); // Will fail due to file not existing
5222        assert!(!call_result.content.is_empty());
5223    }
5224
5225    #[tokio::test]
5226    async fn test_analyze_complexity_all_metrics() {
5227        let server = create_test_server().await;
5228        let manager = ToolManager::new(server.clone());
5229
5230        // Test with "all" metrics
5231        let args = serde_json::json!({
5232            "target": "test_file.py",
5233            "metrics": ["all"],
5234            "threshold_warnings": false
5235        });
5236
5237        let result = manager
5238            .analyze_complexity(&*server.read().await, Some(args))
5239            .await;
5240        assert!(result.is_ok());
5241    }
5242
5243    #[tokio::test]
5244    async fn test_analyze_complexity_missing_target() {
5245        let server = create_test_server().await;
5246        let manager = ToolManager::new(server.clone());
5247
5248        // Test without target parameter
5249        let args = serde_json::json!({
5250            "metrics": ["cyclomatic"]
5251        });
5252
5253        let result = manager
5254            .analyze_complexity(&*server.read().await, Some(args))
5255            .await;
5256        assert!(result.is_ok());
5257
5258        let call_result = result.unwrap();
5259        assert_eq!(call_result.is_error, Some(true));
5260    }
5261
5262    #[tokio::test]
5263    #[ignore] // Temporarily disabled due to memory allocation issue in CI
5264    async fn test_find_duplicates_tool() {
5265        let server = create_test_server().await;
5266        let manager = ToolManager::new(server.clone());
5267
5268        // Test with valid parameters
5269        let args = serde_json::json!({
5270            "similarity_threshold": 0.8,
5271            "min_lines": 3,
5272            "scope": "repository"
5273        });
5274
5275        let result = manager
5276            .find_duplicates(&*server.read().await, Some(args))
5277            .await;
5278        assert!(result.is_ok());
5279
5280        let call_result = result.unwrap();
5281        assert_eq!(call_result.is_error, Some(false)); // Should succeed since test server has a repository
5282        assert!(!call_result.content.is_empty());
5283    }
5284
5285    #[tokio::test]
5286    async fn test_find_duplicates_default_params() {
5287        let server = create_test_server().await;
5288        let manager = ToolManager::new(server.clone());
5289
5290        // Test with empty arguments (should use defaults)
5291        let result = manager.find_duplicates(&*server.read().await, None).await;
5292        assert!(result.is_ok());
5293
5294        let call_result = result.unwrap();
5295        assert!(!call_result.content.is_empty());
5296    }
5297
5298    #[tokio::test]
5299    async fn test_calculate_cyclomatic_complexity() {
5300        let server = create_test_server().await;
5301        let manager = ToolManager::new(server);
5302
5303        // Test simple function
5304        let simple_code = "def simple_func():\n    return 42";
5305        let complexity = manager.calculate_cyclomatic_complexity(simple_code);
5306        assert_eq!(complexity, 1); // Base complexity
5307
5308        // Test function with conditionals
5309        let complex_code = r#"
5310def complex_func(x):
5311    if x > 0:
5312        return x
5313    elif x < 0:
5314        return -x
5315    else:
5316        return 0
5317"#;
5318        let complexity = manager.calculate_cyclomatic_complexity(complex_code);
5319        assert!(complexity > 1); // Should have higher complexity
5320    }
5321
5322    #[tokio::test]
5323    async fn test_calculate_cognitive_complexity() {
5324        let server = create_test_server().await;
5325        let manager = ToolManager::new(server);
5326
5327        // Test simple function
5328        let simple_code = "def simple_func():\n    return 42";
5329        let complexity = manager.calculate_cognitive_complexity(simple_code);
5330        assert_eq!(complexity, 0); // No cognitive complexity
5331
5332        // Test nested conditions
5333        let nested_code = r#"
5334def nested_func(x):
5335    if x > 0:
5336        for i in range(x):
5337            if i % 2 == 0:
5338                print(i)
5339"#;
5340        let complexity = manager.calculate_cognitive_complexity(nested_code);
5341        assert!(complexity > 0); // Should have cognitive complexity due to nesting
5342    }
5343
5344    #[tokio::test]
5345    async fn test_calculate_halstead_metrics() {
5346        let server = create_test_server().await;
5347        let manager = ToolManager::new(server);
5348
5349        let code = "x = a + b * c";
5350        let (volume, difficulty, effort) = manager.calculate_halstead_metrics(code);
5351
5352        assert!(volume > 0.0);
5353        assert!(difficulty > 0.0);
5354        assert!(effort > 0.0);
5355        assert!(effort >= difficulty * volume); // Basic relationship check
5356    }
5357
5358    #[tokio::test]
5359    async fn test_calculate_maintainability_index() {
5360        let server = create_test_server().await;
5361        let manager = ToolManager::new(server);
5362
5363        let simple_code = "def simple():\n    return 42";
5364        let mi = manager.calculate_maintainability_index(simple_code, 2);
5365
5366        assert!(mi >= 0.0, "MI should be >= 0, got {}", mi);
5367        assert!(mi <= 100.0, "MI should be <= 100, got {}", mi);
5368
5369        // Complex code should have lower maintainability
5370        let complex_code = r#"
5371def complex_function(a, b, c, d, e):
5372    if a > b:
5373        if c > d:
5374            if e > a:
5375                for i in range(100):
5376                    if i % 2 == 0:
5377                        result = i * a + b * c + d * e
5378                        if result > 1000:
5379                            return result
5380    return 0
5381"#;
5382        let mi_complex = manager.calculate_maintainability_index(complex_code, 10);
5383
5384        // Debug output for troubleshooting
5385        let (volume_simple, _difficulty_simple, _effort_simple) =
5386            manager.calculate_halstead_metrics(simple_code);
5387        let cyclomatic_simple = manager.calculate_cyclomatic_complexity(simple_code);
5388
5389        let (volume_complex, _difficulty_complex, _effort_complex) =
5390            manager.calculate_halstead_metrics(complex_code);
5391        let cyclomatic_complex = manager.calculate_cyclomatic_complexity(complex_code);
5392
5393        // Basic validations
5394        assert!(
5395            mi_complex >= 0.0,
5396            "Complex MI should be >= 0, got {}",
5397            mi_complex
5398        );
5399        assert!(
5400            mi_complex <= 100.0,
5401            "Complex MI should be <= 100, got {}",
5402            mi_complex
5403        );
5404
5405        // The complex code should have higher complexity metrics
5406        assert!(
5407            cyclomatic_complex > cyclomatic_simple,
5408            "Complex code should have higher cyclomatic complexity: {} vs {}",
5409            cyclomatic_complex,
5410            cyclomatic_simple
5411        );
5412        assert!(
5413            volume_complex > volume_simple,
5414            "Complex code should have higher volume: {} vs {}",
5415            volume_complex,
5416            volume_simple
5417        );
5418
5419        // And therefore lower maintainability index
5420        assert!(mi_complex < mi,
5421                "Complex code should have lower MI: {} vs {} (simple: volume={}, cyclomatic={}, complex: volume={}, cyclomatic={})", 
5422                mi_complex, mi, volume_simple, cyclomatic_simple, volume_complex, cyclomatic_complex);
5423    }
5424
5425    #[tokio::test]
5426    async fn test_calculate_content_similarity() {
5427        let server = create_test_server().await;
5428        let manager = ToolManager::new(server);
5429
5430        // Identical content
5431        let content1 = "line 1\nline 2\nline 3";
5432        let content2 = "line 1\nline 2\nline 3";
5433        let similarity = manager._calculate_content_similarity(content1, content2);
5434        assert_eq!(similarity, 1.0);
5435
5436        // Completely different content
5437        let content3 = "different\ncontent\nhere";
5438        let similarity2 = manager._calculate_content_similarity(content1, content3);
5439        assert_eq!(similarity2, 0.0);
5440
5441        // Partial similarity
5442        let content4 = "line 1\nline 2\ndifferent line";
5443        let similarity3 = manager._calculate_content_similarity(content1, content4);
5444        assert!(similarity3 > 0.0 && similarity3 < 1.0);
5445    }
5446
5447    #[tokio::test]
5448    async fn test_complexity_tool_integration() {
5449        use std::fs;
5450        use tempfile::TempDir;
5451
5452        let temp_dir = TempDir::new().unwrap();
5453        let file_path = temp_dir.path().join("test.py");
5454
5455        // Create a test file
5456        fs::write(
5457            &file_path,
5458            r#"
5459def test_function(x, y):
5460    if x > 0:
5461        result = x + y
5462        if y > 0:
5463            result *= 2
5464        return result
5465    else:
5466        return 0
5467"#,
5468        )
5469        .unwrap();
5470
5471        let server = create_test_server().await;
5472        let manager = ToolManager::new(server);
5473
5474        // Test file analysis
5475        let result = manager.analyze_file_complexity(&file_path, &["all".to_string()], true);
5476        assert!(result.is_ok());
5477
5478        let complexity_data = result.unwrap();
5479        assert!(
5480            complexity_data["metrics"]["cyclomatic_complexity"]["value"]
5481                .as_u64()
5482                .unwrap()
5483                > 1
5484        );
5485        assert!(
5486            complexity_data["metrics"]["cognitive_complexity"]["value"]
5487                .as_u64()
5488                .unwrap()
5489                > 0
5490        );
5491    }
5492
5493    #[tokio::test]
5494    async fn test_tool_list_includes_new_tools() {
5495        let server = create_test_server().await;
5496        let manager = ToolManager::new(server);
5497        let params = crate::tools::ListToolsParams { cursor: None };
5498
5499        let result = manager.list_tools(params).await;
5500        assert!(result.is_ok());
5501
5502        let tools_result = result.unwrap();
5503        let tool_names: Vec<&String> = tools_result.tools.iter().map(|t| &t.name).collect();
5504
5505        // Check that our new tools are included
5506        assert!(tool_names.contains(&&"analyze_complexity".to_string()));
5507        assert!(tool_names.contains(&&"find_duplicates".to_string()));
5508
5509        // Should have increased from original 6 tools
5510        assert!(tools_result.tools.len() >= 8);
5511    }
5512
5513    #[tokio::test]
5514    async fn test_new_tools_call_routing() {
5515        let server = create_test_server().await;
5516        let manager = ToolManager::new(server);
5517        let _server = create_test_server().await;
5518
5519        // Test analyze_complexity routing
5520        let complexity_params = crate::tools::CallToolParams {
5521            name: "analyze_complexity".to_string(),
5522            arguments: Some(serde_json::json!({
5523                "target": "test.py",
5524                "metrics": ["cyclomatic"]
5525            })),
5526        };
5527
5528        let result = manager.call_tool(complexity_params).await;
5529        assert!(result.is_ok());
5530
5531        // Test find_duplicates routing
5532        let duplicates_params = crate::tools::CallToolParams {
5533            name: "find_duplicates".to_string(),
5534            arguments: Some(serde_json::json!({
5535                "similarity_threshold": 0.8
5536            })),
5537        };
5538
5539        let result2 = manager.call_tool(duplicates_params).await;
5540        assert!(result2.is_ok());
5541    }
5542
5543    #[tokio::test]
5544    async fn test_detect_patterns_tool() {
5545        let server = create_test_server().await;
5546        let manager = ToolManager::new(server.clone());
5547
5548        // Test with default parameters
5549        let params = crate::tools::CallToolParams {
5550            name: "detect_patterns".to_string(),
5551            arguments: Some(serde_json::json!({
5552                "scope": "repository",
5553                "pattern_types": ["design_patterns"],
5554                "confidence_threshold": 0.8
5555            })),
5556        };
5557
5558        let result = manager.call_tool(params).await;
5559        assert!(result.is_ok());
5560
5561        let call_result = result.unwrap();
5562        assert_eq!(call_result.is_error, Some(false));
5563        assert!(!call_result.content.is_empty());
5564
5565        // Verify the response contains expected fields
5566        if let ToolContent::Text { text } = &call_result.content[0] {
5567            let parsed: serde_json::Value = serde_json::from_str(text).unwrap();
5568            assert!(parsed["patterns"].is_array());
5569            assert!(parsed["summary"].is_object());
5570            assert!(parsed["analysis_successful"].as_bool().unwrap_or(false));
5571        }
5572    }
5573
5574    #[tokio::test]
5575    async fn test_analyze_transitive_dependencies_tool() {
5576        let server = create_test_server().await;
5577        let manager = ToolManager::new(server.clone());
5578
5579        // Test with valid parameters
5580        let params = crate::tools::CallToolParams {
5581            name: "analyze_transitive_dependencies".to_string(),
5582            arguments: Some(serde_json::json!({
5583                "target": "test_file.py",
5584                "max_depth": 3,
5585                "detect_cycles": true,
5586                "dependency_types": ["calls", "imports"]
5587            })),
5588        };
5589
5590        let result = manager.call_tool(params).await;
5591        assert!(result.is_ok());
5592
5593        let call_result = result.unwrap();
5594        assert_eq!(call_result.is_error, Some(false));
5595
5596        // Verify the response contains expected fields
5597        if let ToolContent::Text { text } = &call_result.content[0] {
5598            let parsed: serde_json::Value = serde_json::from_str(text).unwrap();
5599            assert!(parsed["target"].is_string());
5600            assert!(parsed["analysis"].is_object());
5601            assert!(parsed["parameters"].is_object());
5602            assert!(parsed["analysis_successful"].as_bool().unwrap_or(false));
5603        }
5604    }
5605
5606    #[tokio::test]
5607    async fn test_new_phase2_tools_in_list() {
5608        let server = create_test_server().await;
5609        let manager = ToolManager::new(server);
5610        let params = crate::tools::ListToolsParams { cursor: None };
5611
5612        let result = manager.list_tools(params).await;
5613        assert!(result.is_ok());
5614
5615        let tools_result = result.unwrap();
5616        let tool_names: Vec<&String> = tools_result.tools.iter().map(|t| &t.name).collect();
5617
5618        // Check that our new Phase 2 tools are included
5619        assert!(tool_names.contains(&&"detect_patterns".to_string()));
5620        assert!(tool_names.contains(&&"analyze_transitive_dependencies".to_string()));
5621
5622        // Should have all tools including Phase 1 and Phase 2 and Phase 3
5623        assert!(tools_result.tools.len() >= 13); // Original + Phase 1 + Phase 2 + Phase 3
5624    }
5625
5626    #[tokio::test]
5627    async fn test_trace_data_flow_tool() {
5628        let server = create_test_server().await;
5629        let tool_manager = ToolManager::new(server);
5630
5631        // Test with missing arguments
5632        let params = CallToolParams {
5633            name: "trace_data_flow".to_string(),
5634            arguments: Some(serde_json::json!({})),
5635        };
5636
5637        let result = tool_manager.call_tool(params).await;
5638        assert!(result.is_err()); // Should fail due to missing variable_or_parameter
5639
5640        // Test with valid arguments (though the actual analysis might not find much in test data)
5641        let params = CallToolParams {
5642            name: "trace_data_flow".to_string(),
5643            arguments: Some(serde_json::json!({
5644                "variable_or_parameter": "deadbeef12345678", // Dummy hex ID
5645                "direction": "forward",
5646                "max_depth": 5
5647            })),
5648        };
5649
5650        let result = tool_manager.call_tool(params).await;
5651        // Result may be Ok or Error depending on whether the symbol exists, but shouldn't panic
5652        match result {
5653            Ok(tool_result) => {
5654                // If successful, check the structure
5655                if let ToolContent::Text { text } = &tool_result.content[0] {
5656                    let flow_result: serde_json::Value = serde_json::from_str(text).unwrap();
5657                    // Should have basic structure
5658                    assert!(flow_result.is_object());
5659                }
5660            }
5661            Err(_) => {
5662                // Error is acceptable if symbol doesn't exist
5663                assert!(true);
5664            }
5665        }
5666    }
5667
5668    #[tokio::test]
5669    async fn test_phase3_tools_in_list() {
5670        let server = create_test_server().await;
5671        let tool_manager = ToolManager::new(server);
5672
5673        let result = tool_manager
5674            .list_tools(ListToolsParams { cursor: None })
5675            .await;
5676        assert!(result.is_ok());
5677
5678        let tools_result = result.unwrap();
5679        let tool_names: Vec<String> = tools_result.tools.iter().map(|t| t.name.clone()).collect();
5680
5681        // Verify Phase 3 tool is included
5682        assert!(tool_names.contains(&"trace_data_flow".to_string()));
5683
5684        // Verify the tool has proper schema
5685        let trace_data_flow_tool = tools_result
5686            .tools
5687            .iter()
5688            .find(|t| t.name == "trace_data_flow")
5689            .unwrap();
5690
5691        let schema = trace_data_flow_tool.input_schema.as_object().unwrap();
5692        assert!(schema.contains_key("properties"));
5693        assert!(schema.contains_key("required"));
5694
5695        let required = schema.get("required").unwrap().as_array().unwrap();
5696        assert!(required.contains(&serde_json::Value::String(
5697            "variable_or_parameter".to_string()
5698        )));
5699    }
5700
5701    #[tokio::test]
5702    async fn test_find_unused_code_tool() {
5703        let server = create_test_server().await;
5704        let tool_manager = ToolManager::new(server);
5705
5706        // Test with default arguments
5707        let params = CallToolParams {
5708            name: "find_unused_code".to_string(),
5709            arguments: Some(serde_json::json!({})),
5710        };
5711
5712        let result = tool_manager.call_tool(params).await;
5713        assert!(result.is_ok());
5714
5715        let tool_result = result.unwrap();
5716        assert_eq!(tool_result.is_error, Some(false));
5717
5718        if let ToolContent::Text { text } = &tool_result.content[0] {
5719            let unused_result: serde_json::Value = serde_json::from_str(text).unwrap();
5720            // Should have basic structure
5721            assert!(unused_result.is_object());
5722            assert!(unused_result.get("scope").is_some());
5723            assert!(unused_result.get("unused_code").is_some());
5724            assert!(unused_result.get("summary").is_some());
5725            assert!(unused_result.get("recommendations").is_some());
5726        }
5727
5728        // Test with specific parameters
5729        let params = CallToolParams {
5730            name: "find_unused_code".to_string(),
5731            arguments: Some(serde_json::json!({
5732                "analyze_types": ["functions", "classes"],
5733                "confidence_threshold": 0.8,
5734                "consider_external_apis": false
5735            })),
5736        };
5737
5738        let result = tool_manager.call_tool(params).await;
5739        assert!(result.is_ok());
5740    }
5741
5742    #[tokio::test]
5743    async fn test_phase3_unused_code_tools_in_list() {
5744        let server = create_test_server().await;
5745        let tool_manager = ToolManager::new(server);
5746
5747        let result = tool_manager
5748            .list_tools(ListToolsParams { cursor: None })
5749            .await;
5750        assert!(result.is_ok());
5751
5752        let tools_result = result.unwrap();
5753        let tool_names: Vec<String> = tools_result.tools.iter().map(|t| t.name.clone()).collect();
5754
5755        // Verify Phase 3 tools are included
5756        assert!(tool_names.contains(&"trace_data_flow".to_string()));
5757        assert!(tool_names.contains(&"find_unused_code".to_string()));
5758
5759        // Verify the unused code tool has proper schema
5760        let find_unused_code_tool = tools_result
5761            .tools
5762            .iter()
5763            .find(|t| t.name == "find_unused_code")
5764            .unwrap();
5765
5766        let schema = find_unused_code_tool.input_schema.as_object().unwrap();
5767        assert!(schema.contains_key("properties"));
5768
5769        // The tool has no required parameters
5770        if let Some(required) = schema.get("required") {
5771            assert!(required.as_array().unwrap().is_empty());
5772        }
5773    }
5774
5775    #[tokio::test]
5776    async fn test_analyze_security_tool() {
5777        let server = create_test_server().await;
5778        let tool_manager = ToolManager::new(server);
5779
5780        let params = CallToolParams {
5781            name: "analyze_security".to_string(),
5782            arguments: Some(serde_json::json!({
5783                "scope": "repository",
5784                "vulnerability_types": ["injection", "authentication"],
5785                "severity_threshold": "medium",
5786                "include_data_flow_analysis": true,
5787                "check_external_dependencies": true
5788            })),
5789        };
5790
5791        let result = tool_manager.call_tool(params).await;
5792        assert!(result.is_ok());
5793
5794        let tool_result = result.unwrap();
5795        assert!(tool_result.is_error.is_none() || !tool_result.is_error.unwrap());
5796        assert!(!tool_result.content.is_empty());
5797
5798        // Verify the response contains expected security analysis structure
5799        if let ToolContent::Text { text } = &tool_result.content[0] {
5800            let parsed: serde_json::Value = serde_json::from_str(text).unwrap();
5801            assert!(parsed.get("scope").is_some());
5802            assert!(parsed.get("summary").is_some());
5803            assert!(parsed.get("vulnerabilities").is_some());
5804            assert!(parsed.get("recommendations").is_some());
5805            assert!(parsed.get("analysis_parameters").is_some());
5806        }
5807    }
5808
5809    #[tokio::test]
5810    async fn test_analyze_security_default_params() {
5811        let server = create_test_server().await;
5812        let tool_manager = ToolManager::new(server);
5813
5814        let params = CallToolParams {
5815            name: "analyze_security".to_string(),
5816            arguments: Some(serde_json::json!({})),
5817        };
5818
5819        let result = tool_manager.call_tool(params).await;
5820        assert!(result.is_ok());
5821
5822        let tool_result = result.unwrap();
5823        assert!(tool_result.is_error.is_none() || !tool_result.is_error.unwrap());
5824    }
5825
5826    #[tokio::test]
5827    async fn test_analyze_security_specific_vulnerability_types() {
5828        let server = create_test_server().await;
5829        let tool_manager = ToolManager::new(server);
5830
5831        let params = CallToolParams {
5832            name: "analyze_security".to_string(),
5833            arguments: Some(serde_json::json!({
5834                "vulnerability_types": ["injection", "crypto_issues"],
5835                "severity_threshold": "high",
5836                "include_data_flow_analysis": false
5837            })),
5838        };
5839
5840        let result = tool_manager.call_tool(params).await;
5841        assert!(result.is_ok());
5842
5843        let tool_result = result.unwrap();
5844        assert!(tool_result.is_error.is_none() || !tool_result.is_error.unwrap());
5845
5846        // Verify the response focuses on specified vulnerability types
5847        if let ToolContent::Text { text } = &tool_result.content[0] {
5848            let parsed: serde_json::Value = serde_json::from_str(text).unwrap();
5849            let vulnerabilities = parsed.get("vulnerabilities").unwrap().as_array().unwrap();
5850
5851            // Check that only specified vulnerability types are included (if any found)
5852            for vuln in vulnerabilities {
5853                let vuln_type = vuln.get("type").unwrap().as_str().unwrap();
5854                assert!(
5855                    vuln_type.to_lowercase().contains("injection")
5856                        || vuln_type.to_lowercase().contains("crypto")
5857                );
5858            }
5859        }
5860    }
5861
5862    #[tokio::test]
5863    async fn test_phase4_security_tools_in_list() {
5864        let server = create_test_server().await;
5865        let tool_manager = ToolManager::new(server);
5866
5867        let result = tool_manager
5868            .list_tools(ListToolsParams { cursor: None })
5869            .await;
5870        assert!(result.is_ok());
5871
5872        let tools_result = result.unwrap();
5873        let tool_names: Vec<String> = tools_result.tools.iter().map(|t| t.name.clone()).collect();
5874
5875        // Verify Phase 4 security analysis tool is included
5876        assert!(tool_names.contains(&"analyze_security".to_string()));
5877
5878        // Verify the security analysis tool has proper schema
5879        let analyze_security_tool = tools_result
5880            .tools
5881            .iter()
5882            .find(|t| t.name == "analyze_security")
5883            .unwrap();
5884
5885        let schema = analyze_security_tool.input_schema.as_object().unwrap();
5886        assert!(schema.contains_key("properties"));
5887
5888        let properties = schema.get("properties").unwrap().as_object().unwrap();
5889        assert!(properties.contains_key("scope"));
5890        assert!(properties.contains_key("vulnerability_types"));
5891        assert!(properties.contains_key("severity_threshold"));
5892        assert!(properties.contains_key("include_data_flow_analysis"));
5893        assert!(properties.contains_key("check_external_dependencies"));
5894        assert!(properties.contains_key("exclude_patterns"));
5895
5896        // The tool has no required parameters
5897        if let Some(required) = schema.get("required") {
5898            assert!(required.as_array().unwrap().is_empty());
5899        }
5900    }
5901
5902    #[tokio::test]
5903    async fn test_analyze_security_severity_filtering() {
5904        let server = create_test_server().await;
5905        let tool_manager = ToolManager::new(server);
5906
5907        // Test with low severity threshold
5908        let params_low = CallToolParams {
5909            name: "analyze_security".to_string(),
5910            arguments: Some(serde_json::json!({
5911                "severity_threshold": "low",
5912                "vulnerability_types": ["all"]
5913            })),
5914        };
5915
5916        let result_low = tool_manager.call_tool(params_low).await;
5917        assert!(result_low.is_ok());
5918
5919        // Test with critical severity threshold
5920        let params_critical = CallToolParams {
5921            name: "analyze_security".to_string(),
5922            arguments: Some(serde_json::json!({
5923                "severity_threshold": "critical",
5924                "vulnerability_types": ["all"]
5925            })),
5926        };
5927
5928        let result_critical = tool_manager.call_tool(params_critical).await;
5929        assert!(result_critical.is_ok());
5930
5931        // Both should succeed regardless of findings
5932        let tool_result_low = result_low.unwrap();
5933        let tool_result_critical = result_critical.unwrap();
5934
5935        assert!(tool_result_low.is_error.is_none() || !tool_result_low.is_error.unwrap());
5936        assert!(tool_result_critical.is_error.is_none() || !tool_result_critical.is_error.unwrap());
5937    }
5938
5939    #[tokio::test]
5940    async fn test_analyze_performance_tool() {
5941        let server = create_test_server().await;
5942        let tool_manager = ToolManager::new(server);
5943
5944        let params = CallToolParams {
5945            name: "analyze_performance".to_string(),
5946            arguments: Some(serde_json::json!({
5947                "scope": "repository",
5948                "analysis_types": ["time_complexity", "memory_usage"],
5949                "complexity_threshold": "medium",
5950                "include_algorithmic_analysis": true,
5951                "detect_bottlenecks": true
5952            })),
5953        };
5954
5955        let result = tool_manager.call_tool(params).await;
5956        assert!(result.is_ok());
5957
5958        let tool_result = result.unwrap();
5959        assert!(tool_result.is_error.is_none() || !tool_result.is_error.unwrap());
5960        assert!(!tool_result.content.is_empty());
5961
5962        // Verify the response contains expected performance analysis structure
5963        if let ToolContent::Text { text } = &tool_result.content[0] {
5964            let parsed: serde_json::Value = serde_json::from_str(text).unwrap();
5965            assert!(parsed.get("scope").is_some());
5966            assert!(parsed.get("summary").is_some());
5967            assert!(parsed.get("performance_issues").is_some());
5968            assert!(parsed.get("recommendations").is_some());
5969            assert!(parsed.get("analysis_parameters").is_some());
5970        }
5971    }
5972
5973    #[tokio::test]
5974    async fn test_analyze_performance_default_params() {
5975        let server = create_test_server().await;
5976        let tool_manager = ToolManager::new(server);
5977
5978        let params = CallToolParams {
5979            name: "analyze_performance".to_string(),
5980            arguments: Some(serde_json::json!({})),
5981        };
5982
5983        let result = tool_manager.call_tool(params).await;
5984        assert!(result.is_ok());
5985
5986        let tool_result = result.unwrap();
5987        assert!(tool_result.is_error.is_none() || !tool_result.is_error.unwrap());
5988    }
5989
5990    #[tokio::test]
5991    async fn test_analyze_performance_specific_analysis_types() {
5992        let server = create_test_server().await;
5993        let tool_manager = ToolManager::new(server);
5994
5995        let params = CallToolParams {
5996            name: "analyze_performance".to_string(),
5997            arguments: Some(serde_json::json!({
5998                "analysis_types": ["hot_spots", "scalability"],
5999                "complexity_threshold": "high",
6000                "include_algorithmic_analysis": false,
6001                "detect_bottlenecks": false
6002            })),
6003        };
6004
6005        let result = tool_manager.call_tool(params).await;
6006        assert!(result.is_ok());
6007
6008        let tool_result = result.unwrap();
6009        assert!(tool_result.is_error.is_none() || !tool_result.is_error.unwrap());
6010
6011        // Verify the response focuses on specified analysis types
6012        if let ToolContent::Text { text } = &tool_result.content[0] {
6013            let parsed: serde_json::Value = serde_json::from_str(text).unwrap();
6014            let issues = parsed
6015                .get("performance_issues")
6016                .unwrap()
6017                .as_array()
6018                .unwrap();
6019
6020            // Check that only specified analysis types are included (if any found)
6021            for issue in issues {
6022                let issue_category = issue.get("category").unwrap().as_str().unwrap();
6023                assert!(issue_category == "hot_spots" || issue_category == "scalability");
6024            }
6025        }
6026    }
6027
6028    #[tokio::test]
6029    async fn test_analyze_performance_complexity_filtering() {
6030        let server = create_test_server().await;
6031        let tool_manager = ToolManager::new(server);
6032
6033        // Test with low complexity threshold
6034        let params_low = CallToolParams {
6035            name: "analyze_performance".to_string(),
6036            arguments: Some(serde_json::json!({
6037                "complexity_threshold": "low",
6038                "analysis_types": ["all"]
6039            })),
6040        };
6041
6042        let result_low = tool_manager.call_tool(params_low).await;
6043        assert!(result_low.is_ok());
6044
6045        // Test with high complexity threshold
6046        let params_high = CallToolParams {
6047            name: "analyze_performance".to_string(),
6048            arguments: Some(serde_json::json!({
6049                "complexity_threshold": "high",
6050                "analysis_types": ["all"]
6051            })),
6052        };
6053
6054        let result_high = tool_manager.call_tool(params_high).await;
6055        assert!(result_high.is_ok());
6056
6057        // Both should succeed regardless of findings
6058        let tool_result_low = result_low.unwrap();
6059        let tool_result_high = result_high.unwrap();
6060
6061        assert!(tool_result_low.is_error.is_none() || !tool_result_low.is_error.unwrap());
6062        assert!(tool_result_high.is_error.is_none() || !tool_result_high.is_error.unwrap());
6063    }
6064
6065    #[tokio::test]
6066    async fn test_phase4_performance_tools_in_list() {
6067        let server = create_test_server().await;
6068        let tool_manager = ToolManager::new(server);
6069
6070        let result = tool_manager
6071            .list_tools(ListToolsParams { cursor: None })
6072            .await;
6073        assert!(result.is_ok());
6074
6075        let tools_result = result.unwrap();
6076        let tool_names: Vec<String> = tools_result.tools.iter().map(|t| t.name.clone()).collect();
6077
6078        // Verify Phase 4 performance analysis tool is included
6079        assert!(tool_names.contains(&"analyze_performance".to_string()));
6080
6081        // Verify the performance analysis tool has proper schema
6082        let analyze_performance_tool = tools_result
6083            .tools
6084            .iter()
6085            .find(|t| t.name == "analyze_performance")
6086            .unwrap();
6087
6088        let schema = analyze_performance_tool.input_schema.as_object().unwrap();
6089        assert!(schema.contains_key("properties"));
6090
6091        let properties = schema.get("properties").unwrap().as_object().unwrap();
6092        assert!(properties.contains_key("scope"));
6093        assert!(properties.contains_key("analysis_types"));
6094        assert!(properties.contains_key("complexity_threshold"));
6095        assert!(properties.contains_key("include_algorithmic_analysis"));
6096        assert!(properties.contains_key("detect_bottlenecks"));
6097        assert!(properties.contains_key("exclude_patterns"));
6098
6099        // The tool has no required parameters
6100        if let Some(required) = schema.get("required") {
6101            assert!(required.as_array().unwrap().is_empty());
6102        }
6103    }
6104
6105    #[tokio::test]
6106    async fn test_analyze_api_surface_tool() {
6107        let server = create_test_server().await;
6108        let tool_manager = ToolManager::new(server);
6109
6110        let params = CallToolParams {
6111            name: "analyze_api_surface".to_string(),
6112            arguments: Some(serde_json::json!({
6113                "scope": "repository",
6114                "analysis_types": ["public_api", "documentation"],
6115                "api_version": "1.0.0",
6116                "include_private_apis": true,
6117                "check_documentation_coverage": true,
6118                "detect_breaking_changes": true
6119            })),
6120        };
6121
6122        let result = tool_manager.call_tool(params).await;
6123        assert!(result.is_ok());
6124
6125        let tool_result = result.unwrap();
6126        assert!(tool_result.is_error.is_none() || !tool_result.is_error.unwrap());
6127        assert!(!tool_result.content.is_empty());
6128
6129        // Verify the response contains expected API surface analysis structure
6130        if let ToolContent::Text { text } = &tool_result.content[0] {
6131            let parsed: serde_json::Value = serde_json::from_str(text).unwrap();
6132            assert!(parsed.get("scope").is_some());
6133            assert!(parsed.get("summary").is_some());
6134            assert!(parsed.get("api_issues").is_some());
6135            assert!(parsed.get("recommendations").is_some());
6136            assert!(parsed.get("analysis_parameters").is_some());
6137        }
6138    }
6139
6140    #[tokio::test]
6141    async fn test_analyze_api_surface_default_params() {
6142        let server = create_test_server().await;
6143        let tool_manager = ToolManager::new(server);
6144
6145        let params = CallToolParams {
6146            name: "analyze_api_surface".to_string(),
6147            arguments: Some(serde_json::json!({})),
6148        };
6149
6150        let result = tool_manager.call_tool(params).await;
6151        assert!(result.is_ok());
6152
6153        let tool_result = result.unwrap();
6154        assert!(tool_result.is_error.is_none() || !tool_result.is_error.unwrap());
6155    }
6156
6157    #[tokio::test]
6158    async fn test_analyze_api_surface_specific_analysis_types() {
6159        let server = create_test_server().await;
6160        let tool_manager = ToolManager::new(server);
6161
6162        let params = CallToolParams {
6163            name: "analyze_api_surface".to_string(),
6164            arguments: Some(serde_json::json!({
6165                "analysis_types": ["versioning", "breaking_changes"],
6166                "api_version": "2.1.0",
6167                "include_private_apis": false,
6168                "detect_breaking_changes": true
6169            })),
6170        };
6171
6172        let result = tool_manager.call_tool(params).await;
6173        assert!(result.is_ok());
6174
6175        let tool_result = result.unwrap();
6176        assert!(tool_result.is_error.is_none() || !tool_result.is_error.unwrap());
6177
6178        // Verify the response focuses on specified analysis types
6179        if let ToolContent::Text { text } = &tool_result.content[0] {
6180            let parsed: serde_json::Value = serde_json::from_str(text).unwrap();
6181            let issues = parsed.get("api_issues").unwrap().as_array().unwrap();
6182
6183            // Check that only specified analysis types are included (if any found)
6184            for issue in issues {
6185                let issue_category = issue.get("category").unwrap().as_str().unwrap();
6186                assert!(issue_category == "versioning" || issue_category == "breaking_changes");
6187            }
6188        }
6189    }
6190
6191    #[tokio::test]
6192    async fn test_analyze_api_surface_with_version() {
6193        let server = create_test_server().await;
6194        let tool_manager = ToolManager::new(server);
6195
6196        let params = CallToolParams {
6197            name: "analyze_api_surface".to_string(),
6198            arguments: Some(serde_json::json!({
6199                "analysis_types": ["compatibility", "versioning"],
6200                "api_version": "v1.2.3",
6201                "include_private_apis": false,
6202                "check_documentation_coverage": false
6203            })),
6204        };
6205
6206        let result = tool_manager.call_tool(params).await;
6207        assert!(result.is_ok());
6208
6209        let tool_result = result.unwrap();
6210        assert!(tool_result.is_error.is_none() || !tool_result.is_error.unwrap());
6211
6212        // Verify the API version is included in the analysis
6213        if let ToolContent::Text { text } = &tool_result.content[0] {
6214            let parsed: serde_json::Value = serde_json::from_str(text).unwrap();
6215            let analysis_params = parsed.get("analysis_parameters").unwrap();
6216            assert_eq!(
6217                analysis_params.get("api_version").unwrap().as_str(),
6218                Some("v1.2.3")
6219            );
6220        }
6221    }
6222
6223    #[tokio::test]
6224    async fn test_phase4_api_surface_tools_in_list() {
6225        let server = create_test_server().await;
6226        let tool_manager = ToolManager::new(server);
6227
6228        let result = tool_manager
6229            .list_tools(ListToolsParams { cursor: None })
6230            .await;
6231        assert!(result.is_ok());
6232
6233        let tools_result = result.unwrap();
6234        let tool_names: Vec<String> = tools_result.tools.iter().map(|t| t.name.clone()).collect();
6235
6236        // Verify Phase 4 API surface analysis tool is included
6237        assert!(tool_names.contains(&"analyze_api_surface".to_string()));
6238
6239        // Verify the API surface analysis tool has proper schema
6240        let analyze_api_surface_tool = tools_result
6241            .tools
6242            .iter()
6243            .find(|t| t.name == "analyze_api_surface")
6244            .unwrap();
6245
6246        let schema = analyze_api_surface_tool.input_schema.as_object().unwrap();
6247        assert!(schema.contains_key("properties"));
6248
6249        let properties = schema.get("properties").unwrap().as_object().unwrap();
6250        assert!(properties.contains_key("scope"));
6251        assert!(properties.contains_key("analysis_types"));
6252        assert!(properties.contains_key("api_version"));
6253        assert!(properties.contains_key("include_private_apis"));
6254        assert!(properties.contains_key("check_documentation_coverage"));
6255        assert!(properties.contains_key("detect_breaking_changes"));
6256        assert!(properties.contains_key("exclude_patterns"));
6257
6258        // The tool has no required parameters
6259        if let Some(required) = schema.get("required") {
6260            assert!(required.as_array().unwrap().is_empty());
6261        }
6262    }
6263
6264    #[tokio::test]
6265    async fn test_phase4_all_tools_integration() {
6266        let server = create_test_server().await;
6267        let tool_manager = ToolManager::new(server);
6268
6269        let result = tool_manager
6270            .list_tools(ListToolsParams { cursor: None })
6271            .await;
6272        assert!(result.is_ok());
6273
6274        let tools_result = result.unwrap();
6275        let tool_names: Vec<String> = tools_result.tools.iter().map(|t| t.name.clone()).collect();
6276
6277        // Verify all Phase 4 tools are present
6278        assert!(tool_names.contains(&"analyze_security".to_string()));
6279        assert!(tool_names.contains(&"analyze_performance".to_string()));
6280        assert!(tool_names.contains(&"analyze_api_surface".to_string()));
6281
6282        // Verify all Phase 3 tools are still present
6283        assert!(tool_names.contains(&"trace_data_flow".to_string()));
6284        assert!(tool_names.contains(&"find_unused_code".to_string()));
6285
6286        // Total tools should now be 20
6287        assert_eq!(tools_result.tools.len(), 20);
6288    }
6289}
6290
6291impl ToolManager {
6292    /// Helper method for design pattern analysis
6293    async fn analyze_design_patterns(
6294        &self,
6295        server: &CodePrismMcpServer,
6296        pattern_types: &[String],
6297        confidence_threshold: f64,
6298        include_suggestions: bool,
6299    ) -> Result<Vec<serde_json::Value>> {
6300        let mut detected_patterns = Vec::new();
6301
6302        // Analyze Singleton Pattern
6303        if pattern_types.contains(&"design_patterns".to_string())
6304            || pattern_types.contains(&"all".to_string())
6305        {
6306            let singleton_patterns = self
6307                .detect_singleton_pattern(server, confidence_threshold)
6308                .await?;
6309            detected_patterns.extend(singleton_patterns);
6310
6311            let factory_patterns = self
6312                .detect_factory_pattern(server, confidence_threshold)
6313                .await?;
6314            detected_patterns.extend(factory_patterns);
6315
6316            let observer_patterns = self
6317                .detect_observer_pattern(server, confidence_threshold)
6318                .await?;
6319            detected_patterns.extend(observer_patterns);
6320        }
6321
6322        // Analyze Anti-patterns
6323        if pattern_types.contains(&"anti_patterns".to_string())
6324            || pattern_types.contains(&"all".to_string())
6325        {
6326            let anti_patterns = self
6327                .detect_anti_patterns(server, confidence_threshold)
6328                .await?;
6329            detected_patterns.extend(anti_patterns);
6330        }
6331
6332        // Analyze Architectural patterns
6333        if pattern_types.contains(&"architectural_patterns".to_string())
6334            || pattern_types.contains(&"all".to_string())
6335        {
6336            let arch_patterns = self
6337                .detect_architectural_patterns(server, confidence_threshold)
6338                .await?;
6339            detected_patterns.extend(arch_patterns);
6340        }
6341
6342        // Analyze Metaprogramming patterns
6343        if pattern_types.contains(&"metaprogramming_patterns".to_string())
6344            || pattern_types.contains(&"all".to_string())
6345        {
6346            let metaprogramming_patterns = self
6347                .detect_metaprogramming_patterns(server, confidence_threshold)
6348                .await?;
6349            detected_patterns.extend(metaprogramming_patterns);
6350        }
6351
6352        // Add suggestions if requested
6353        if include_suggestions {
6354            for pattern in &mut detected_patterns {
6355                if let Some(pattern_obj) = pattern.as_object_mut() {
6356                    if let Some(pattern_type) = pattern_obj.get("type").and_then(|v| v.as_str()) {
6357                        let suggestions = self.get_pattern_suggestions(pattern_type);
6358                        pattern_obj.insert("suggestions".to_string(), suggestions.into());
6359                    }
6360                }
6361            }
6362        }
6363
6364        Ok(detected_patterns)
6365    }
6366
6367    /// Helper method for transitive dependency analysis
6368    async fn perform_transitive_analysis(
6369        &self,
6370        server: &CodePrismMcpServer,
6371        target: &str,
6372        max_depth: usize,
6373        detect_cycles: bool,
6374        _include_external: bool,
6375        dependency_types: &[String],
6376    ) -> Result<serde_json::Value> {
6377        // Parse target (could be node ID or file path)
6378        let target_nodes = if target.len() == 32 && target.chars().all(|c| c.is_ascii_hexdigit()) {
6379            // It's a node ID
6380            if let Ok(node_id) = self.parse_node_id(target) {
6381                if let Some(node) = server.graph_store().get_node(&node_id) {
6382                    vec![node]
6383                } else {
6384                    return Ok(serde_json::json!({
6385                        "error": "Node not found",
6386                        "target": target
6387                    }));
6388                }
6389            } else {
6390                return Ok(serde_json::json!({
6391                    "error": "Invalid node ID format",
6392                    "target": target
6393                }));
6394            }
6395        } else {
6396            // It's a file path
6397            let file_path = std::path::PathBuf::from(target);
6398            server.graph_store().get_nodes_in_file(&file_path)
6399        };
6400
6401        if target_nodes.is_empty() {
6402            return Ok(serde_json::json!({
6403                "error": "No nodes found for target",
6404                "target": target
6405            }));
6406        }
6407
6408        let mut analysis_results = Vec::new();
6409
6410        for target_node in &target_nodes {
6411            let dependencies = self
6412                .build_transitive_dependencies(server, &target_node.id, max_depth, dependency_types)
6413                .await?;
6414
6415            let mut cycles = Vec::new();
6416            if detect_cycles {
6417                cycles = self
6418                    .detect_dependency_cycles(server, &target_node.id, &dependencies)
6419                    .await?;
6420            }
6421
6422            let analysis = serde_json::json!({
6423                "target_node": {
6424                    "id": target_node.id.to_hex(),
6425                    "name": target_node.name,
6426                    "kind": format!("{:?}", target_node.kind),
6427                    "file": target_node.file.display().to_string(),
6428                    "span": target_node.span
6429                },
6430                "transitive_dependencies": dependencies,
6431                "dependency_chains": self.build_dependency_chains(server, &target_node.id, max_depth).await?,
6432                "cycles": cycles,
6433                "statistics": {
6434                    "total_dependencies": dependencies.len(),
6435                    "max_depth_reached": self.calculate_max_depth(&dependencies),
6436                    "cycles_detected": cycles.len()
6437                }
6438            });
6439
6440            analysis_results.push(analysis);
6441        }
6442
6443        Ok(serde_json::json!({
6444            "target_file_or_symbol": target,
6445            "analyses": analysis_results,
6446            "summary": {
6447                "total_nodes_analyzed": target_nodes.len(),
6448                "total_unique_dependencies": self.count_unique_dependencies(&analysis_results),
6449                "total_cycles_found": self.count_total_cycles(&analysis_results)
6450            }
6451        }))
6452    }
6453
6454    /// Detect Singleton pattern
6455    async fn detect_singleton_pattern(
6456        &self,
6457        server: &CodePrismMcpServer,
6458        confidence_threshold: f64,
6459    ) -> Result<Vec<serde_json::Value>> {
6460        let mut patterns = Vec::new();
6461        let classes = server
6462            .graph_store()
6463            .get_nodes_by_kind(codeprism_core::NodeKind::Class);
6464
6465        for class in classes {
6466            let mut confidence = 0.0;
6467            let mut indicators = Vec::new();
6468
6469            // Check for private constructor pattern
6470            let methods = server.graph_store().get_outgoing_edges(&class.id);
6471            let has_private_constructor = methods.iter().any(|edge| {
6472                if let Some(target_node) = server.graph_store().get_node(&edge.target) {
6473                    target_node.kind == codeprism_core::NodeKind::Method
6474                        && target_node.name.contains("__init__")
6475                        || target_node.name.contains("constructor")
6476                } else {
6477                    false
6478                }
6479            });
6480
6481            if has_private_constructor {
6482                confidence += 0.3;
6483                indicators.push("Private constructor detected");
6484            }
6485
6486            // Check for getInstance method
6487            let has_get_instance = methods.iter().any(|edge| {
6488                if let Some(target_node) = server.graph_store().get_node(&edge.target) {
6489                    target_node.name.to_lowercase().contains("getinstance")
6490                        || target_node.name.to_lowercase().contains("get_instance")
6491                } else {
6492                    false
6493                }
6494            });
6495
6496            if has_get_instance {
6497                confidence += 0.4;
6498                indicators.push("getInstance method detected");
6499            }
6500
6501            // Check for static instance variable
6502            let variables = server
6503                .graph_store()
6504                .get_nodes_by_kind(codeprism_core::NodeKind::Variable);
6505            let has_static_instance = variables.iter().any(|var| {
6506                var.file == class.file
6507                    && (var.name.contains("instance") || var.name.contains("_instance"))
6508            });
6509
6510            if has_static_instance {
6511                confidence += 0.3;
6512                indicators.push("Static instance variable detected");
6513            }
6514
6515            if confidence >= confidence_threshold {
6516                patterns.push(serde_json::json!({
6517                    "type": "Singleton",
6518                    "category": "design_pattern",
6519                    "confidence": confidence,
6520                    "class": {
6521                        "id": class.id.to_hex(),
6522                        "name": class.name,
6523                        "file": class.file.display().to_string(),
6524                        "span": class.span
6525                    },
6526                    "indicators": indicators,
6527                    "description": "Class appears to implement the Singleton design pattern"
6528                }));
6529            }
6530        }
6531
6532        Ok(patterns)
6533    }
6534
6535    /// Detect Factory pattern
6536    async fn detect_factory_pattern(
6537        &self,
6538        server: &CodePrismMcpServer,
6539        confidence_threshold: f64,
6540    ) -> Result<Vec<serde_json::Value>> {
6541        let mut patterns = Vec::new();
6542        let classes = server
6543            .graph_store()
6544            .get_nodes_by_kind(codeprism_core::NodeKind::Class);
6545
6546        for class in classes {
6547            if class.name.to_lowercase().contains("factory") {
6548                let mut confidence = 0.5; // Base confidence for Factory in name
6549                let mut indicators = vec!["Factory in class name".to_string()];
6550
6551                // Check for creation methods
6552                let methods = server.graph_store().get_outgoing_edges(&class.id);
6553                let creation_methods = methods
6554                    .iter()
6555                    .filter(|edge| {
6556                        if let Some(target_node) = server.graph_store().get_node(&edge.target) {
6557                            let method_name = target_node.name.to_lowercase();
6558                            method_name.contains("create")
6559                                || method_name.contains("build")
6560                                || method_name.contains("make")
6561                                || method_name.contains("new")
6562                        } else {
6563                            false
6564                        }
6565                    })
6566                    .count();
6567
6568                if creation_methods > 0 {
6569                    confidence += 0.3;
6570                    indicators.push(format!("{} creation methods detected", creation_methods));
6571                }
6572
6573                if confidence >= confidence_threshold {
6574                    patterns.push(serde_json::json!({
6575                        "type": "Factory",
6576                        "category": "design_pattern",
6577                        "confidence": confidence,
6578                        "class": {
6579                            "id": class.id.to_hex(),
6580                            "name": class.name,
6581                            "file": class.file.display().to_string(),
6582                            "span": class.span
6583                        },
6584                        "indicators": indicators,
6585                        "description": "Class appears to implement the Factory design pattern"
6586                    }));
6587                }
6588            }
6589        }
6590
6591        Ok(patterns)
6592    }
6593
6594    /// Detect Observer pattern
6595    async fn detect_observer_pattern(
6596        &self,
6597        server: &CodePrismMcpServer,
6598        confidence_threshold: f64,
6599    ) -> Result<Vec<serde_json::Value>> {
6600        let mut patterns = Vec::new();
6601        let classes = server
6602            .graph_store()
6603            .get_nodes_by_kind(codeprism_core::NodeKind::Class);
6604
6605        for class in classes {
6606            let mut confidence = 0.0;
6607            let mut indicators = Vec::new();
6608
6609            // Check for observer-related method names
6610            let methods = server.graph_store().get_outgoing_edges(&class.id);
6611            let observer_methods = methods
6612                .iter()
6613                .filter(|edge| {
6614                    if let Some(target_node) = server.graph_store().get_node(&edge.target) {
6615                        let method_name = target_node.name.to_lowercase();
6616                        method_name.contains("notify")
6617                            || method_name.contains("update")
6618                            || method_name.contains("observe")
6619                            || method_name.contains("subscribe")
6620                            || method_name.contains("unsubscribe")
6621                    } else {
6622                        false
6623                    }
6624                })
6625                .count();
6626
6627            if observer_methods > 0 {
6628                confidence += 0.4;
6629                indicators.push(format!(
6630                    "{} observer-related methods detected",
6631                    observer_methods
6632                ));
6633            }
6634
6635            // Check for event emissions
6636            let events = server
6637                .graph_store()
6638                .get_outgoing_edges(&class.id)
6639                .iter()
6640                .filter(|edge| edge.kind == codeprism_core::EdgeKind::Emits)
6641                .count();
6642
6643            if events > 0 {
6644                confidence += 0.3;
6645                indicators.push(format!("{} event emissions detected", events));
6646            }
6647
6648            if confidence >= confidence_threshold {
6649                patterns.push(serde_json::json!({
6650                    "type": "Observer",
6651                    "category": "design_pattern",
6652                    "confidence": confidence,
6653                    "class": {
6654                        "id": class.id.to_hex(),
6655                        "name": class.name,
6656                        "file": class.file.display().to_string(),
6657                        "span": class.span
6658                    },
6659                    "indicators": indicators,
6660                    "description": "Class appears to implement the Observer design pattern"
6661                }));
6662            }
6663        }
6664
6665        Ok(patterns)
6666    }
6667
6668    /// Detect anti-patterns
6669    async fn detect_anti_patterns(
6670        &self,
6671        server: &CodePrismMcpServer,
6672        confidence_threshold: f64,
6673    ) -> Result<Vec<serde_json::Value>> {
6674        let mut patterns = Vec::new();
6675
6676        // God Class anti-pattern
6677        let classes = server
6678            .graph_store()
6679            .get_nodes_by_kind(codeprism_core::NodeKind::Class);
6680        for class in classes {
6681            let methods = server.graph_store().get_outgoing_edges(&class.id);
6682            let method_count = methods.len();
6683
6684            if method_count > 20 {
6685                // Threshold for "God Class"
6686                let confidence = ((method_count as f64 - 20.0) / 30.0).min(1.0);
6687                if confidence >= confidence_threshold {
6688                    patterns.push(serde_json::json!({
6689                        "type": "God Class",
6690                        "category": "anti_pattern",
6691                        "confidence": confidence,
6692                        "class": {
6693                            "id": class.id.to_hex(),
6694                            "name": class.name,
6695                            "file": class.file.display().to_string(),
6696                            "span": class.span
6697                        },
6698                        "indicators": [format!("{} methods detected (threshold: 20)", method_count)],
6699                        "description": "Class has too many responsibilities (God Class anti-pattern)",
6700                        "severity": "high"
6701                    }));
6702                }
6703            }
6704        }
6705
6706        // Long Method anti-pattern
6707        let functions = server
6708            .graph_store()
6709            .get_nodes_by_kind(codeprism_core::NodeKind::Function);
6710        for function in functions {
6711            let lines = function.span.end_line - function.span.start_line + 1;
6712            if lines > 50 {
6713                // Threshold for "Long Method"
6714                let confidence = ((lines as f64 - 50.0) / 100.0).min(1.0);
6715                if confidence >= confidence_threshold {
6716                    patterns.push(serde_json::json!({
6717                        "type": "Long Method",
6718                        "category": "anti_pattern",
6719                        "confidence": confidence,
6720                        "function": {
6721                            "id": function.id.to_hex(),
6722                            "name": function.name,
6723                            "file": function.file.display().to_string(),
6724                            "span": function.span
6725                        },
6726                        "indicators": [format!("{} lines of code (threshold: 50)", lines)],
6727                        "description": "Method is too long and complex",
6728                        "severity": "medium"
6729                    }));
6730                }
6731            }
6732        }
6733
6734        Ok(patterns)
6735    }
6736
6737    /// Detect architectural patterns
6738    async fn detect_architectural_patterns(
6739        &self,
6740        server: &CodePrismMcpServer,
6741        confidence_threshold: f64,
6742    ) -> Result<Vec<serde_json::Value>> {
6743        let mut patterns = Vec::new();
6744
6745        // MVC Pattern detection
6746        let classes = server
6747            .graph_store()
6748            .get_nodes_by_kind(codeprism_core::NodeKind::Class);
6749        let mut controllers = 0;
6750        let mut models = 0;
6751        let mut views = 0;
6752
6753        for class in &classes {
6754            let name_lower = class.name.to_lowercase();
6755            if name_lower.contains("controller") {
6756                controllers += 1;
6757            } else if name_lower.contains("model") {
6758                models += 1;
6759            } else if name_lower.contains("view") {
6760                views += 1;
6761            }
6762        }
6763
6764        if controllers > 0 && models > 0 && views > 0 {
6765            let confidence =
6766                ((controllers + models + views) as f64 / classes.len() as f64).min(1.0);
6767            if confidence >= confidence_threshold {
6768                patterns.push(serde_json::json!({
6769                    "type": "MVC (Model-View-Controller)",
6770                    "category": "architectural_pattern",
6771                    "confidence": confidence,
6772                    "indicators": [
6773                        format!("{} Controllers", controllers),
6774                        format!("{} Models", models),
6775                        format!("{} Views", views)
6776                    ],
6777                    "description": "Application appears to follow MVC architectural pattern"
6778                }));
6779            }
6780        }
6781
6782        // Repository Pattern detection
6783        let repository_classes = classes
6784            .iter()
6785            .filter(|c| {
6786                c.name.to_lowercase().contains("repository")
6787                    || c.name.to_lowercase().contains("repo")
6788            })
6789            .count();
6790
6791        if repository_classes > 0 {
6792            let confidence = (repository_classes as f64 / classes.len() as f64 * 10.0).min(1.0);
6793            if confidence >= confidence_threshold {
6794                patterns.push(serde_json::json!({
6795                    "type": "Repository Pattern",
6796                    "category": "architectural_pattern",
6797                    "confidence": confidence,
6798                    "indicators": [format!("{} Repository classes", repository_classes)],
6799                    "description": "Data access appears to follow Repository pattern"
6800                }));
6801            }
6802        }
6803
6804        Ok(patterns)
6805    }
6806
6807    /// Detect metaprogramming patterns specific to Python
6808    async fn detect_metaprogramming_patterns(
6809        &self,
6810        server: &CodePrismMcpServer,
6811        confidence_threshold: f64,
6812    ) -> Result<Vec<serde_json::Value>> {
6813        let mut patterns = Vec::new();
6814
6815        // Registry Metaclass Pattern (like AgentMetaclass)
6816        let registry_patterns = self
6817            .detect_registry_metaclass_pattern(server, confidence_threshold)
6818            .await?;
6819        patterns.extend(registry_patterns);
6820
6821        // Attribute Injection Metaclass Pattern
6822        let attribute_injection_patterns = self
6823            .detect_attribute_injection_metaclass_pattern(server, confidence_threshold)
6824            .await?;
6825        patterns.extend(attribute_injection_patterns);
6826
6827        // Decorator Factory Pattern
6828        let decorator_factory_patterns = self
6829            .detect_decorator_factory_pattern(server, confidence_threshold)
6830            .await?;
6831        patterns.extend(decorator_factory_patterns);
6832
6833        // Property Descriptor Pattern
6834        let descriptor_patterns = self
6835            .detect_property_descriptor_pattern(server, confidence_threshold)
6836            .await?;
6837        patterns.extend(descriptor_patterns);
6838
6839        // Dynamic Attribute Pattern (__getattr__/__setattr__)
6840        let dynamic_attr_patterns = self
6841            .detect_dynamic_attribute_pattern(server, confidence_threshold)
6842            .await?;
6843        patterns.extend(dynamic_attr_patterns);
6844
6845        // Mixin Pattern
6846        let mixin_patterns = self
6847            .detect_mixin_pattern(server, confidence_threshold)
6848            .await?;
6849        patterns.extend(mixin_patterns);
6850
6851        // Abstract Base Class Pattern
6852        let abc_patterns = self
6853            .detect_abstract_base_class_pattern(server, confidence_threshold)
6854            .await?;
6855        patterns.extend(abc_patterns);
6856
6857        // Protocol/Interface Pattern (Duck Typing)
6858        let protocol_patterns = self
6859            .detect_protocol_pattern(server, confidence_threshold)
6860            .await?;
6861        patterns.extend(protocol_patterns);
6862
6863        Ok(patterns)
6864    }
6865
6866    /// Detect Registry Metaclass Pattern (like AgentMetaclass)
6867    async fn detect_registry_metaclass_pattern(
6868        &self,
6869        server: &CodePrismMcpServer,
6870        confidence_threshold: f64,
6871    ) -> Result<Vec<serde_json::Value>> {
6872        let mut patterns = Vec::new();
6873        let classes = server
6874            .graph_store()
6875            .get_nodes_by_kind(codeprism_core::NodeKind::Class);
6876
6877        for class in classes {
6878            // Check if class is a metaclass that implements registry pattern
6879            if let Ok(inheritance_info) = server.graph_query().get_inheritance_info(&class.id) {
6880                if inheritance_info.is_metaclass {
6881                    let mut confidence = 0.5; // Base confidence for being a metaclass
6882                    let mut indicators = vec!["Is a metaclass".to_string()];
6883
6884                    // Check for registry-like naming
6885                    if class.name.to_lowercase().contains("registry")
6886                        || class.name.to_lowercase().contains("manager")
6887                        || class.name.ends_with("Metaclass")
6888                    {
6889                        confidence += 0.2;
6890                        indicators.push("Registry-like naming pattern".to_string());
6891                    }
6892
6893                    // Check for classes that use this metaclass
6894                    let affected_classes = inheritance_info.subclasses.len();
6895                    if affected_classes > 2 {
6896                        confidence += 0.3;
6897                        indicators.push(format!("Used by {} classes", affected_classes));
6898                    }
6899
6900                    // Check for dynamic attributes that suggest registry behavior
6901                    if !inheritance_info.dynamic_attributes.is_empty() {
6902                        confidence += 0.2;
6903                        indicators.push(format!(
6904                            "{} dynamic attributes created",
6905                            inheritance_info.dynamic_attributes.len()
6906                        ));
6907                    }
6908
6909                    if confidence >= confidence_threshold {
6910                        patterns.push(serde_json::json!({
6911                            "type": "Registry Metaclass",
6912                            "category": "metaprogramming_pattern",
6913                            "confidence": confidence,
6914                            "metaclass": {
6915                                "id": class.id.to_hex(),
6916                                "name": class.name,
6917                                "file": class.file.display().to_string(),
6918                                "span": class.span
6919                            },
6920                            "affected_classes": affected_classes,
6921                            "dynamic_attributes": inheritance_info.dynamic_attributes,
6922                            "indicators": indicators,
6923                            "description": "Metaclass that automatically registers classes and injects functionality"
6924                        }));
6925                    }
6926                }
6927            }
6928        }
6929
6930        Ok(patterns)
6931    }
6932
6933    /// Detect Attribute Injection Metaclass Pattern
6934    async fn detect_attribute_injection_metaclass_pattern(
6935        &self,
6936        server: &CodePrismMcpServer,
6937        confidence_threshold: f64,
6938    ) -> Result<Vec<serde_json::Value>> {
6939        let mut patterns = Vec::new();
6940        let classes = server
6941            .graph_store()
6942            .get_nodes_by_kind(codeprism_core::NodeKind::Class);
6943
6944        for class in classes {
6945            if let Ok(inheritance_info) = server.graph_query().get_inheritance_info(&class.id) {
6946                if inheritance_info.is_metaclass && !inheritance_info.dynamic_attributes.is_empty()
6947                {
6948                    let dynamic_count = inheritance_info.dynamic_attributes.len();
6949                    let confidence = (dynamic_count as f64 / 10.0).min(1.0);
6950
6951                    if confidence >= confidence_threshold {
6952                        patterns.push(serde_json::json!({
6953                            "type": "Attribute Injection Metaclass",
6954                            "category": "metaprogramming_pattern",
6955                            "confidence": confidence,
6956                            "metaclass": {
6957                                "id": class.id.to_hex(),
6958                                "name": class.name,
6959                                "file": class.file.display().to_string(),
6960                                "span": class.span
6961                            },
6962                            "injected_attributes": inheritance_info.dynamic_attributes,
6963                            "indicators": [format!("Injects {} dynamic attributes", dynamic_count)],
6964                            "description": "Metaclass that automatically injects attributes into classes"
6965                        }));
6966                    }
6967                }
6968            }
6969        }
6970
6971        Ok(patterns)
6972    }
6973
6974    /// Detect Decorator Factory Pattern
6975    async fn detect_decorator_factory_pattern(
6976        &self,
6977        server: &CodePrismMcpServer,
6978        confidence_threshold: f64,
6979    ) -> Result<Vec<serde_json::Value>> {
6980        let mut patterns = Vec::new();
6981        let functions = server
6982            .graph_store()
6983            .get_nodes_by_kind(codeprism_core::NodeKind::Function);
6984
6985        for function in functions {
6986            let mut confidence = 0.0;
6987            let mut indicators = Vec::new();
6988
6989            // Check if function name suggests decorator factory
6990            let name_lower = function.name.to_lowercase();
6991            if name_lower.contains("decorator")
6992                || name_lower.ends_with("_decorator")
6993                || name_lower.starts_with("make_")
6994                || name_lower.contains("factory")
6995            {
6996                confidence += 0.4;
6997                indicators.push("Decorator-like naming pattern".to_string());
6998            }
6999
7000            // Check for nested function definitions (typical of decorator factories)
7001            // This is a simplified check - in real implementation we'd parse the AST
7002            if let Ok(content) = std::fs::read_to_string(&function.file) {
7003                let lines: Vec<&str> = content.lines().collect();
7004                let start_line = function.span.start_line.saturating_sub(1);
7005                let end_line = function.span.end_line.min(lines.len());
7006
7007                if start_line < end_line {
7008                    let function_content: String = lines[start_line..end_line].join("\n");
7009
7010                    // Look for nested def statements
7011                    let nested_defs = function_content.matches("def ").count();
7012                    if nested_defs > 1 {
7013                        confidence += 0.4;
7014                        indicators.push("Contains nested function definitions".to_string());
7015                    }
7016
7017                    // Look for return statements that return functions
7018                    if function_content.contains("return ")
7019                        && (function_content.contains("wrapper")
7020                            || function_content.contains("decorator"))
7021                    {
7022                        confidence += 0.3;
7023                        indicators.push("Returns wrapper function".to_string());
7024                    }
7025                }
7026            }
7027
7028            if confidence >= confidence_threshold {
7029                patterns.push(serde_json::json!({
7030                    "type": "Decorator Factory",
7031                    "category": "metaprogramming_pattern",
7032                    "confidence": confidence,
7033                    "function": {
7034                        "id": function.id.to_hex(),
7035                        "name": function.name,
7036                        "file": function.file.display().to_string(),
7037                        "span": function.span
7038                    },
7039                    "indicators": indicators,
7040                    "description": "Function that creates and returns decorators"
7041                }));
7042            }
7043        }
7044
7045        Ok(patterns)
7046    }
7047
7048    /// Detect Property Descriptor Pattern
7049    async fn detect_property_descriptor_pattern(
7050        &self,
7051        server: &CodePrismMcpServer,
7052        confidence_threshold: f64,
7053    ) -> Result<Vec<serde_json::Value>> {
7054        let mut patterns = Vec::new();
7055        let classes = server
7056            .graph_store()
7057            .get_nodes_by_kind(codeprism_core::NodeKind::Class);
7058
7059        for class in classes {
7060            let mut confidence = 0.0;
7061            let mut indicators = Vec::new();
7062            let mut descriptor_methods = Vec::new();
7063
7064            // Check for descriptor protocol methods
7065            let methods = server.graph_store().get_outgoing_edges(&class.id);
7066            for edge in methods {
7067                if let Some(method_node) = server.graph_store().get_node(&edge.target) {
7068                    if method_node.kind == codeprism_core::NodeKind::Method {
7069                        match method_node.name.as_str() {
7070                            "__get__" => {
7071                                confidence += 0.4;
7072                                descriptor_methods.push("__get__".to_string());
7073                            }
7074                            "__set__" => {
7075                                confidence += 0.3;
7076                                descriptor_methods.push("__set__".to_string());
7077                            }
7078                            "__delete__" => {
7079                                confidence += 0.2;
7080                                descriptor_methods.push("__delete__".to_string());
7081                            }
7082                            "__set_name__" => {
7083                                confidence += 0.2;
7084                                descriptor_methods.push("__set_name__".to_string());
7085                            }
7086                            _ => {}
7087                        }
7088                    }
7089                }
7090            }
7091
7092            if !descriptor_methods.is_empty() {
7093                indicators.push(format!(
7094                    "Implements descriptor methods: {}",
7095                    descriptor_methods.join(", ")
7096                ));
7097            }
7098
7099            // Check for property-like naming
7100            if class.name.to_lowercase().contains("property")
7101                || class.name.to_lowercase().contains("descriptor")
7102                || class.name.to_lowercase().contains("field")
7103            {
7104                confidence += 0.2;
7105                indicators.push("Property-like naming pattern".to_string());
7106            }
7107
7108            if confidence >= confidence_threshold {
7109                patterns.push(serde_json::json!({
7110                    "type": "Property Descriptor",
7111                    "category": "metaprogramming_pattern",
7112                    "confidence": confidence,
7113                    "class": {
7114                        "id": class.id.to_hex(),
7115                        "name": class.name,
7116                        "file": class.file.display().to_string(),
7117                        "span": class.span
7118                    },
7119                    "descriptor_methods": descriptor_methods,
7120                    "indicators": indicators,
7121                    "description": "Class implementing the descriptor protocol for managed attributes"
7122                }));
7123            }
7124        }
7125
7126        Ok(patterns)
7127    }
7128
7129    /// Detect Dynamic Attribute Pattern (__getattr__/__setattr__)
7130    async fn detect_dynamic_attribute_pattern(
7131        &self,
7132        server: &CodePrismMcpServer,
7133        confidence_threshold: f64,
7134    ) -> Result<Vec<serde_json::Value>> {
7135        let mut patterns = Vec::new();
7136        let classes = server
7137            .graph_store()
7138            .get_nodes_by_kind(codeprism_core::NodeKind::Class);
7139
7140        for class in classes {
7141            let mut confidence = 0.0;
7142            let mut indicators = Vec::new();
7143            let mut dynamic_methods = Vec::new();
7144
7145            // Check for dynamic attribute methods
7146            let methods = server.graph_store().get_outgoing_edges(&class.id);
7147            for edge in methods {
7148                if let Some(method_node) = server.graph_store().get_node(&edge.target) {
7149                    if method_node.kind == codeprism_core::NodeKind::Method {
7150                        match method_node.name.as_str() {
7151                            "__getattr__" => {
7152                                confidence += 0.4;
7153                                dynamic_methods.push("__getattr__".to_string());
7154                            }
7155                            "__setattr__" => {
7156                                confidence += 0.3;
7157                                dynamic_methods.push("__setattr__".to_string());
7158                            }
7159                            "__getattribute__" => {
7160                                confidence += 0.3;
7161                                dynamic_methods.push("__getattribute__".to_string());
7162                            }
7163                            "__delattr__" => {
7164                                confidence += 0.2;
7165                                dynamic_methods.push("__delattr__".to_string());
7166                            }
7167                            _ => {}
7168                        }
7169                    }
7170                }
7171            }
7172
7173            if !dynamic_methods.is_empty() {
7174                indicators.push(format!(
7175                    "Implements dynamic attribute methods: {}",
7176                    dynamic_methods.join(", ")
7177                ));
7178            }
7179
7180            // Check for proxy-like naming
7181            if class.name.to_lowercase().contains("proxy")
7182                || class.name.to_lowercase().contains("wrapper")
7183                || class.name.to_lowercase().contains("dynamic")
7184            {
7185                confidence += 0.2;
7186                indicators.push("Dynamic/proxy-like naming pattern".to_string());
7187            }
7188
7189            if confidence >= confidence_threshold {
7190                patterns.push(serde_json::json!({
7191                    "type": "Dynamic Attribute Pattern",
7192                    "category": "metaprogramming_pattern",
7193                    "confidence": confidence,
7194                    "class": {
7195                        "id": class.id.to_hex(),
7196                        "name": class.name,
7197                        "file": class.file.display().to_string(),
7198                        "span": class.span
7199                    },
7200                    "dynamic_methods": dynamic_methods,
7201                    "indicators": indicators,
7202                    "description": "Class with dynamic attribute access and manipulation"
7203                }));
7204            }
7205        }
7206
7207        Ok(patterns)
7208    }
7209
7210    /// Detect Mixin Pattern
7211    async fn detect_mixin_pattern(
7212        &self,
7213        server: &CodePrismMcpServer,
7214        confidence_threshold: f64,
7215    ) -> Result<Vec<serde_json::Value>> {
7216        let mut patterns = Vec::new();
7217        let classes = server
7218            .graph_store()
7219            .get_nodes_by_kind(codeprism_core::NodeKind::Class);
7220
7221        for class in classes {
7222            let mut confidence = 0.0;
7223            let mut indicators = Vec::new();
7224
7225            // Check for mixin naming convention
7226            if class.name.ends_with("Mixin") || class.name.to_lowercase().contains("mixin") {
7227                confidence += 0.6;
7228                indicators.push("Mixin naming convention".to_string());
7229            }
7230
7231            // Check if this class is used as a mixin by others
7232            if let Ok(inheritance_info) = server.graph_query().get_inheritance_info(&class.id) {
7233                let usage_count = inheritance_info.subclasses.len();
7234                if usage_count > 1 {
7235                    confidence += 0.3;
7236                    indicators.push(format!("Used by {} classes", usage_count));
7237                }
7238
7239                // Check if it has a small, focused set of methods (typical of mixins)
7240                let method_count = server
7241                    .graph_store()
7242                    .get_outgoing_edges(&class.id)
7243                    .iter()
7244                    .filter(|edge| {
7245                        if let Some(target_node) = server.graph_store().get_node(&edge.target) {
7246                            target_node.kind == codeprism_core::NodeKind::Method
7247                        } else {
7248                            false
7249                        }
7250                    })
7251                    .count();
7252
7253                if method_count > 0 && method_count <= 5 {
7254                    confidence += 0.2;
7255                    indicators.push(format!(
7256                        "Small focused interface ({} methods)",
7257                        method_count
7258                    ));
7259                }
7260            }
7261
7262            if confidence >= confidence_threshold {
7263                patterns.push(serde_json::json!({
7264                    "type": "Mixin Pattern",
7265                    "category": "metaprogramming_pattern",
7266                    "confidence": confidence,
7267                    "class": {
7268                        "id": class.id.to_hex(),
7269                        "name": class.name,
7270                        "file": class.file.display().to_string(),
7271                        "span": class.span
7272                    },
7273                    "indicators": indicators,
7274                    "description": "Class designed to be mixed into other classes to provide specific functionality"
7275                }));
7276            }
7277        }
7278
7279        Ok(patterns)
7280    }
7281
7282    /// Detect Abstract Base Class Pattern
7283    async fn detect_abstract_base_class_pattern(
7284        &self,
7285        server: &CodePrismMcpServer,
7286        confidence_threshold: f64,
7287    ) -> Result<Vec<serde_json::Value>> {
7288        let mut patterns = Vec::new();
7289        let classes = server
7290            .graph_store()
7291            .get_nodes_by_kind(codeprism_core::NodeKind::Class);
7292
7293        for class in classes {
7294            let mut confidence = 0.0;
7295            let mut indicators = Vec::new();
7296
7297            // Check for ABC naming patterns
7298            if class.name.starts_with("Abstract")
7299                || class.name.starts_with("Base")
7300                || class.name.ends_with("ABC")
7301                || class.name.ends_with("Base")
7302            {
7303                confidence += 0.4;
7304                indicators.push("Abstract/Base naming pattern".to_string());
7305            }
7306
7307            // Check if it has subclasses (typical of abstract base classes)
7308            if let Ok(inheritance_info) = server.graph_query().get_inheritance_info(&class.id) {
7309                let subclass_count = inheritance_info.subclasses.len();
7310                if subclass_count > 0 {
7311                    confidence += 0.4;
7312                    indicators.push(format!("Has {} subclasses", subclass_count));
7313                }
7314
7315                // Check for ABC inheritance
7316                if inheritance_info
7317                    .base_classes
7318                    .iter()
7319                    .any(|base| base.class_name == "ABC")
7320                {
7321                    confidence += 0.3;
7322                    indicators.push("Inherits from ABC".to_string());
7323                }
7324            }
7325
7326            // Check for abstract method indicators (methods that might raise NotImplementedError)
7327            let methods = server.graph_store().get_outgoing_edges(&class.id);
7328            let abstract_methods = methods
7329                .iter()
7330                .filter(|edge| {
7331                    if let Some(method_node) = server.graph_store().get_node(&edge.target) {
7332                        if method_node.kind == codeprism_core::NodeKind::Method {
7333                            // This is a simplified check - ideally we'd parse the method body
7334                            if let Ok(content) = std::fs::read_to_string(&method_node.file) {
7335                                let lines: Vec<&str> = content.lines().collect();
7336                                let start_line = method_node.span.start_line.saturating_sub(1);
7337                                let end_line = method_node.span.end_line.min(lines.len());
7338
7339                                if start_line < end_line {
7340                                    let method_content: String =
7341                                        lines[start_line..end_line].join("\n");
7342                                    return method_content.contains("NotImplementedError")
7343                                        || method_content.contains("@abstractmethod");
7344                                }
7345                            }
7346                        }
7347                    }
7348                    false
7349                })
7350                .count();
7351
7352            if abstract_methods > 0 {
7353                confidence += 0.3;
7354                indicators.push(format!("{} abstract methods", abstract_methods));
7355            }
7356
7357            if confidence >= confidence_threshold {
7358                patterns.push(serde_json::json!({
7359                    "type": "Abstract Base Class",
7360                    "category": "metaprogramming_pattern",
7361                    "confidence": confidence,
7362                    "class": {
7363                        "id": class.id.to_hex(),
7364                        "name": class.name,
7365                        "file": class.file.display().to_string(),
7366                        "span": class.span
7367                    },
7368                    "abstract_methods": abstract_methods,
7369                    "indicators": indicators,
7370                    "description": "Abstract base class defining interface for subclasses"
7371                }));
7372            }
7373        }
7374
7375        Ok(patterns)
7376    }
7377
7378    /// Detect Protocol/Interface Pattern (Duck Typing)
7379    async fn detect_protocol_pattern(
7380        &self,
7381        server: &CodePrismMcpServer,
7382        confidence_threshold: f64,
7383    ) -> Result<Vec<serde_json::Value>> {
7384        let mut patterns = Vec::new();
7385        let classes = server
7386            .graph_store()
7387            .get_nodes_by_kind(codeprism_core::NodeKind::Class);
7388
7389        for class in classes {
7390            let mut confidence = 0.0;
7391            let mut indicators = Vec::new();
7392
7393            // Check for Protocol naming patterns
7394            if class.name.ends_with("Protocol")
7395                || class.name.ends_with("Interface")
7396                || class.name.starts_with("I")
7397                    && class
7398                        .name
7399                        .chars()
7400                        .nth(1)
7401                        .map_or(false, |c| c.is_uppercase())
7402            {
7403                confidence += 0.5;
7404                indicators.push("Protocol/Interface naming pattern".to_string());
7405            }
7406
7407            // Check for Protocol inheritance (typing.Protocol)
7408            if let Ok(inheritance_info) = server.graph_query().get_inheritance_info(&class.id) {
7409                if inheritance_info
7410                    .base_classes
7411                    .iter()
7412                    .any(|base| base.class_name == "Protocol")
7413                {
7414                    confidence += 0.4;
7415                    indicators.push("Inherits from Protocol".to_string());
7416                }
7417            }
7418
7419            // Check for interface-like structure (methods without implementation)
7420            let methods = server.graph_store().get_outgoing_edges(&class.id);
7421            let method_count = methods
7422                .iter()
7423                .filter(|edge| {
7424                    if let Some(method_node) = server.graph_store().get_node(&edge.target) {
7425                        method_node.kind == codeprism_core::NodeKind::Method
7426                    } else {
7427                        false
7428                    }
7429                })
7430                .count();
7431
7432            // Protocol classes typically have methods but minimal implementation
7433            if method_count > 0 && method_count <= 10 {
7434                confidence += 0.2;
7435                indicators.push(format!("Defines {} interface methods", method_count));
7436            }
7437
7438            if confidence >= confidence_threshold {
7439                patterns.push(serde_json::json!({
7440                    "type": "Protocol/Interface",
7441                    "category": "metaprogramming_pattern",
7442                    "confidence": confidence,
7443                    "class": {
7444                        "id": class.id.to_hex(),
7445                        "name": class.name,
7446                        "file": class.file.display().to_string(),
7447                        "span": class.span
7448                    },
7449                    "method_count": method_count,
7450                    "indicators": indicators,
7451                    "description": "Protocol or interface defining expected behavior via duck typing"
7452                }));
7453            }
7454        }
7455
7456        Ok(patterns)
7457    }
7458
7459    /// Get improvement suggestions for a pattern type
7460    fn get_pattern_suggestions(&self, pattern_type: &str) -> Vec<String> {
7461        match pattern_type {
7462            "Singleton" => vec![
7463                "Consider using dependency injection instead of Singleton".to_string(),
7464                "Ensure thread safety in multi-threaded environments".to_string(),
7465                "Consider if global state is truly necessary".to_string(),
7466            ],
7467            "Factory" => vec![
7468                "Consider using abstract factory for families of objects".to_string(),
7469                "Ensure proper error handling in object creation".to_string(),
7470                "Document the creation strategies clearly".to_string(),
7471            ],
7472            "Observer" => vec![
7473                "Consider using weak references to prevent memory leaks".to_string(),
7474                "Implement proper error handling in notifications".to_string(),
7475                "Consider async notifications for heavy operations".to_string(),
7476            ],
7477            "God Class" => vec![
7478                "Split into smaller, focused classes".to_string(),
7479                "Apply Single Responsibility Principle".to_string(),
7480                "Extract related methods into separate classes".to_string(),
7481            ],
7482            "Long Method" => vec![
7483                "Break down into smaller, focused methods".to_string(),
7484                "Extract common logic into helper methods".to_string(),
7485                "Consider if the method has too many responsibilities".to_string(),
7486            ],
7487            "Registry Metaclass" => vec![
7488                "Document the registration behavior clearly".to_string(),
7489                "Consider thread safety for registry operations".to_string(),
7490                "Provide clear error messages for registration failures".to_string(),
7491                "Consider using class decorators as an alternative".to_string(),
7492            ],
7493            "Attribute Injection Metaclass" => vec![
7494                "Document all injected attributes".to_string(),
7495                "Avoid name conflicts with user-defined attributes".to_string(),
7496                "Consider using descriptors for complex attribute behavior".to_string(),
7497            ],
7498            "Decorator Factory" => vec![
7499                "Use functools.wraps to preserve function metadata".to_string(),
7500                "Document the decorator's behavior and parameters".to_string(),
7501                "Consider type hints for better IDE support".to_string(),
7502            ],
7503            "Property Descriptor" => vec![
7504                "Implement proper error handling in descriptor methods".to_string(),
7505                "Document the descriptor's behavior clearly".to_string(),
7506                "Consider using __set_name__ for better introspection".to_string(),
7507            ],
7508            "Dynamic Attribute Pattern" => vec![
7509                "Be careful with infinite recursion in __getattribute__".to_string(),
7510                "Document the dynamic attribute behavior".to_string(),
7511                "Consider performance implications of dynamic access".to_string(),
7512            ],
7513            "Mixin Pattern" => vec![
7514                "Keep mixins small and focused on single responsibility".to_string(),
7515                "Use clear naming conventions (e.g., SomethingMixin)".to_string(),
7516                "Document the expected interface and dependencies".to_string(),
7517            ],
7518            "Abstract Base Class" => vec![
7519                "Use @abstractmethod decorator for abstract methods".to_string(),
7520                "Document the contract that subclasses must implement".to_string(),
7521                "Consider using typing.Protocol for structural subtyping".to_string(),
7522            ],
7523            "Protocol/Interface" => vec![
7524                "Use typing.Protocol for static type checking".to_string(),
7525                "Document the expected behavior, not just signatures".to_string(),
7526                "Consider runtime checks if needed".to_string(),
7527            ],
7528            _ => vec!["No specific suggestions available".to_string()],
7529        }
7530    }
7531
7532    /// Build transitive dependencies map
7533    async fn build_transitive_dependencies(
7534        &self,
7535        server: &CodePrismMcpServer,
7536        start_node: &codeprism_core::NodeId,
7537        max_depth: usize,
7538        dependency_types: &[String],
7539    ) -> Result<Vec<serde_json::Value>> {
7540        let mut dependencies = Vec::new();
7541        let mut visited = std::collections::HashSet::new();
7542        let mut queue = std::collections::VecDeque::new();
7543
7544        queue.push_back((*start_node, 0));
7545        visited.insert(*start_node);
7546
7547        while let Some((current_node, depth)) = queue.pop_front() {
7548            if depth >= max_depth {
7549                continue;
7550            }
7551
7552            let edges = server.graph_store().get_outgoing_edges(&current_node);
7553            for edge in edges {
7554                // Filter by dependency types
7555                let include_edge = dependency_types.contains(&"all".to_string())
7556                    || dependency_types.iter().any(|dt| match dt.as_str() {
7557                        "calls" => edge.kind == codeprism_core::EdgeKind::Calls,
7558                        "imports" => edge.kind == codeprism_core::EdgeKind::Imports,
7559                        "reads" => edge.kind == codeprism_core::EdgeKind::Reads,
7560                        "writes" => edge.kind == codeprism_core::EdgeKind::Writes,
7561                        "extends" => edge.kind == codeprism_core::EdgeKind::Extends,
7562                        "implements" => edge.kind == codeprism_core::EdgeKind::Implements,
7563                        _ => false,
7564                    });
7565
7566                if include_edge {
7567                    if let Some(target_node) = server.graph_store().get_node(&edge.target) {
7568                        dependencies.push(serde_json::json!({
7569                            "source": {
7570                                "id": current_node.to_hex(),
7571                                "name": server.graph_store().get_node(&current_node)
7572                                    .map(|n| n.name.clone()).unwrap_or("unknown".to_string())
7573                            },
7574                            "target": {
7575                                "id": target_node.id.to_hex(),
7576                                "name": target_node.name,
7577                                "kind": format!("{:?}", target_node.kind),
7578                                "file": target_node.file.display().to_string()
7579                            },
7580                            "edge_type": format!("{:?}", edge.kind),
7581                            "depth": depth + 1
7582                        }));
7583
7584                        if !visited.contains(&edge.target) {
7585                            visited.insert(edge.target);
7586                            queue.push_back((edge.target, depth + 1));
7587                        }
7588                    }
7589                }
7590            }
7591        }
7592
7593        Ok(dependencies)
7594    }
7595
7596    /// Build dependency chains
7597    async fn build_dependency_chains(
7598        &self,
7599        server: &CodePrismMcpServer,
7600        start_node: &codeprism_core::NodeId,
7601        max_depth: usize,
7602    ) -> Result<Vec<serde_json::Value>> {
7603        let mut chains = Vec::new();
7604        let current_chain = Vec::new();
7605
7606        self.build_chains_recursive(
7607            server,
7608            *start_node,
7609            current_chain,
7610            &mut chains,
7611            max_depth,
7612            0,
7613        )
7614        .await?;
7615
7616        Ok(chains)
7617    }
7618
7619    /// Recursive helper for building dependency chains
7620    fn build_chains_recursive<'a>(
7621        &'a self,
7622        server: &'a CodePrismMcpServer,
7623        current_node: codeprism_core::NodeId,
7624        current_chain: Vec<String>,
7625        all_chains: &'a mut Vec<serde_json::Value>,
7626        max_depth: usize,
7627        current_depth: usize,
7628    ) -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<()>> + 'a>> {
7629        Box::pin(async move {
7630            if current_depth >= max_depth {
7631                return Ok(());
7632            }
7633
7634            let mut chain = current_chain;
7635            if let Some(node) = server.graph_store().get_node(&current_node) {
7636                chain.push(format!("{}:{}", node.name, node.id.to_hex()));
7637            }
7638
7639            let edges = server.graph_store().get_outgoing_edges(&current_node);
7640            if edges.is_empty() {
7641                // End of chain
7642                if chain.len() > 1 {
7643                    all_chains.push(serde_json::json!({
7644                        "chain": chain,
7645                        "length": chain.len()
7646                    }));
7647                }
7648            } else {
7649                for edge in edges {
7650                    if edge.kind == codeprism_core::EdgeKind::Calls
7651                        || edge.kind == codeprism_core::EdgeKind::Imports
7652                    {
7653                        self.build_chains_recursive(
7654                            server,
7655                            edge.target,
7656                            chain.clone(),
7657                            all_chains,
7658                            max_depth,
7659                            current_depth + 1,
7660                        )
7661                        .await?;
7662                    }
7663                }
7664            }
7665
7666            Ok(())
7667        })
7668    }
7669
7670    /// Detect dependency cycles
7671    async fn detect_dependency_cycles(
7672        &self,
7673        server: &CodePrismMcpServer,
7674        start_node: &codeprism_core::NodeId,
7675        _dependencies: &[serde_json::Value],
7676    ) -> Result<Vec<serde_json::Value>> {
7677        let mut cycles = Vec::new();
7678        let mut visited = std::collections::HashSet::new();
7679        let mut rec_stack = std::collections::HashSet::new();
7680        let mut path = Vec::new();
7681
7682        self.detect_cycles_dfs(
7683            server,
7684            *start_node,
7685            &mut visited,
7686            &mut rec_stack,
7687            &mut path,
7688            &mut cycles,
7689        )
7690        .await?;
7691
7692        Ok(cycles)
7693    }
7694
7695    /// DFS helper for cycle detection
7696    fn detect_cycles_dfs<'a>(
7697        &'a self,
7698        server: &'a CodePrismMcpServer,
7699        node: codeprism_core::NodeId,
7700        visited: &'a mut std::collections::HashSet<codeprism_core::NodeId>,
7701        rec_stack: &'a mut std::collections::HashSet<codeprism_core::NodeId>,
7702        path: &'a mut Vec<codeprism_core::NodeId>,
7703        cycles: &'a mut Vec<serde_json::Value>,
7704    ) -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<()>> + 'a>> {
7705        Box::pin(async move {
7706            visited.insert(node);
7707            rec_stack.insert(node);
7708            path.push(node);
7709
7710            let edges = server.graph_store().get_outgoing_edges(&node);
7711            for edge in edges {
7712                if edge.kind == codeprism_core::EdgeKind::Calls
7713                    || edge.kind == codeprism_core::EdgeKind::Imports
7714                {
7715                    if !visited.contains(&edge.target) {
7716                        self.detect_cycles_dfs(
7717                            server,
7718                            edge.target,
7719                            visited,
7720                            rec_stack,
7721                            path,
7722                            cycles,
7723                        )
7724                        .await?;
7725                    } else if rec_stack.contains(&edge.target) {
7726                        // Found a cycle
7727                        if let Some(cycle_start) = path.iter().position(|&id| id == edge.target) {
7728                            let cycle_path: Vec<String> = path[cycle_start..]
7729                                .iter()
7730                                .map(|id| {
7731                                    if let Some(node) = server.graph_store().get_node(id) {
7732                                        format!("{}:{}", node.name, id.to_hex())
7733                                    } else {
7734                                        id.to_hex()
7735                                    }
7736                                })
7737                                .collect();
7738
7739                            cycles.push(serde_json::json!({
7740                                "cycle_path": cycle_path,
7741                                "cycle_length": cycle_path.len(),
7742                                "cycle_type": "dependency_cycle"
7743                            }));
7744                        }
7745                    }
7746                }
7747            }
7748
7749            path.pop();
7750            rec_stack.remove(&node);
7751
7752            Ok(())
7753        })
7754    }
7755
7756    /// Calculate maximum depth in dependencies
7757    fn calculate_max_depth(&self, dependencies: &[serde_json::Value]) -> usize {
7758        dependencies
7759            .iter()
7760            .filter_map(|dep| dep.get("depth").and_then(|d| d.as_u64()))
7761            .max()
7762            .unwrap_or(0) as usize
7763    }
7764
7765    /// Count unique dependencies across all analyses
7766    fn count_unique_dependencies(&self, analyses: &[serde_json::Value]) -> usize {
7767        let mut unique_deps = std::collections::HashSet::new();
7768
7769        for analysis in analyses {
7770            if let Some(deps) = analysis
7771                .get("transitive_dependencies")
7772                .and_then(|d| d.as_array())
7773            {
7774                for dep in deps {
7775                    if let Some(target_id) = dep
7776                        .get("target")
7777                        .and_then(|t| t.get("id"))
7778                        .and_then(|id| id.as_str())
7779                    {
7780                        unique_deps.insert(target_id.to_string());
7781                    }
7782                }
7783            }
7784        }
7785
7786        unique_deps.len()
7787    }
7788
7789    /// Count total cycles across all analyses
7790    fn count_total_cycles(&self, analyses: &[serde_json::Value]) -> usize {
7791        analyses
7792            .iter()
7793            .map(|analysis| {
7794                analysis
7795                    .get("cycles")
7796                    .and_then(|c| c.as_array())
7797                    .map(|arr| arr.len())
7798                    .unwrap_or(0)
7799            })
7800            .sum()
7801    }
7802
7803    /// Perform data flow analysis on a symbol
7804    async fn perform_data_flow_analysis(
7805        &self,
7806        server: &CodePrismMcpServer,
7807        symbol_id: &codeprism_core::NodeId,
7808        direction: &str,
7809        include_transformations: bool,
7810        max_depth: usize,
7811        follow_function_calls: bool,
7812        include_field_access: bool,
7813    ) -> Result<serde_json::Value> {
7814        // Get the starting symbol
7815        let start_node = server
7816            .graph_store()
7817            .get_node(symbol_id)
7818            .ok_or_else(|| anyhow::anyhow!("Symbol not found: {}", symbol_id.to_hex()))?;
7819
7820        let mut data_flows = Vec::new();
7821        let mut visited = std::collections::HashSet::new();
7822
7823        match direction {
7824            "forward" => {
7825                self.trace_data_flow_forward(
7826                    server,
7827                    symbol_id,
7828                    &mut data_flows,
7829                    &mut visited,
7830                    0,
7831                    max_depth,
7832                    include_transformations,
7833                    follow_function_calls,
7834                    include_field_access,
7835                )
7836                .await?;
7837            }
7838            "backward" => {
7839                self.trace_data_flow_backward(
7840                    server,
7841                    symbol_id,
7842                    &mut data_flows,
7843                    &mut visited,
7844                    0,
7845                    max_depth,
7846                    include_transformations,
7847                    follow_function_calls,
7848                    include_field_access,
7849                )
7850                .await?;
7851            }
7852            "both" => {
7853                let mut forward_flows = Vec::new();
7854                let mut backward_flows = Vec::new();
7855                let mut forward_visited = std::collections::HashSet::new();
7856                let mut backward_visited = std::collections::HashSet::new();
7857
7858                self.trace_data_flow_forward(
7859                    server,
7860                    symbol_id,
7861                    &mut forward_flows,
7862                    &mut forward_visited,
7863                    0,
7864                    max_depth,
7865                    include_transformations,
7866                    follow_function_calls,
7867                    include_field_access,
7868                )
7869                .await?;
7870
7871                self.trace_data_flow_backward(
7872                    server,
7873                    symbol_id,
7874                    &mut backward_flows,
7875                    &mut backward_visited,
7876                    0,
7877                    max_depth,
7878                    include_transformations,
7879                    follow_function_calls,
7880                    include_field_access,
7881                )
7882                .await?;
7883
7884                return Ok(serde_json::json!({
7885                    "starting_symbol": {
7886                        "id": start_node.id.to_hex(),
7887                        "name": start_node.name,
7888                        "kind": format!("{:?}", start_node.kind),
7889                        "file": start_node.file.display().to_string(),
7890                        "location": {
7891                            "line": start_node.span.start_line,
7892                            "column": start_node.span.start_column
7893                        }
7894                    },
7895                    "direction": direction,
7896                    "forward_flows": forward_flows,
7897                    "backward_flows": backward_flows,
7898                    "summary": {
7899                        "total_forward_flows": forward_flows.len(),
7900                        "total_backward_flows": backward_flows.len(),
7901                        "max_depth_reached": max_depth,
7902                        "unique_symbols_forward": forward_visited.len(),
7903                        "unique_symbols_backward": backward_visited.len()
7904                    },
7905                    "parameters": {
7906                        "include_transformations": include_transformations,
7907                        "follow_function_calls": follow_function_calls,
7908                        "include_field_access": include_field_access,
7909                        "max_depth": max_depth
7910                    }
7911                }));
7912            }
7913            _ => {
7914                return Err(anyhow::anyhow!(
7915                    "Invalid direction: {}. Must be 'forward', 'backward', or 'both'",
7916                    direction
7917                ));
7918            }
7919        }
7920
7921        Ok(serde_json::json!({
7922            "starting_symbol": {
7923                "id": start_node.id.to_hex(),
7924                "name": start_node.name,
7925                "kind": format!("{:?}", start_node.kind),
7926                "file": start_node.file.display().to_string(),
7927                "location": {
7928                    "line": start_node.span.start_line,
7929                    "column": start_node.span.start_column
7930                }
7931            },
7932            "direction": direction,
7933            "data_flows": data_flows,
7934            "summary": {
7935                "total_flows": data_flows.len(),
7936                "max_depth_reached": max_depth,
7937                "unique_symbols": visited.len()
7938            },
7939            "parameters": {
7940                "include_transformations": include_transformations,
7941                "follow_function_calls": follow_function_calls,
7942                "include_field_access": include_field_access,
7943                "max_depth": max_depth
7944            }
7945        }))
7946    }
7947
7948    /// Trace data flow in forward direction
7949    fn trace_data_flow_forward<'a>(
7950        &'a self,
7951        server: &'a CodePrismMcpServer,
7952        symbol_id: &'a codeprism_core::NodeId,
7953        data_flows: &'a mut Vec<serde_json::Value>,
7954        visited: &'a mut std::collections::HashSet<codeprism_core::NodeId>,
7955        current_depth: usize,
7956        max_depth: usize,
7957        include_transformations: bool,
7958        follow_function_calls: bool,
7959        include_field_access: bool,
7960    ) -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<()>> + 'a>> {
7961        Box::pin(async move {
7962            if current_depth >= max_depth || visited.contains(symbol_id) {
7963                return Ok(());
7964            }
7965
7966            visited.insert(*symbol_id);
7967
7968            let current_node = server
7969                .graph_store()
7970                .get_node(symbol_id)
7971                .ok_or_else(|| anyhow::anyhow!("Node not found: {}", symbol_id.to_hex()))?;
7972
7973            // Find all reads from this symbol (data flowing out)
7974            let dependencies = server
7975                .graph_query()
7976                .find_dependencies(symbol_id, codeprism_core::graph::DependencyType::Reads)?;
7977
7978            for dep in dependencies
7979                .iter()
7980                .filter(|d| self.is_valid_dependency_node(&d.target_node))
7981            {
7982                let flow_info = serde_json::json!({
7983                    "flow_type": "read",
7984                    "depth": current_depth,
7985                    "source": {
7986                        "id": current_node.id.to_hex(),
7987                        "name": current_node.name,
7988                        "kind": format!("{:?}", current_node.kind),
7989                        "file": current_node.file.display().to_string(),
7990                        "location": {
7991                            "line": current_node.span.start_line,
7992                            "column": current_node.span.start_column
7993                        }
7994                    },
7995                    "target": {
7996                        "id": dep.target_node.id.to_hex(),
7997                        "name": dep.target_node.name,
7998                        "kind": format!("{:?}", dep.target_node.kind),
7999                        "file": dep.target_node.file.display().to_string(),
8000                        "location": {
8001                            "line": dep.target_node.span.start_line,
8002                            "column": dep.target_node.span.start_column
8003                        }
8004                    },
8005                    "edge_kind": format!("{:?}", dep.edge_kind)
8006                });
8007                data_flows.push(flow_info);
8008
8009                // Continue tracing from the target
8010                self.trace_data_flow_forward(
8011                    server,
8012                    &dep.target_node.id,
8013                    data_flows,
8014                    visited,
8015                    current_depth + 1,
8016                    max_depth,
8017                    include_transformations,
8018                    follow_function_calls,
8019                    include_field_access,
8020                )
8021                .await?;
8022            }
8023
8024            // If following function calls, trace through function parameters and returns
8025            if follow_function_calls {
8026                let call_dependencies = server
8027                    .graph_query()
8028                    .find_dependencies(symbol_id, codeprism_core::graph::DependencyType::Calls)?;
8029
8030                for dep in call_dependencies
8031                    .iter()
8032                    .filter(|d| self.is_valid_dependency_node(&d.target_node))
8033                {
8034                    let flow_info = serde_json::json!({
8035                        "flow_type": "function_call",
8036                        "depth": current_depth,
8037                        "source": {
8038                            "id": current_node.id.to_hex(),
8039                            "name": current_node.name,
8040                            "kind": format!("{:?}", current_node.kind),
8041                            "file": current_node.file.display().to_string(),
8042                            "location": {
8043                                "line": current_node.span.start_line,
8044                                "column": current_node.span.start_column
8045                            }
8046                        },
8047                        "target": {
8048                            "id": dep.target_node.id.to_hex(),
8049                            "name": dep.target_node.name,
8050                            "kind": format!("{:?}", dep.target_node.kind),
8051                            "file": dep.target_node.file.display().to_string(),
8052                            "location": {
8053                                "line": dep.target_node.span.start_line,
8054                                "column": dep.target_node.span.start_column
8055                            }
8056                        },
8057                        "edge_kind": format!("{:?}", dep.edge_kind)
8058                    });
8059                    data_flows.push(flow_info);
8060
8061                    // Continue tracing into the function
8062                    self.trace_data_flow_forward(
8063                        server,
8064                        &dep.target_node.id,
8065                        data_flows,
8066                        visited,
8067                        current_depth + 1,
8068                        max_depth,
8069                        include_transformations,
8070                        follow_function_calls,
8071                        include_field_access,
8072                    )
8073                    .await?;
8074                }
8075            }
8076
8077            Ok(())
8078        })
8079    }
8080
8081    /// Trace data flow in backward direction
8082    fn trace_data_flow_backward<'a>(
8083        &'a self,
8084        server: &'a CodePrismMcpServer,
8085        symbol_id: &'a codeprism_core::NodeId,
8086        data_flows: &'a mut Vec<serde_json::Value>,
8087        visited: &'a mut std::collections::HashSet<codeprism_core::NodeId>,
8088        current_depth: usize,
8089        max_depth: usize,
8090        include_transformations: bool,
8091        follow_function_calls: bool,
8092        include_field_access: bool,
8093    ) -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<()>> + 'a>> {
8094        Box::pin(async move {
8095            if current_depth >= max_depth || visited.contains(symbol_id) {
8096                return Ok(());
8097            }
8098
8099            visited.insert(*symbol_id);
8100
8101            let current_node = server
8102                .graph_store()
8103                .get_node(symbol_id)
8104                .ok_or_else(|| anyhow::anyhow!("Node not found: {}", symbol_id.to_hex()))?;
8105
8106            // Find all writes to this symbol (data flowing in)
8107            let references = server.graph_query().find_references(symbol_id)?;
8108
8109            for ref_info in references.iter() {
8110                // Filter for write operations
8111                if matches!(ref_info.edge_kind, codeprism_core::EdgeKind::Writes) {
8112                    let flow_info = serde_json::json!({
8113                        "flow_type": "write",
8114                        "depth": current_depth,
8115                        "source": {
8116                            "id": ref_info.source_node.id.to_hex(),
8117                            "name": ref_info.source_node.name,
8118                            "kind": format!("{:?}", ref_info.source_node.kind),
8119                            "file": ref_info.source_node.file.display().to_string(),
8120                            "location": {
8121                                "line": ref_info.source_node.span.start_line,
8122                                "column": ref_info.source_node.span.start_column
8123                            }
8124                        },
8125                        "target": {
8126                            "id": current_node.id.to_hex(),
8127                            "name": current_node.name,
8128                            "kind": format!("{:?}", current_node.kind),
8129                            "file": current_node.file.display().to_string(),
8130                            "location": {
8131                                "line": current_node.span.start_line,
8132                                "column": current_node.span.start_column
8133                            }
8134                        },
8135                        "edge_kind": format!("{:?}", ref_info.edge_kind)
8136                    });
8137                    data_flows.push(flow_info);
8138
8139                    // Continue tracing from the source
8140                    self.trace_data_flow_backward(
8141                        server,
8142                        &ref_info.source_node.id,
8143                        data_flows,
8144                        visited,
8145                        current_depth + 1,
8146                        max_depth,
8147                        include_transformations,
8148                        follow_function_calls,
8149                        include_field_access,
8150                    )
8151                    .await?;
8152                }
8153            }
8154
8155            // If following function calls, trace backward through function parameters
8156            if follow_function_calls {
8157                for ref_info in references.iter() {
8158                    if matches!(ref_info.edge_kind, codeprism_core::EdgeKind::Calls) {
8159                        let flow_info = serde_json::json!({
8160                            "flow_type": "function_parameter",
8161                            "depth": current_depth,
8162                            "source": {
8163                                "id": ref_info.source_node.id.to_hex(),
8164                                "name": ref_info.source_node.name,
8165                                "kind": format!("{:?}", ref_info.source_node.kind),
8166                                "file": ref_info.source_node.file.display().to_string(),
8167                                "location": {
8168                                    "line": ref_info.source_node.span.start_line,
8169                                    "column": ref_info.source_node.span.start_column
8170                                }
8171                            },
8172                            "target": {
8173                                "id": current_node.id.to_hex(),
8174                                "name": current_node.name,
8175                                "kind": format!("{:?}", current_node.kind),
8176                                "file": current_node.file.display().to_string(),
8177                                "location": {
8178                                    "line": current_node.span.start_line,
8179                                    "column": current_node.span.start_column
8180                                }
8181                            },
8182                            "edge_kind": format!("{:?}", ref_info.edge_kind)
8183                        });
8184                        data_flows.push(flow_info);
8185
8186                        // Continue tracing backward from the caller
8187                        self.trace_data_flow_backward(
8188                            server,
8189                            &ref_info.source_node.id,
8190                            data_flows,
8191                            visited,
8192                            current_depth + 1,
8193                            max_depth,
8194                            include_transformations,
8195                            follow_function_calls,
8196                            include_field_access,
8197                        )
8198                        .await?;
8199                    }
8200                }
8201            }
8202
8203            Ok(())
8204        })
8205    }
8206
8207    /// Perform unused code analysis
8208    async fn perform_unused_code_analysis(
8209        &self,
8210        server: &CodePrismMcpServer,
8211        scope: &str,
8212        include_dead_code: bool,
8213        consider_external_apis: bool,
8214        confidence_threshold: f64,
8215        analyze_types: &[String],
8216        exclude_patterns: &[String],
8217    ) -> Result<serde_json::Value> {
8218        let mut unused_functions = Vec::new();
8219        let mut unused_classes = Vec::new();
8220        let mut unused_variables = Vec::new();
8221        let mut unused_imports = Vec::new();
8222        let mut dead_code_blocks = Vec::new();
8223
8224        // Analyze different types of code elements based on the request
8225        if analyze_types.contains(&"functions".to_string())
8226            || analyze_types.contains(&"all".to_string())
8227        {
8228            unused_functions = self
8229                .find_unused_functions(
8230                    server,
8231                    confidence_threshold,
8232                    consider_external_apis,
8233                    exclude_patterns,
8234                )
8235                .await?;
8236        }
8237
8238        if analyze_types.contains(&"classes".to_string())
8239            || analyze_types.contains(&"all".to_string())
8240        {
8241            unused_classes = self
8242                .find_unused_classes(
8243                    server,
8244                    confidence_threshold,
8245                    consider_external_apis,
8246                    exclude_patterns,
8247                )
8248                .await?;
8249        }
8250
8251        if analyze_types.contains(&"variables".to_string())
8252            || analyze_types.contains(&"all".to_string())
8253        {
8254            unused_variables = self
8255                .find_unused_variables(server, confidence_threshold, exclude_patterns)
8256                .await?;
8257        }
8258
8259        if analyze_types.contains(&"imports".to_string())
8260            || analyze_types.contains(&"all".to_string())
8261        {
8262            unused_imports = self
8263                .find_unused_imports(server, confidence_threshold, exclude_patterns)
8264                .await?;
8265        }
8266
8267        if include_dead_code {
8268            dead_code_blocks = self
8269                .find_dead_code_blocks(server, confidence_threshold, exclude_patterns)
8270                .await?;
8271        }
8272
8273        Ok(serde_json::json!({
8274            "scope": scope,
8275            "analysis_parameters": {
8276                "include_dead_code": include_dead_code,
8277                "consider_external_apis": consider_external_apis,
8278                "confidence_threshold": confidence_threshold,
8279                "analyze_types": analyze_types
8280            },
8281            "unused_code": {
8282                "functions": unused_functions,
8283                "classes": unused_classes,
8284                "variables": unused_variables,
8285                "imports": unused_imports,
8286                "dead_code_blocks": dead_code_blocks
8287            },
8288            "summary": {
8289                "total_unused_functions": unused_functions.len(),
8290                "total_unused_classes": unused_classes.len(),
8291                "total_unused_variables": unused_variables.len(),
8292                "total_unused_imports": unused_imports.len(),
8293                "total_dead_code_blocks": dead_code_blocks.len(),
8294                "total_unused_elements": unused_functions.len() + unused_classes.len() + unused_variables.len() + unused_imports.len() + dead_code_blocks.len()
8295            },
8296            "recommendations": self.get_unused_code_recommendations(&unused_functions, &unused_classes, &unused_variables, &unused_imports, &dead_code_blocks)
8297        }))
8298    }
8299
8300    /// Find unused functions
8301    async fn find_unused_functions(
8302        &self,
8303        server: &CodePrismMcpServer,
8304        confidence_threshold: f64,
8305        consider_external_apis: bool,
8306        exclude_patterns: &[String],
8307    ) -> Result<Vec<serde_json::Value>> {
8308        let mut unused_functions = Vec::new();
8309        let functions = server
8310            .graph_store()
8311            .get_nodes_by_kind(codeprism_core::NodeKind::Function);
8312
8313        for function in functions {
8314            // Skip if matches exclude patterns
8315            if exclude_patterns
8316                .iter()
8317                .any(|pattern| function.file.to_string_lossy().contains(pattern))
8318            {
8319                continue;
8320            }
8321
8322            let references = server.graph_query().find_references(&function.id)?;
8323            let mut confidence = 1.0;
8324            let mut usage_indicators = Vec::new();
8325
8326            // Check for direct references (calls)
8327            let call_count = references
8328                .iter()
8329                .filter(|r| matches!(r.edge_kind, codeprism_core::EdgeKind::Calls))
8330                .count();
8331
8332            if call_count == 0 {
8333                usage_indicators.push("No direct function calls found".to_string());
8334            } else {
8335                confidence -= (call_count as f64 * 0.3).min(0.8);
8336                usage_indicators.push(format!("{} function calls found", call_count));
8337            }
8338
8339            // Consider potential external API usage
8340            if consider_external_apis {
8341                let function_name = &function.name;
8342
8343                // Check for common external API patterns
8344                if function_name.starts_with("main")
8345                    || function_name.starts_with("__")
8346                    || function_name.contains("handler")
8347                    || function_name.contains("callback")
8348                    || function_name.contains("api")
8349                    || function_name.contains("endpoint")
8350                {
8351                    confidence -= 0.5;
8352                    usage_indicators.push("Potentially used by external API".to_string());
8353                }
8354            }
8355
8356            // Check if it's exported/public
8357            if function.name.starts_with('_') {
8358                // Private function, less likely to be external API
8359                confidence += 0.1;
8360                usage_indicators.push("Private function (name starts with _)".to_string());
8361            }
8362
8363            if confidence >= confidence_threshold {
8364                unused_functions.push(serde_json::json!({
8365                    "id": function.id.to_hex(),
8366                    "name": function.name,
8367                    "kind": "Function",
8368                    "file": function.file.display().to_string(),
8369                    "location": {
8370                        "start_line": function.span.start_line,
8371                        "end_line": function.span.end_line,
8372                        "start_column": function.span.start_column,
8373                        "end_column": function.span.end_column
8374                    },
8375                    "confidence": confidence,
8376                    "usage_indicators": usage_indicators,
8377                    "lines_of_code": function.span.end_line - function.span.start_line + 1,
8378                    "potential_savings": "Remove function to reduce codebase size"
8379                }));
8380            }
8381        }
8382
8383        Ok(unused_functions)
8384    }
8385
8386    /// Find unused classes
8387    async fn find_unused_classes(
8388        &self,
8389        server: &CodePrismMcpServer,
8390        confidence_threshold: f64,
8391        consider_external_apis: bool,
8392        exclude_patterns: &[String],
8393    ) -> Result<Vec<serde_json::Value>> {
8394        let mut unused_classes = Vec::new();
8395        let classes = server
8396            .graph_store()
8397            .get_nodes_by_kind(codeprism_core::NodeKind::Class);
8398
8399        for class in classes {
8400            // Skip if matches exclude patterns
8401            if exclude_patterns
8402                .iter()
8403                .any(|pattern| class.file.to_string_lossy().contains(pattern))
8404            {
8405                continue;
8406            }
8407
8408            let references = server.graph_query().find_references(&class.id)?;
8409            let mut confidence = 1.0;
8410            let mut usage_indicators = Vec::new();
8411
8412            // Check for instantiation or inheritance
8413            let usage_count = references
8414                .iter()
8415                .filter(|r| {
8416                    matches!(
8417                        r.edge_kind,
8418                        codeprism_core::EdgeKind::Calls
8419                            | codeprism_core::EdgeKind::Extends
8420                            | codeprism_core::EdgeKind::Implements
8421                    )
8422                })
8423                .count();
8424
8425            if usage_count == 0 {
8426                usage_indicators
8427                    .push("No instantiation, inheritance, or implementation found".to_string());
8428            } else {
8429                confidence -= (usage_count as f64 * 0.4).min(0.9);
8430                usage_indicators.push(format!(
8431                    "{} usages found (instantiation/inheritance)",
8432                    usage_count
8433                ));
8434            }
8435
8436            // Consider external API patterns for classes
8437            if consider_external_apis {
8438                let class_name = &class.name;
8439
8440                if class_name.contains("Controller")
8441                    || class_name.contains("Service")
8442                    || class_name.contains("Handler")
8443                    || class_name.contains("Model")
8444                    || class_name.contains("Entity")
8445                    || class_name.contains("Exception")
8446                    || class_name.contains("Error")
8447                {
8448                    confidence -= 0.4;
8449                    usage_indicators
8450                        .push("Potentially used by framework or external system".to_string());
8451                }
8452            }
8453
8454            if confidence >= confidence_threshold {
8455                unused_classes.push(serde_json::json!({
8456                    "id": class.id.to_hex(),
8457                    "name": class.name,
8458                    "kind": "Class",
8459                    "file": class.file.display().to_string(),
8460                    "location": {
8461                        "start_line": class.span.start_line,
8462                        "end_line": class.span.end_line,
8463                        "start_column": class.span.start_column,
8464                        "end_column": class.span.end_column
8465                    },
8466                    "confidence": confidence,
8467                    "usage_indicators": usage_indicators,
8468                    "lines_of_code": class.span.end_line - class.span.start_line + 1,
8469                    "potential_savings": "Remove class and its methods to reduce codebase complexity"
8470                }));
8471            }
8472        }
8473
8474        Ok(unused_classes)
8475    }
8476
8477    /// Find unused variables
8478    async fn find_unused_variables(
8479        &self,
8480        server: &CodePrismMcpServer,
8481        confidence_threshold: f64,
8482        exclude_patterns: &[String],
8483    ) -> Result<Vec<serde_json::Value>> {
8484        let mut unused_variables = Vec::new();
8485        let variables = server
8486            .graph_store()
8487            .get_nodes_by_kind(codeprism_core::NodeKind::Variable);
8488
8489        for variable in variables {
8490            // Skip if matches exclude patterns
8491            if exclude_patterns
8492                .iter()
8493                .any(|pattern| variable.file.to_string_lossy().contains(pattern))
8494            {
8495                continue;
8496            }
8497
8498            let references = server.graph_query().find_references(&variable.id)?;
8499            let mut confidence = 1.0;
8500            let mut usage_indicators = Vec::new();
8501
8502            // Check for reads (excluding the definition itself)
8503            let read_count = references
8504                .iter()
8505                .filter(|r| matches!(r.edge_kind, codeprism_core::EdgeKind::Reads))
8506                .count();
8507
8508            if read_count == 0 {
8509                usage_indicators.push("No reads found".to_string());
8510            } else {
8511                confidence -= (read_count as f64 * 0.5).min(0.9);
8512                usage_indicators.push(format!("{} reads found", read_count));
8513            }
8514
8515            // Check for writes (assignments)
8516            let write_count = references
8517                .iter()
8518                .filter(|r| matches!(r.edge_kind, codeprism_core::EdgeKind::Writes))
8519                .count();
8520
8521            if write_count <= 1 {
8522                // Only the initial assignment
8523                usage_indicators.push("Only initial assignment found".to_string());
8524            } else {
8525                confidence -= (write_count as f64 * 0.3).min(0.6);
8526                usage_indicators.push(format!("{} assignments found", write_count));
8527            }
8528
8529            // Consider variable naming patterns
8530            if variable.name.starts_with('_') {
8531                usage_indicators.push("Private variable (name starts with _)".to_string());
8532            }
8533
8534            if confidence >= confidence_threshold {
8535                unused_variables.push(serde_json::json!({
8536                    "id": variable.id.to_hex(),
8537                    "name": variable.name,
8538                    "kind": "Variable",
8539                    "file": variable.file.display().to_string(),
8540                    "location": {
8541                        "start_line": variable.span.start_line,
8542                        "end_line": variable.span.end_line,
8543                        "start_column": variable.span.start_column,
8544                        "end_column": variable.span.end_column
8545                    },
8546                    "confidence": confidence,
8547                    "usage_indicators": usage_indicators,
8548                    "potential_savings": "Remove variable declaration and related code"
8549                }));
8550            }
8551        }
8552
8553        Ok(unused_variables)
8554    }
8555
8556    /// Find unused imports
8557    async fn find_unused_imports(
8558        &self,
8559        server: &CodePrismMcpServer,
8560        confidence_threshold: f64,
8561        exclude_patterns: &[String],
8562    ) -> Result<Vec<serde_json::Value>> {
8563        let mut unused_imports = Vec::new();
8564
8565        // Find all import edges by checking all node types
8566        let mut import_edges = Vec::new();
8567
8568        // Check all major node types for import edges
8569        let node_kinds = [
8570            codeprism_core::NodeKind::Function,
8571            codeprism_core::NodeKind::Class,
8572            codeprism_core::NodeKind::Module,
8573            codeprism_core::NodeKind::Variable,
8574        ];
8575
8576        for kind in &node_kinds {
8577            let nodes = server.graph_store().get_nodes_by_kind(*kind);
8578            for node in nodes {
8579                let edges = server.graph_store().get_outgoing_edges(&node.id);
8580                import_edges.extend(
8581                    edges
8582                        .into_iter()
8583                        .filter(|edge| edge.kind == codeprism_core::EdgeKind::Imports),
8584                );
8585            }
8586        }
8587
8588        for edge in import_edges {
8589            if let (Some(source_node), Some(target_node)) = (
8590                server.graph_store().get_node(&edge.source),
8591                server.graph_store().get_node(&edge.target),
8592            ) {
8593                // Skip if matches exclude patterns
8594                if exclude_patterns
8595                    .iter()
8596                    .any(|pattern| source_node.file.to_string_lossy().contains(pattern))
8597                {
8598                    continue;
8599                }
8600
8601                // Check if the imported symbol is actually used
8602                let target_references = server.graph_query().find_references(&target_node.id)?;
8603                let mut confidence = 1.0;
8604                let mut usage_indicators = Vec::new();
8605
8606                // Count non-import references (actual usage)
8607                let usage_count = target_references
8608                    .iter()
8609                    .filter(|r| !matches!(r.edge_kind, codeprism_core::EdgeKind::Imports))
8610                    .count();
8611
8612                if usage_count == 0 {
8613                    usage_indicators.push("Import not used in code".to_string());
8614                } else {
8615                    confidence -= (usage_count as f64 * 0.6).min(0.9);
8616                    usage_indicators.push(format!("{} usages found", usage_count));
8617                }
8618
8619                if confidence >= confidence_threshold {
8620                    unused_imports.push(serde_json::json!({
8621                        "import_source_id": source_node.id.to_hex(),
8622                        "import_target_id": target_node.id.to_hex(),
8623                        "imported_name": target_node.name,
8624                        "kind": "Import",
8625                        "file": source_node.file.display().to_string(),
8626                        "location": {
8627                            "start_line": source_node.span.start_line,
8628                            "end_line": source_node.span.end_line,
8629                            "start_column": source_node.span.start_column,
8630                            "end_column": source_node.span.end_column
8631                        },
8632                        "confidence": confidence,
8633                        "usage_indicators": usage_indicators,
8634                        "potential_savings": "Remove unused import to clean up code"
8635                    }));
8636                }
8637            }
8638        }
8639
8640        Ok(unused_imports)
8641    }
8642
8643    /// Find dead code blocks (unreachable code)
8644    async fn find_dead_code_blocks(
8645        &self,
8646        server: &CodePrismMcpServer,
8647        confidence_threshold: f64,
8648        exclude_patterns: &[String],
8649    ) -> Result<Vec<serde_json::Value>> {
8650        let mut dead_code_blocks = Vec::new();
8651
8652        // Find functions that are never called and not entry points
8653        let functions = server
8654            .graph_store()
8655            .get_nodes_by_kind(codeprism_core::NodeKind::Function);
8656
8657        for function in functions {
8658            // Skip if matches exclude patterns
8659            if exclude_patterns
8660                .iter()
8661                .any(|pattern| function.file.to_string_lossy().contains(pattern))
8662            {
8663                continue;
8664            }
8665
8666            // Skip main functions and special methods
8667            if function.name == "main"
8668                || function.name.starts_with("__")
8669                || function.name.starts_with("test_")
8670                || function.name.contains("init")
8671            {
8672                continue;
8673            }
8674
8675            let references = server.graph_query().find_references(&function.id)?;
8676            let call_count = references
8677                .iter()
8678                .filter(|r| matches!(r.edge_kind, codeprism_core::EdgeKind::Calls))
8679                .count();
8680
8681            if call_count == 0 {
8682                let confidence = 0.95; // High confidence for unreachable functions
8683
8684                if confidence >= confidence_threshold {
8685                    dead_code_blocks.push(serde_json::json!({
8686                        "id": function.id.to_hex(),
8687                        "name": function.name,
8688                        "kind": "Dead Function",
8689                        "file": function.file.display().to_string(),
8690                        "location": {
8691                            "start_line": function.span.start_line,
8692                            "end_line": function.span.end_line,
8693                            "start_column": function.span.start_column,
8694                            "end_column": function.span.end_column
8695                        },
8696                        "confidence": confidence,
8697                        "description": "Function is never called and appears to be unreachable",
8698                        "lines_of_code": function.span.end_line - function.span.start_line + 1,
8699                        "potential_savings": "Remove dead function to reduce codebase size and maintenance burden"
8700                    }));
8701                }
8702            }
8703        }
8704
8705        Ok(dead_code_blocks)
8706    }
8707
8708    /// Get recommendations for unused code cleanup
8709    fn get_unused_code_recommendations(
8710        &self,
8711        unused_functions: &[serde_json::Value],
8712        unused_classes: &[serde_json::Value],
8713        unused_variables: &[serde_json::Value],
8714        unused_imports: &[serde_json::Value],
8715        dead_code_blocks: &[serde_json::Value],
8716    ) -> Vec<String> {
8717        let mut recommendations = Vec::new();
8718
8719        if !unused_imports.is_empty() {
8720            recommendations.push(format!(
8721                "Remove {} unused imports to clean up dependencies",
8722                unused_imports.len()
8723            ));
8724        }
8725
8726        if !unused_variables.is_empty() {
8727            recommendations.push(format!(
8728                "Remove {} unused variables to reduce code clutter",
8729                unused_variables.len()
8730            ));
8731        }
8732
8733        if !unused_functions.is_empty() {
8734            let lines_saved: usize = unused_functions
8735                .iter()
8736                .filter_map(|f| f.get("lines_of_code").and_then(|v| v.as_u64()))
8737                .map(|v| v as usize)
8738                .sum();
8739            recommendations.push(format!(
8740                "Remove {} unused functions to save approximately {} lines of code",
8741                unused_functions.len(),
8742                lines_saved
8743            ));
8744        }
8745
8746        if !unused_classes.is_empty() {
8747            let lines_saved: usize = unused_classes
8748                .iter()
8749                .filter_map(|c| c.get("lines_of_code").and_then(|v| v.as_u64()))
8750                .map(|v| v as usize)
8751                .sum();
8752            recommendations.push(format!(
8753                "Remove {} unused classes to save approximately {} lines of code",
8754                unused_classes.len(),
8755                lines_saved
8756            ));
8757        }
8758
8759        if !dead_code_blocks.is_empty() {
8760            recommendations.push(format!(
8761                "Remove {} dead code blocks to eliminate unreachable code",
8762                dead_code_blocks.len()
8763            ));
8764        }
8765
8766        if recommendations.is_empty() {
8767            recommendations
8768                .push("No unused code detected with current confidence threshold".to_string());
8769        } else {
8770            recommendations.push("Consider running tests after removing unused code to ensure no unexpected dependencies".to_string());
8771            recommendations.push(
8772                "Use version control to safely experiment with unused code removal".to_string(),
8773            );
8774        }
8775
8776        recommendations
8777    }
8778
8779    /// Perform security vulnerability analysis
8780    async fn perform_security_analysis(
8781        &self,
8782        server: &CodePrismMcpServer,
8783        scope: &str,
8784        vulnerability_types: &[String],
8785        severity_threshold: &str,
8786        include_data_flow_analysis: bool,
8787        check_external_dependencies: bool,
8788        exclude_patterns: &[String],
8789    ) -> Result<serde_json::Value> {
8790        let mut vulnerabilities = Vec::new();
8791
8792        // Analyze different types of vulnerabilities based on the request
8793        if vulnerability_types.contains(&"injection".to_string())
8794            || vulnerability_types.contains(&"all".to_string())
8795        {
8796            let injection_vulns = self
8797                .detect_injection_vulnerabilities(server, exclude_patterns)
8798                .await?;
8799            vulnerabilities.extend(injection_vulns);
8800        }
8801
8802        if vulnerability_types.contains(&"authentication".to_string())
8803            || vulnerability_types.contains(&"all".to_string())
8804        {
8805            let auth_vulns = self
8806                .detect_authentication_issues(server, exclude_patterns)
8807                .await?;
8808            vulnerabilities.extend(auth_vulns);
8809        }
8810
8811        if vulnerability_types.contains(&"authorization".to_string())
8812            || vulnerability_types.contains(&"all".to_string())
8813        {
8814            let authz_vulns = self
8815                .detect_authorization_issues(server, exclude_patterns)
8816                .await?;
8817            vulnerabilities.extend(authz_vulns);
8818        }
8819
8820        if vulnerability_types.contains(&"data_exposure".to_string())
8821            || vulnerability_types.contains(&"all".to_string())
8822        {
8823            let data_vulns = self
8824                .detect_data_exposure_issues(server, exclude_patterns)
8825                .await?;
8826            vulnerabilities.extend(data_vulns);
8827        }
8828
8829        if vulnerability_types.contains(&"unsafe_patterns".to_string())
8830            || vulnerability_types.contains(&"all".to_string())
8831        {
8832            let unsafe_vulns = self
8833                .detect_unsafe_patterns(server, exclude_patterns)
8834                .await?;
8835            vulnerabilities.extend(unsafe_vulns);
8836        }
8837
8838        if vulnerability_types.contains(&"crypto_issues".to_string())
8839            || vulnerability_types.contains(&"all".to_string())
8840        {
8841            let crypto_vulns = self.detect_crypto_issues(server, exclude_patterns).await?;
8842            vulnerabilities.extend(crypto_vulns);
8843        }
8844
8845        // Filter by severity threshold
8846        let severity_order = ["low", "medium", "high", "critical"];
8847        let min_severity_index = severity_order
8848            .iter()
8849            .position(|&s| s == severity_threshold)
8850            .unwrap_or(1);
8851
8852        vulnerabilities.retain(|vuln| {
8853            if let Some(severity) = vuln.get("severity").and_then(|s| s.as_str()) {
8854                severity_order
8855                    .iter()
8856                    .position(|&s| s == severity)
8857                    .unwrap_or(0)
8858                    >= min_severity_index
8859            } else {
8860                true // Include if severity is not specified
8861            }
8862        });
8863
8864        // Group vulnerabilities by severity and type
8865        let mut by_severity = std::collections::HashMap::new();
8866        let mut by_type = std::collections::HashMap::new();
8867
8868        for vuln in &vulnerabilities {
8869            if let Some(severity) = vuln.get("severity").and_then(|s| s.as_str()) {
8870                by_severity
8871                    .entry(severity.to_string())
8872                    .or_insert_with(Vec::new)
8873                    .push(vuln);
8874            }
8875            if let Some(vuln_type) = vuln.get("type").and_then(|t| t.as_str()) {
8876                by_type
8877                    .entry(vuln_type.to_string())
8878                    .or_insert_with(Vec::new)
8879                    .push(vuln);
8880            }
8881        }
8882
8883        Ok(serde_json::json!({
8884            "scope": scope,
8885            "analysis_parameters": {
8886                "vulnerability_types": vulnerability_types,
8887                "severity_threshold": severity_threshold,
8888                "include_data_flow_analysis": include_data_flow_analysis,
8889                "check_external_dependencies": check_external_dependencies
8890            },
8891            "vulnerabilities": vulnerabilities,
8892            "summary": {
8893                "total_vulnerabilities": vulnerabilities.len(),
8894                "by_severity": by_severity.iter().map(|(k, v)| (k.clone(), v.len())).collect::<std::collections::HashMap<_, _>>(),
8895                "by_type": by_type.iter().map(|(k, v)| (k.clone(), v.len())).collect::<std::collections::HashMap<_, _>>(),
8896                "critical_count": by_severity.get("critical").map(|v| v.len()).unwrap_or(0),
8897                "high_count": by_severity.get("high").map(|v| v.len()).unwrap_or(0),
8898                "medium_count": by_severity.get("medium").map(|v| v.len()).unwrap_or(0),
8899                "low_count": by_severity.get("low").map(|v| v.len()).unwrap_or(0)
8900            },
8901            "recommendations": self.get_security_recommendations(&vulnerabilities)
8902        }))
8903    }
8904
8905    /// Detect injection vulnerabilities (SQL injection, code injection, etc.)
8906    async fn detect_injection_vulnerabilities(
8907        &self,
8908        server: &CodePrismMcpServer,
8909        exclude_patterns: &[String],
8910    ) -> Result<Vec<serde_json::Value>> {
8911        let mut vulnerabilities = Vec::new();
8912        let functions = server
8913            .graph_store()
8914            .get_nodes_by_kind(codeprism_core::NodeKind::Function);
8915
8916        for function in functions {
8917            if exclude_patterns
8918                .iter()
8919                .any(|pattern| function.file.to_string_lossy().contains(pattern))
8920            {
8921                continue;
8922            }
8923
8924            // Check function names for SQL-related patterns
8925            let function_name_lower = function.name.to_lowercase();
8926            if function_name_lower.contains("sql")
8927                || function_name_lower.contains("query")
8928                || function_name_lower.contains("exec")
8929            {
8930                // Look for potentially dangerous patterns
8931                let references = server.graph_query().find_references(&function.id)?;
8932                let call_count = references
8933                    .iter()
8934                    .filter(|r| matches!(r.edge_kind, codeprism_core::EdgeKind::Calls))
8935                    .count();
8936
8937                if call_count > 0 {
8938                    vulnerabilities.push(serde_json::json!({
8939                        "type": "Potential SQL Injection",
8940                        "severity": "medium",
8941                        "function": {
8942                            "id": function.id.to_hex(),
8943                            "name": function.name,
8944                            "file": function.file.display().to_string(),
8945                            "location": {
8946                                "start_line": function.span.start_line,
8947                                "end_line": function.span.end_line
8948                            }
8949                        },
8950                        "description": "Function name suggests SQL operations - ensure proper parameterization",
8951                        "recommendation": "Use parameterized queries or prepared statements to prevent SQL injection",
8952                        "confidence": 0.6
8953                    }));
8954                }
8955            }
8956
8957            // Check for eval-like functions (code injection risk)
8958            if function_name_lower.contains("eval")
8959                || function_name_lower.contains("exec")
8960                || function_name_lower.contains("compile")
8961            {
8962                vulnerabilities.push(serde_json::json!({
8963                    "type": "Code Injection Risk",
8964                    "severity": "high",
8965                    "function": {
8966                        "id": function.id.to_hex(),
8967                        "name": function.name,
8968                        "file": function.file.display().to_string(),
8969                        "location": {
8970                            "start_line": function.span.start_line,
8971                            "end_line": function.span.end_line
8972                        }
8973                    },
8974                    "description": "Function involves dynamic code execution which can be dangerous",
8975                    "recommendation": "Avoid dynamic code execution or implement strict input validation",
8976                    "confidence": 0.8
8977                }));
8978            }
8979        }
8980
8981        Ok(vulnerabilities)
8982    }
8983
8984    /// Detect authentication-related security issues
8985    async fn detect_authentication_issues(
8986        &self,
8987        server: &CodePrismMcpServer,
8988        exclude_patterns: &[String],
8989    ) -> Result<Vec<serde_json::Value>> {
8990        let mut vulnerabilities = Vec::new();
8991        let functions = server
8992            .graph_store()
8993            .get_nodes_by_kind(codeprism_core::NodeKind::Function);
8994
8995        for function in functions {
8996            if exclude_patterns
8997                .iter()
8998                .any(|pattern| function.file.to_string_lossy().contains(pattern))
8999            {
9000                continue;
9001            }
9002
9003            let function_name_lower = function.name.to_lowercase();
9004
9005            // Check for authentication-related functions
9006            if function_name_lower.contains("login")
9007                || function_name_lower.contains("auth")
9008                || function_name_lower.contains("signin")
9009                || function_name_lower.contains("password")
9010            {
9011                // Look for potential weak authentication patterns
9012                let variables = server
9013                    .graph_store()
9014                    .get_nodes_by_kind(codeprism_core::NodeKind::Variable);
9015                let weak_auth_patterns = variables.iter().any(|var| {
9016                    let var_name_lower = var.name.to_lowercase();
9017                    var.file == function.file
9018                        && (var_name_lower.contains("password")
9019                            || var_name_lower.contains("secret")
9020                            || var_name_lower.contains("token"))
9021                });
9022
9023                if weak_auth_patterns {
9024                    vulnerabilities.push(serde_json::json!({
9025                        "type": "Authentication Security Concern",
9026                        "severity": "medium",
9027                        "function": {
9028                            "id": function.id.to_hex(),
9029                            "name": function.name,
9030                            "file": function.file.display().to_string(),
9031                            "location": {
9032                                "start_line": function.span.start_line,
9033                                "end_line": function.span.end_line
9034                            }
9035                        },
9036                        "description": "Authentication function detected - ensure secure implementation",
9037                        "recommendation": "Use secure password hashing, implement rate limiting, and secure session management",
9038                        "confidence": 0.7
9039                    }));
9040                }
9041            }
9042        }
9043
9044        Ok(vulnerabilities)
9045    }
9046
9047    /// Detect authorization-related security issues
9048    async fn detect_authorization_issues(
9049        &self,
9050        server: &CodePrismMcpServer,
9051        exclude_patterns: &[String],
9052    ) -> Result<Vec<serde_json::Value>> {
9053        let mut vulnerabilities = Vec::new();
9054        let functions = server
9055            .graph_store()
9056            .get_nodes_by_kind(codeprism_core::NodeKind::Function);
9057
9058        for function in functions {
9059            if exclude_patterns
9060                .iter()
9061                .any(|pattern| function.file.to_string_lossy().contains(pattern))
9062            {
9063                continue;
9064            }
9065
9066            let function_name_lower = function.name.to_lowercase();
9067
9068            // Check for authorization-related functions that might need access control
9069            if function_name_lower.contains("admin")
9070                || function_name_lower.contains("delete")
9071                || function_name_lower.contains("modify")
9072                || function_name_lower.contains("update")
9073                || function_name_lower.contains("create")
9074            {
9075                vulnerabilities.push(serde_json::json!({
9076                    "type": "Authorization Check Needed",
9077                    "severity": "medium",
9078                    "function": {
9079                        "id": function.id.to_hex(),
9080                        "name": function.name,
9081                        "file": function.file.display().to_string(),
9082                        "location": {
9083                            "start_line": function.span.start_line,
9084                            "end_line": function.span.end_line
9085                        }
9086                    },
9087                    "description": "Function performs sensitive operations - ensure proper authorization checks",
9088                    "recommendation": "Implement role-based access control and verify user permissions before execution",
9089                    "confidence": 0.5
9090                }));
9091            }
9092        }
9093
9094        Ok(vulnerabilities)
9095    }
9096
9097    /// Detect data exposure issues
9098    async fn detect_data_exposure_issues(
9099        &self,
9100        server: &CodePrismMcpServer,
9101        exclude_patterns: &[String],
9102    ) -> Result<Vec<serde_json::Value>> {
9103        let mut vulnerabilities = Vec::new();
9104        let variables = server
9105            .graph_store()
9106            .get_nodes_by_kind(codeprism_core::NodeKind::Variable);
9107
9108        for variable in variables {
9109            if exclude_patterns
9110                .iter()
9111                .any(|pattern| variable.file.to_string_lossy().contains(pattern))
9112            {
9113                continue;
9114            }
9115
9116            let var_name_lower = variable.name.to_lowercase();
9117
9118            // Check for sensitive data in variable names
9119            if var_name_lower.contains("password")
9120                || var_name_lower.contains("secret")
9121                || var_name_lower.contains("key")
9122                || var_name_lower.contains("token")
9123                || var_name_lower.contains("api_key")
9124                || var_name_lower.contains("private")
9125            {
9126                vulnerabilities.push(serde_json::json!({
9127                    "type": "Sensitive Data Exposure",
9128                    "severity": "high",
9129                    "variable": {
9130                        "id": variable.id.to_hex(),
9131                        "name": variable.name,
9132                        "file": variable.file.display().to_string(),
9133                        "location": {
9134                            "start_line": variable.span.start_line,
9135                            "end_line": variable.span.end_line
9136                        }
9137                    },
9138                    "description": "Variable contains potentially sensitive data",
9139                    "recommendation": "Ensure sensitive data is properly encrypted and not logged or exposed",
9140                    "confidence": 0.8
9141                }));
9142            }
9143        }
9144
9145        Ok(vulnerabilities)
9146    }
9147
9148    /// Detect unsafe coding patterns
9149    async fn detect_unsafe_patterns(
9150        &self,
9151        server: &CodePrismMcpServer,
9152        exclude_patterns: &[String],
9153    ) -> Result<Vec<serde_json::Value>> {
9154        let mut vulnerabilities = Vec::new();
9155        let functions = server
9156            .graph_store()
9157            .get_nodes_by_kind(codeprism_core::NodeKind::Function);
9158
9159        for function in functions {
9160            if exclude_patterns
9161                .iter()
9162                .any(|pattern| function.file.to_string_lossy().contains(pattern))
9163            {
9164                continue;
9165            }
9166
9167            let function_name_lower = function.name.to_lowercase();
9168
9169            // Check for potentially unsafe functions
9170            if function_name_lower.contains("unsafe")
9171                || function_name_lower.contains("raw")
9172                || function_name_lower.contains("ptr")
9173                || function_name_lower.contains("malloc")
9174                || function_name_lower.contains("strcpy")
9175            {
9176                vulnerabilities.push(serde_json::json!({
9177                    "type": "Unsafe Pattern",
9178                    "severity": "medium",
9179                    "function": {
9180                        "id": function.id.to_hex(),
9181                        "name": function.name,
9182                        "file": function.file.display().to_string(),
9183                        "location": {
9184                            "start_line": function.span.start_line,
9185                            "end_line": function.span.end_line
9186                        }
9187                    },
9188                    "description": "Function uses potentially unsafe patterns",
9189                    "recommendation": "Review for memory safety and input validation",
9190                    "confidence": 0.6
9191                }));
9192            }
9193        }
9194
9195        Ok(vulnerabilities)
9196    }
9197
9198    /// Detect cryptographic implementation issues
9199    async fn detect_crypto_issues(
9200        &self,
9201        server: &CodePrismMcpServer,
9202        exclude_patterns: &[String],
9203    ) -> Result<Vec<serde_json::Value>> {
9204        let mut vulnerabilities = Vec::new();
9205        let functions = server
9206            .graph_store()
9207            .get_nodes_by_kind(codeprism_core::NodeKind::Function);
9208
9209        for function in functions {
9210            if exclude_patterns
9211                .iter()
9212                .any(|pattern| function.file.to_string_lossy().contains(pattern))
9213            {
9214                continue;
9215            }
9216
9217            let function_name_lower = function.name.to_lowercase();
9218
9219            // Check for cryptographic functions that might be implemented unsafely
9220            if function_name_lower.contains("encrypt")
9221                || function_name_lower.contains("decrypt")
9222                || function_name_lower.contains("hash")
9223                || function_name_lower.contains("crypto")
9224                || function_name_lower.contains("cipher")
9225            {
9226                vulnerabilities.push(serde_json::json!({
9227                    "type": "Cryptographic Implementation",
9228                    "severity": "high",
9229                    "function": {
9230                        "id": function.id.to_hex(),
9231                        "name": function.name,
9232                        "file": function.file.display().to_string(),
9233                        "location": {
9234                            "start_line": function.span.start_line,
9235                            "end_line": function.span.end_line
9236                        }
9237                    },
9238                    "description": "Function implements cryptographic operations - ensure secure implementation",
9239                    "recommendation": "Use well-tested cryptographic libraries, avoid custom crypto implementations",
9240                    "confidence": 0.7
9241                }));
9242            }
9243        }
9244
9245        Ok(vulnerabilities)
9246    }
9247
9248    /// Get security recommendations based on found vulnerabilities
9249    fn get_security_recommendations(&self, vulnerabilities: &[serde_json::Value]) -> Vec<String> {
9250        let mut recommendations = Vec::new();
9251
9252        let critical_count = vulnerabilities
9253            .iter()
9254            .filter(|v| v.get("severity").and_then(|s| s.as_str()) == Some("critical"))
9255            .count();
9256
9257        let high_count = vulnerabilities
9258            .iter()
9259            .filter(|v| v.get("severity").and_then(|s| s.as_str()) == Some("high"))
9260            .count();
9261
9262        if critical_count > 0 {
9263            recommendations.push(format!(
9264                "URGENT: Address {} critical security vulnerabilities immediately",
9265                critical_count
9266            ));
9267        }
9268
9269        if high_count > 0 {
9270            recommendations.push(format!(
9271                "HIGH PRIORITY: Address {} high-severity security issues",
9272                high_count
9273            ));
9274        }
9275
9276        // Type-specific recommendations
9277        let injection_count = vulnerabilities
9278            .iter()
9279            .filter(|v| {
9280                v.get("type")
9281                    .and_then(|t| t.as_str())
9282                    .map(|s| s.contains("Injection"))
9283                    .unwrap_or(false)
9284            })
9285            .count();
9286
9287        if injection_count > 0 {
9288            recommendations.push(
9289                "Implement input validation and parameterized queries to prevent injection attacks"
9290                    .to_string(),
9291            );
9292        }
9293
9294        let auth_count = vulnerabilities
9295            .iter()
9296            .filter(|v| {
9297                v.get("type")
9298                    .and_then(|t| t.as_str())
9299                    .map(|s| s.contains("Authentication"))
9300                    .unwrap_or(false)
9301            })
9302            .count();
9303
9304        if auth_count > 0 {
9305            recommendations.push(
9306                "Review authentication mechanisms and implement secure password handling"
9307                    .to_string(),
9308            );
9309        }
9310
9311        let crypto_count = vulnerabilities
9312            .iter()
9313            .filter(|v| {
9314                v.get("type")
9315                    .and_then(|t| t.as_str())
9316                    .map(|s| s.contains("Cryptographic"))
9317                    .unwrap_or(false)
9318            })
9319            .count();
9320
9321        if crypto_count > 0 {
9322            recommendations.push(
9323                "Use established cryptographic libraries instead of custom implementations"
9324                    .to_string(),
9325            );
9326        }
9327
9328        if recommendations.is_empty() {
9329            recommendations.push(
9330                "No significant security vulnerabilities detected with current analysis"
9331                    .to_string(),
9332            );
9333        } else {
9334            recommendations.push(
9335                "Conduct regular security audits and implement automated security testing"
9336                    .to_string(),
9337            );
9338            recommendations.push("Follow OWASP security guidelines and best practices".to_string());
9339        }
9340
9341        recommendations
9342    }
9343
9344    /// Perform performance analysis
9345    async fn perform_performance_analysis(
9346        &self,
9347        server: &CodePrismMcpServer,
9348        scope: &str,
9349        analysis_types: &[String],
9350        complexity_threshold: &str,
9351        include_algorithmic_analysis: bool,
9352        detect_bottlenecks: bool,
9353        exclude_patterns: &[String],
9354    ) -> Result<serde_json::Value> {
9355        let mut performance_issues = Vec::new();
9356
9357        // Analyze different types of performance characteristics based on the request
9358        if analysis_types.contains(&"time_complexity".to_string())
9359            || analysis_types.contains(&"all".to_string())
9360        {
9361            let complexity_issues = self
9362                .analyze_time_complexity(server, exclude_patterns, include_algorithmic_analysis)
9363                .await?;
9364            performance_issues.extend(complexity_issues);
9365        }
9366
9367        if analysis_types.contains(&"memory_usage".to_string())
9368            || analysis_types.contains(&"all".to_string())
9369        {
9370            let memory_issues = self.analyze_memory_usage(server, exclude_patterns).await?;
9371            performance_issues.extend(memory_issues);
9372        }
9373
9374        if analysis_types.contains(&"hot_spots".to_string())
9375            || analysis_types.contains(&"all".to_string())
9376        {
9377            let hot_spot_issues = self
9378                .detect_performance_hot_spots(server, exclude_patterns, detect_bottlenecks)
9379                .await?;
9380            performance_issues.extend(hot_spot_issues);
9381        }
9382
9383        if analysis_types.contains(&"anti_patterns".to_string())
9384            || analysis_types.contains(&"all".to_string())
9385        {
9386            let anti_pattern_issues = self
9387                .detect_performance_anti_patterns(server, exclude_patterns)
9388                .await?;
9389            performance_issues.extend(anti_pattern_issues);
9390        }
9391
9392        if analysis_types.contains(&"scalability".to_string())
9393            || analysis_types.contains(&"all".to_string())
9394        {
9395            let scalability_issues = self
9396                .analyze_scalability_concerns(server, exclude_patterns)
9397                .await?;
9398            performance_issues.extend(scalability_issues);
9399        }
9400
9401        // Filter by complexity threshold
9402        let complexity_order = ["low", "medium", "high"];
9403        let min_complexity_index = complexity_order
9404            .iter()
9405            .position(|&s| s == complexity_threshold)
9406            .unwrap_or(1);
9407
9408        performance_issues.retain(|issue| {
9409            if let Some(complexity) = issue.get("complexity").and_then(|c| c.as_str()) {
9410                complexity_order
9411                    .iter()
9412                    .position(|&s| s == complexity)
9413                    .unwrap_or(0)
9414                    >= min_complexity_index
9415            } else {
9416                true // Include if complexity is not specified
9417            }
9418        });
9419
9420        // Group issues by category and complexity
9421        let mut by_category = std::collections::HashMap::new();
9422        let mut by_complexity = std::collections::HashMap::new();
9423
9424        for issue in &performance_issues {
9425            if let Some(category) = issue.get("category").and_then(|c| c.as_str()) {
9426                by_category
9427                    .entry(category.to_string())
9428                    .or_insert_with(Vec::new)
9429                    .push(issue);
9430            }
9431            if let Some(complexity) = issue.get("complexity").and_then(|c| c.as_str()) {
9432                by_complexity
9433                    .entry(complexity.to_string())
9434                    .or_insert_with(Vec::new)
9435                    .push(issue);
9436            }
9437        }
9438
9439        Ok(serde_json::json!({
9440            "scope": scope,
9441            "analysis_parameters": {
9442                "analysis_types": analysis_types,
9443                "complexity_threshold": complexity_threshold,
9444                "include_algorithmic_analysis": include_algorithmic_analysis,
9445                "detect_bottlenecks": detect_bottlenecks
9446            },
9447            "performance_issues": performance_issues,
9448            "summary": {
9449                "total_issues": performance_issues.len(),
9450                "by_category": by_category.iter().map(|(k, v)| (k.clone(), v.len())).collect::<std::collections::HashMap<_, _>>(),
9451                "by_complexity": by_complexity.iter().map(|(k, v)| (k.clone(), v.len())).collect::<std::collections::HashMap<_, _>>(),
9452                "high_complexity_count": by_complexity.get("high").map(|v| v.len()).unwrap_or(0),
9453                "medium_complexity_count": by_complexity.get("medium").map(|v| v.len()).unwrap_or(0),
9454                "low_complexity_count": by_complexity.get("low").map(|v| v.len()).unwrap_or(0)
9455            },
9456            "recommendations": self.get_performance_recommendations(&performance_issues)
9457        }))
9458    }
9459
9460    /// Analyze time complexity characteristics
9461    async fn analyze_time_complexity(
9462        &self,
9463        server: &CodePrismMcpServer,
9464        exclude_patterns: &[String],
9465        include_algorithmic_analysis: bool,
9466    ) -> Result<Vec<serde_json::Value>> {
9467        let mut issues = Vec::new();
9468        let functions = server
9469            .graph_store()
9470            .get_nodes_by_kind(codeprism_core::NodeKind::Function);
9471
9472        for function in functions {
9473            if exclude_patterns
9474                .iter()
9475                .any(|pattern| function.file.to_string_lossy().contains(pattern))
9476            {
9477                continue;
9478            }
9479
9480            // Analyze nested loops (basic O(n^k) detection)
9481            let function_name_lower = function.name.to_lowercase();
9482
9483            // Check for potentially expensive operations
9484            if function_name_lower.contains("sort")
9485                || function_name_lower.contains("search")
9486                || function_name_lower.contains("find")
9487                || function_name_lower.contains("filter")
9488            {
9489                let references = server.graph_query().find_references(&function.id)?;
9490                let call_count = references
9491                    .iter()
9492                    .filter(|r| matches!(r.edge_kind, codeprism_core::EdgeKind::Calls))
9493                    .count();
9494
9495                if call_count > 10 {
9496                    // Frequently called expensive functions
9497                    issues.push(serde_json::json!({
9498                        "type": "High Time Complexity Function",
9499                        "category": "time_complexity",
9500                        "complexity": "high",
9501                        "function": {
9502                            "id": function.id.to_hex(),
9503                            "name": function.name,
9504                            "file": function.file.display().to_string(),
9505                            "location": {
9506                                "start_line": function.span.start_line,
9507                                "end_line": function.span.end_line
9508                            }
9509                        },
9510                        "description": format!("Function '{}' appears to involve expensive operations and is frequently called ({} times)", function.name, call_count),
9511                        "estimated_complexity": "O(n log n) or worse",
9512                        "recommendation": "Consider caching results, optimizing algorithms, or reducing call frequency",
9513                        "call_count": call_count
9514                    }));
9515                }
9516            }
9517
9518            // Basic nested loop detection by function length and complexity
9519            if include_algorithmic_analysis {
9520                let function_lines = function.span.end_line - function.span.start_line + 1;
9521                let cyclomatic_complexity = self.calculate_cyclomatic_complexity("");
9522
9523                if function_lines > 100 && cyclomatic_complexity > 20 {
9524                    issues.push(serde_json::json!({
9525                        "type": "Complex Algorithm",
9526                        "category": "time_complexity",
9527                        "complexity": "medium",
9528                        "function": {
9529                            "id": function.id.to_hex(),
9530                            "name": function.name,
9531                            "file": function.file.display().to_string(),
9532                            "location": {
9533                                "start_line": function.span.start_line,
9534                                "end_line": function.span.end_line
9535                            }
9536                        },
9537                        "description": format!("Function '{}' has high complexity ({} lines, complexity: {})", function.name, function_lines, cyclomatic_complexity),
9538                        "estimated_complexity": "O(n^2) or worse",
9539                        "recommendation": "Break down into smaller functions and optimize algorithms",
9540                        "lines_of_code": function_lines,
9541                        "cyclomatic_complexity": cyclomatic_complexity
9542                    }));
9543                }
9544            }
9545        }
9546
9547        Ok(issues)
9548    }
9549
9550    /// Analyze memory usage patterns
9551    async fn analyze_memory_usage(
9552        &self,
9553        server: &CodePrismMcpServer,
9554        exclude_patterns: &[String],
9555    ) -> Result<Vec<serde_json::Value>> {
9556        let mut issues = Vec::new();
9557        let functions = server
9558            .graph_store()
9559            .get_nodes_by_kind(codeprism_core::NodeKind::Function);
9560
9561        for function in functions {
9562            if exclude_patterns
9563                .iter()
9564                .any(|pattern| function.file.to_string_lossy().contains(pattern))
9565            {
9566                continue;
9567            }
9568
9569            let function_name_lower = function.name.to_lowercase();
9570
9571            // Check for potential memory-intensive operations
9572            if function_name_lower.contains("load")
9573                || function_name_lower.contains("read")
9574                || function_name_lower.contains("parse")
9575                || function_name_lower.contains("create")
9576                || function_name_lower.contains("build")
9577            {
9578                // Look for variables that might indicate large data structures
9579                let variables = server
9580                    .graph_store()
9581                    .get_nodes_by_kind(codeprism_core::NodeKind::Variable);
9582                let large_data_vars = variables
9583                    .iter()
9584                    .filter(|var| {
9585                        var.file == function.file
9586                            && (var.name.to_lowercase().contains("list")
9587                                || var.name.to_lowercase().contains("array")
9588                                || var.name.to_lowercase().contains("data")
9589                                || var.name.to_lowercase().contains("buffer")
9590                                || var.name.to_lowercase().contains("cache"))
9591                    })
9592                    .count();
9593
9594                if large_data_vars > 3 {
9595                    issues.push(serde_json::json!({
9596                        "type": "High Memory Usage",
9597                        "category": "memory_usage",
9598                        "complexity": "medium",
9599                        "function": {
9600                            "id": function.id.to_hex(),
9601                            "name": function.name,
9602                            "file": function.file.display().to_string(),
9603                            "location": {
9604                                "start_line": function.span.start_line,
9605                                "end_line": function.span.end_line
9606                            }
9607                        },
9608                        "description": format!("Function '{}' uses multiple large data structures ({} variables)", function.name, large_data_vars),
9609                        "recommendation": "Consider streaming processing, pagination, or memory pooling",
9610                        "large_data_variables": large_data_vars
9611                    }));
9612                }
9613            }
9614        }
9615
9616        Ok(issues)
9617    }
9618
9619    /// Detect performance hot spots and bottlenecks
9620    async fn detect_performance_hot_spots(
9621        &self,
9622        server: &CodePrismMcpServer,
9623        exclude_patterns: &[String],
9624        detect_bottlenecks: bool,
9625    ) -> Result<Vec<serde_json::Value>> {
9626        let mut issues = Vec::new();
9627        let functions = server
9628            .graph_store()
9629            .get_nodes_by_kind(codeprism_core::NodeKind::Function);
9630
9631        for function in functions {
9632            if exclude_patterns
9633                .iter()
9634                .any(|pattern| function.file.to_string_lossy().contains(pattern))
9635            {
9636                continue;
9637            }
9638
9639            // Count references to identify hot spots
9640            let references = server.graph_query().find_references(&function.id)?;
9641            let call_count = references
9642                .iter()
9643                .filter(|r| matches!(r.edge_kind, codeprism_core::EdgeKind::Calls))
9644                .count();
9645
9646            // Functions called many times are potential hot spots
9647            if call_count > 20 {
9648                let function_lines = function.span.end_line - function.span.start_line + 1;
9649
9650                issues.push(serde_json::json!({
9651                    "type": "Performance Hot Spot",
9652                    "category": "hot_spots",
9653                    "complexity": if call_count > 50 { "high" } else { "medium" },
9654                    "function": {
9655                        "id": function.id.to_hex(),
9656                        "name": function.name,
9657                        "file": function.file.display().to_string(),
9658                        "location": {
9659                            "start_line": function.span.start_line,
9660                            "end_line": function.span.end_line
9661                        }
9662                    },
9663                    "description": format!("Function '{}' is called {} times - potential performance hot spot", function.name, call_count),
9664                    "recommendation": "Optimize this function as it's frequently called, consider caching or memoization",
9665                    "call_count": call_count,
9666                    "lines_of_code": function_lines
9667                }));
9668            }
9669
9670            // Detect potential bottlenecks (I/O operations)
9671            if detect_bottlenecks {
9672                let function_name_lower = function.name.to_lowercase();
9673                if function_name_lower.contains("read")
9674                    || function_name_lower.contains("write")
9675                    || function_name_lower.contains("fetch")
9676                    || function_name_lower.contains("request")
9677                    || function_name_lower.contains("query")
9678                {
9679                    issues.push(serde_json::json!({
9680                        "type": "I/O Bottleneck",
9681                        "category": "hot_spots",
9682                        "complexity": "medium",
9683                        "function": {
9684                            "id": function.id.to_hex(),
9685                            "name": function.name,
9686                            "file": function.file.display().to_string(),
9687                            "location": {
9688                                "start_line": function.span.start_line,
9689                                "end_line": function.span.end_line
9690                            }
9691                        },
9692                        "description": format!("Function '{}' performs I/O operations which can be a bottleneck", function.name),
9693                        "recommendation": "Consider async operations, connection pooling, or caching",
9694                        "call_count": call_count
9695                    }));
9696                }
9697            }
9698        }
9699
9700        Ok(issues)
9701    }
9702
9703    /// Detect performance anti-patterns
9704    async fn detect_performance_anti_patterns(
9705        &self,
9706        server: &CodePrismMcpServer,
9707        exclude_patterns: &[String],
9708    ) -> Result<Vec<serde_json::Value>> {
9709        let mut issues = Vec::new();
9710        let functions = server
9711            .graph_store()
9712            .get_nodes_by_kind(codeprism_core::NodeKind::Function);
9713
9714        for function in functions {
9715            if exclude_patterns
9716                .iter()
9717                .any(|pattern| function.file.to_string_lossy().contains(pattern))
9718            {
9719                continue;
9720            }
9721
9722            // Detect potential N+1 query pattern
9723            let function_name_lower = function.name.to_lowercase();
9724            if function_name_lower.contains("get") || function_name_lower.contains("fetch") {
9725                let dependencies = server.graph_query().find_dependencies(
9726                    &function.id,
9727                    codeprism_core::graph::DependencyType::Calls,
9728                )?;
9729                let loop_like_calls = dependencies
9730                    .iter()
9731                    .filter(|dep| {
9732                        let dep_name = dep.target_node.name.to_lowercase();
9733                        dep_name.contains("query")
9734                            || dep_name.contains("get")
9735                            || dep_name.contains("fetch")
9736                    })
9737                    .count();
9738
9739                if loop_like_calls > 1 {
9740                    issues.push(serde_json::json!({
9741                        "type": "Potential N+1 Query Pattern",
9742                        "category": "anti_patterns",
9743                        "complexity": "high",
9744                        "function": {
9745                            "id": function.id.to_hex(),
9746                            "name": function.name,
9747                            "file": function.file.display().to_string(),
9748                            "location": {
9749                                "start_line": function.span.start_line,
9750                                "end_line": function.span.end_line
9751                            }
9752                        },
9753                        "description": format!("Function '{}' makes multiple queries/fetches - potential N+1 pattern", function.name),
9754                        "recommendation": "Use batch queries, joins, or eager loading to reduce query count",
9755                        "query_calls": loop_like_calls
9756                    }));
9757                }
9758            }
9759
9760            // Detect premature optimization patterns
9761            if function_name_lower.contains("optimize") || function_name_lower.contains("cache") {
9762                let function_lines = function.span.end_line - function.span.start_line + 1;
9763                if function_lines > 50 {
9764                    issues.push(serde_json::json!({
9765                        "type": "Complex Optimization",
9766                        "category": "anti_patterns",
9767                        "complexity": "medium",
9768                        "function": {
9769                            "id": function.id.to_hex(),
9770                            "name": function.name,
9771                            "file": function.file.display().to_string(),
9772                            "location": {
9773                                "start_line": function.span.start_line,
9774                                "end_line": function.span.end_line
9775                            }
9776                        },
9777                        "description": format!("Function '{}' appears to be a complex optimization - verify it's necessary", function.name),
9778                        "recommendation": "Ensure optimization is justified by profiling data",
9779                        "lines_of_code": function_lines
9780                    }));
9781                }
9782            }
9783        }
9784
9785        Ok(issues)
9786    }
9787
9788    /// Analyze scalability concerns
9789    async fn analyze_scalability_concerns(
9790        &self,
9791        server: &CodePrismMcpServer,
9792        exclude_patterns: &[String],
9793    ) -> Result<Vec<serde_json::Value>> {
9794        let mut issues = Vec::new();
9795        let functions = server
9796            .graph_store()
9797            .get_nodes_by_kind(codeprism_core::NodeKind::Function);
9798
9799        for function in functions {
9800            if exclude_patterns
9801                .iter()
9802                .any(|pattern| function.file.to_string_lossy().contains(pattern))
9803            {
9804                continue;
9805            }
9806
9807            let function_name_lower = function.name.to_lowercase();
9808
9809            // Check for global state usage (scalability concern)
9810            if function_name_lower.contains("global")
9811                || function_name_lower.contains("singleton")
9812                || function_name_lower.contains("static")
9813            {
9814                issues.push(serde_json::json!({
9815                    "type": "Global State Usage",
9816                    "category": "scalability",
9817                    "complexity": "medium",
9818                    "function": {
9819                        "id": function.id.to_hex(),
9820                        "name": function.name,
9821                        "file": function.file.display().to_string(),
9822                        "location": {
9823                            "start_line": function.span.start_line,
9824                            "end_line": function.span.end_line
9825                        }
9826                    },
9827                    "description": format!("Function '{}' uses global state which can limit scalability", function.name),
9828                    "recommendation": "Consider dependency injection or stateless design for better scalability"
9829                }));
9830            }
9831
9832            // Check for synchronous operations that could block
9833            if function_name_lower.contains("wait")
9834                || function_name_lower.contains("sleep")
9835                || function_name_lower.contains("block")
9836                || function_name_lower.contains("sync")
9837            {
9838                issues.push(serde_json::json!({
9839                    "type": "Blocking Operation",
9840                    "category": "scalability",
9841                    "complexity": "high",
9842                    "function": {
9843                        "id": function.id.to_hex(),
9844                        "name": function.name,
9845                        "file": function.file.display().to_string(),
9846                        "location": {
9847                            "start_line": function.span.start_line,
9848                            "end_line": function.span.end_line
9849                        }
9850                    },
9851                    "description": format!("Function '{}' performs blocking operations which can hurt scalability", function.name),
9852                    "recommendation": "Consider async operations or non-blocking alternatives"
9853                }));
9854            }
9855        }
9856
9857        Ok(issues)
9858    }
9859
9860    /// Get performance recommendations based on found issues
9861    fn get_performance_recommendations(&self, issues: &[serde_json::Value]) -> Vec<String> {
9862        let mut recommendations = Vec::new();
9863
9864        let high_complexity_count = issues
9865            .iter()
9866            .filter(|i| i.get("complexity").and_then(|c| c.as_str()) == Some("high"))
9867            .count();
9868
9869        let medium_complexity_count = issues
9870            .iter()
9871            .filter(|i| i.get("complexity").and_then(|c| c.as_str()) == Some("medium"))
9872            .count();
9873
9874        if high_complexity_count > 0 {
9875            recommendations.push(format!(
9876                "HIGH PRIORITY: Address {} high-complexity performance issues",
9877                high_complexity_count
9878            ));
9879        }
9880
9881        if medium_complexity_count > 0 {
9882            recommendations.push(format!(
9883                "MEDIUM PRIORITY: Review {} medium-complexity performance concerns",
9884                medium_complexity_count
9885            ));
9886        }
9887
9888        // Category-specific recommendations
9889        let hot_spot_count = issues
9890            .iter()
9891            .filter(|i| i.get("category").and_then(|c| c.as_str()) == Some("hot_spots"))
9892            .count();
9893
9894        if hot_spot_count > 0 {
9895            recommendations
9896                .push("Profile hot spots and optimize frequently called functions".to_string());
9897        }
9898
9899        let time_complexity_count = issues
9900            .iter()
9901            .filter(|i| i.get("category").and_then(|c| c.as_str()) == Some("time_complexity"))
9902            .count();
9903
9904        if time_complexity_count > 0 {
9905            recommendations.push(
9906                "Review algorithmic complexity and consider more efficient algorithms".to_string(),
9907            );
9908        }
9909
9910        let memory_count = issues
9911            .iter()
9912            .filter(|i| i.get("category").and_then(|c| c.as_str()) == Some("memory_usage"))
9913            .count();
9914
9915        if memory_count > 0 {
9916            recommendations.push(
9917                "Optimize memory usage with streaming, pagination, or caching strategies"
9918                    .to_string(),
9919            );
9920        }
9921
9922        let scalability_count = issues
9923            .iter()
9924            .filter(|i| i.get("category").and_then(|c| c.as_str()) == Some("scalability"))
9925            .count();
9926
9927        if scalability_count > 0 {
9928            recommendations.push(
9929                "Address scalability concerns by reducing global state and blocking operations"
9930                    .to_string(),
9931            );
9932        }
9933
9934        if recommendations.is_empty() {
9935            recommendations.push(
9936                "No significant performance issues detected with current analysis".to_string(),
9937            );
9938        } else {
9939            recommendations
9940                .push("Use profiling tools to validate performance assumptions".to_string());
9941            recommendations.push("Implement performance monitoring and alerting".to_string());
9942            recommendations
9943                .push("Consider load testing to validate scalability improvements".to_string());
9944        }
9945
9946        recommendations
9947    }
9948
9949    /// Perform API surface analysis
9950    async fn perform_api_surface_analysis(
9951        &self,
9952        server: &CodePrismMcpServer,
9953        scope: &str,
9954        analysis_types: &[String],
9955        api_version: Option<&str>,
9956        include_private_apis: bool,
9957        check_documentation_coverage: bool,
9958        detect_breaking_changes: bool,
9959        exclude_patterns: &[String],
9960    ) -> Result<serde_json::Value> {
9961        let mut api_issues = Vec::new();
9962
9963        // Analyze different types of API characteristics based on the request
9964        if analysis_types.contains(&"public_api".to_string())
9965            || analysis_types.contains(&"all".to_string())
9966        {
9967            let public_api_analysis = self
9968                .analyze_public_api(server, exclude_patterns, include_private_apis)
9969                .await?;
9970            api_issues.extend(public_api_analysis);
9971        }
9972
9973        if analysis_types.contains(&"versioning".to_string())
9974            || analysis_types.contains(&"all".to_string())
9975        {
9976            let versioning_issues = self
9977                .analyze_api_versioning(server, exclude_patterns, api_version)
9978                .await?;
9979            api_issues.extend(versioning_issues);
9980        }
9981
9982        if (analysis_types.contains(&"breaking_changes".to_string())
9983            || analysis_types.contains(&"all".to_string()))
9984            && detect_breaking_changes
9985        {
9986            let breaking_change_issues = self
9987                .detect_api_breaking_changes(server, exclude_patterns)
9988                .await?;
9989            api_issues.extend(breaking_change_issues);
9990        }
9991
9992        if (analysis_types.contains(&"documentation".to_string())
9993            || analysis_types.contains(&"all".to_string()))
9994            && check_documentation_coverage
9995        {
9996            let doc_coverage_issues = self
9997                .analyze_api_documentation_coverage(server, exclude_patterns)
9998                .await?;
9999            api_issues.extend(doc_coverage_issues);
10000        }
10001
10002        if analysis_types.contains(&"compatibility".to_string())
10003            || analysis_types.contains(&"all".to_string())
10004        {
10005            let compatibility_issues = self
10006                .analyze_api_compatibility(server, exclude_patterns, api_version)
10007                .await?;
10008            api_issues.extend(compatibility_issues);
10009        }
10010
10011        // Group issues by category and severity
10012        let mut by_category = std::collections::HashMap::new();
10013        let mut by_severity = std::collections::HashMap::new();
10014
10015        for issue in &api_issues {
10016            if let Some(category) = issue.get("category").and_then(|c| c.as_str()) {
10017                by_category
10018                    .entry(category.to_string())
10019                    .or_insert_with(Vec::new)
10020                    .push(issue);
10021            }
10022            if let Some(severity) = issue.get("severity").and_then(|s| s.as_str()) {
10023                by_severity
10024                    .entry(severity.to_string())
10025                    .or_insert_with(Vec::new)
10026                    .push(issue);
10027            }
10028        }
10029
10030        Ok(serde_json::json!({
10031            "scope": scope,
10032            "analysis_parameters": {
10033                "analysis_types": analysis_types,
10034                "api_version": api_version,
10035                "include_private_apis": include_private_apis,
10036                "check_documentation_coverage": check_documentation_coverage,
10037                "detect_breaking_changes": detect_breaking_changes
10038            },
10039            "api_issues": api_issues,
10040            "summary": {
10041                "total_issues": api_issues.len(),
10042                "by_category": by_category.iter().map(|(k, v)| (k.clone(), v.len())).collect::<std::collections::HashMap<_, _>>(),
10043                "by_severity": by_severity.iter().map(|(k, v)| (k.clone(), v.len())).collect::<std::collections::HashMap<_, _>>(),
10044                "critical_issues": by_severity.get("critical").map(|v| v.len()).unwrap_or(0),
10045                "high_issues": by_severity.get("high").map(|v| v.len()).unwrap_or(0),
10046                "medium_issues": by_severity.get("medium").map(|v| v.len()).unwrap_or(0),
10047                "low_issues": by_severity.get("low").map(|v| v.len()).unwrap_or(0)
10048            },
10049            "recommendations": self.get_api_recommendations(&api_issues)
10050        }))
10051    }
10052
10053    /// Analyze public API surface
10054    async fn analyze_public_api(
10055        &self,
10056        server: &CodePrismMcpServer,
10057        exclude_patterns: &[String],
10058        include_private_apis: bool,
10059    ) -> Result<Vec<serde_json::Value>> {
10060        let mut issues = Vec::new();
10061        let functions = server
10062            .graph_store()
10063            .get_nodes_by_kind(codeprism_core::NodeKind::Function);
10064        let classes = server
10065            .graph_store()
10066            .get_nodes_by_kind(codeprism_core::NodeKind::Class);
10067
10068        // Analyze public functions
10069        for function in functions {
10070            if exclude_patterns
10071                .iter()
10072                .any(|pattern| function.file.to_string_lossy().contains(pattern))
10073            {
10074                continue;
10075            }
10076
10077            let function_name = &function.name;
10078            let is_public = self.is_public_api_element(function_name);
10079            let is_private = function_name.starts_with('_') || function_name.contains("private");
10080
10081            // Report public API functions
10082            if is_public || (include_private_apis && is_private) {
10083                let references = server.graph_query().find_references(&function.id)?;
10084                let external_usage_count = references.len();
10085
10086                issues.push(serde_json::json!({
10087                    "type": if is_public { "Public API Function" } else { "Private API Function" },
10088                    "category": "public_api",
10089                    "severity": if is_public { "medium" } else { "low" },
10090                    "function": {
10091                        "id": function.id.to_hex(),
10092                        "name": function.name,
10093                        "file": function.file.display().to_string(),
10094                        "location": {
10095                            "start_line": function.span.start_line,
10096                            "end_line": function.span.end_line
10097                        }
10098                    },
10099                    "description": format!("Function '{}' is part of the {} API surface", function.name, if is_public { "public" } else { "private" }),
10100                    "visibility": if is_public { "public" } else { "private" },
10101                    "external_usage_count": external_usage_count,
10102                    "recommendation": if is_public { "Ensure this function is well-documented and maintains backward compatibility" } else { "Consider if this function should be exposed or kept internal" }
10103                }));
10104            }
10105        }
10106
10107        // Analyze public classes
10108        for class in classes {
10109            if exclude_patterns
10110                .iter()
10111                .any(|pattern| class.file.to_string_lossy().contains(pattern))
10112            {
10113                continue;
10114            }
10115
10116            let class_name = &class.name;
10117            let is_public = self.is_public_api_element(class_name);
10118            let is_private = class_name.starts_with('_') || class_name.contains("Private");
10119
10120            if is_public || (include_private_apis && is_private) {
10121                // Count public methods in the class
10122                let edges = server.graph_store().get_outgoing_edges(&class.id);
10123                let public_methods = edges
10124                    .iter()
10125                    .filter(|edge| {
10126                        if let Some(target_node) = server.graph_store().get_node(&edge.target) {
10127                            target_node.kind == codeprism_core::NodeKind::Method
10128                                && self.is_public_api_element(&target_node.name)
10129                        } else {
10130                            false
10131                        }
10132                    })
10133                    .count();
10134
10135                issues.push(serde_json::json!({
10136                    "type": if is_public { "Public API Class" } else { "Private API Class" },
10137                    "category": "public_api",
10138                    "severity": if is_public { "medium" } else { "low" },
10139                    "class": {
10140                        "id": class.id.to_hex(),
10141                        "name": class.name,
10142                        "file": class.file.display().to_string(),
10143                        "location": {
10144                            "start_line": class.span.start_line,
10145                            "end_line": class.span.end_line
10146                        }
10147                    },
10148                    "description": format!("Class '{}' is part of the {} API surface with {} public methods", class.name, if is_public { "public" } else { "private" }, public_methods),
10149                    "visibility": if is_public { "public" } else { "private" },
10150                    "public_methods_count": public_methods,
10151                    "recommendation": if is_public { "Ensure all public methods are documented and follow API design principles" } else { "Review if this class should be part of the public API" }
10152                }));
10153            }
10154        }
10155
10156        Ok(issues)
10157    }
10158
10159    /// Analyze API versioning concerns
10160    async fn analyze_api_versioning(
10161        &self,
10162        server: &CodePrismMcpServer,
10163        exclude_patterns: &[String],
10164        api_version: Option<&str>,
10165    ) -> Result<Vec<serde_json::Value>> {
10166        let mut issues = Vec::new();
10167        let functions = server
10168            .graph_store()
10169            .get_nodes_by_kind(codeprism_core::NodeKind::Function);
10170
10171        for function in functions {
10172            if exclude_patterns
10173                .iter()
10174                .any(|pattern| function.file.to_string_lossy().contains(pattern))
10175            {
10176                continue;
10177            }
10178
10179            let function_name = &function.name;
10180
10181            // Check for version-related naming patterns
10182            if function_name.contains("_v")
10183                || function_name.contains("V1")
10184                || function_name.contains("V2")
10185                || function_name.contains("version")
10186            {
10187                issues.push(serde_json::json!({
10188                    "type": "Versioned API Function",
10189                    "category": "versioning",
10190                    "severity": "medium",
10191                    "function": {
10192                        "id": function.id.to_hex(),
10193                        "name": function.name,
10194                        "file": function.file.display().to_string(),
10195                        "location": {
10196                            "start_line": function.span.start_line,
10197                            "end_line": function.span.end_line
10198                        }
10199                    },
10200                    "description": format!("Function '{}' appears to be version-specific", function.name),
10201                    "current_api_version": api_version.unwrap_or("unknown"),
10202                    "recommendation": "Ensure versioning strategy is consistent and deprecated versions are properly marked"
10203                }));
10204            }
10205
10206            // Check for deprecated functions
10207            if function_name.contains("deprecated")
10208                || function_name.contains("legacy")
10209                || function_name.contains("old")
10210            {
10211                issues.push(serde_json::json!({
10212                    "type": "Deprecated API Function",
10213                    "category": "versioning",
10214                    "severity": "high",
10215                    "function": {
10216                        "id": function.id.to_hex(),
10217                        "name": function.name,
10218                        "file": function.file.display().to_string(),
10219                        "location": {
10220                            "start_line": function.span.start_line,
10221                            "end_line": function.span.end_line
10222                        }
10223                    },
10224                    "description": format!("Function '{}' appears to be deprecated", function.name),
10225                    "recommendation": "Provide migration path and timeline for removal"
10226                }));
10227            }
10228        }
10229
10230        Ok(issues)
10231    }
10232
10233    /// Detect potential API breaking changes
10234    async fn detect_api_breaking_changes(
10235        &self,
10236        server: &CodePrismMcpServer,
10237        exclude_patterns: &[String],
10238    ) -> Result<Vec<serde_json::Value>> {
10239        let mut issues = Vec::new();
10240        let functions = server
10241            .graph_store()
10242            .get_nodes_by_kind(codeprism_core::NodeKind::Function);
10243
10244        for function in functions {
10245            if exclude_patterns
10246                .iter()
10247                .any(|pattern| function.file.to_string_lossy().contains(pattern))
10248            {
10249                continue;
10250            }
10251
10252            let function_name = &function.name;
10253
10254            // Functions with many parameters might indicate breaking changes if modified
10255            let dependencies = server
10256                .graph_query()
10257                .find_dependencies(&function.id, codeprism_core::graph::DependencyType::Direct)?;
10258            let parameter_like_deps = dependencies
10259                .iter()
10260                .filter(|dep| matches!(dep.target_node.kind, codeprism_core::NodeKind::Variable))
10261                .count();
10262
10263            if parameter_like_deps > 5 && self.is_public_api_element(function_name) {
10264                issues.push(serde_json::json!({
10265                    "type": "Complex API Function",
10266                    "category": "breaking_changes",
10267                    "severity": "medium",
10268                    "function": {
10269                        "id": function.id.to_hex(),
10270                        "name": function.name,
10271                        "file": function.file.display().to_string(),
10272                        "location": {
10273                            "start_line": function.span.start_line,
10274                            "end_line": function.span.end_line
10275                        }
10276                    },
10277                    "description": format!("Function '{}' has {} parameters - changes could break compatibility", function.name, parameter_like_deps),
10278                    "parameter_count": parameter_like_deps,
10279                    "recommendation": "Consider using configuration objects or builder patterns to avoid breaking changes"
10280                }));
10281            }
10282
10283            // Check for functions that might be removing features
10284            if (function_name.contains("remove")
10285                || function_name.contains("delete")
10286                || function_name.contains("drop"))
10287                && self.is_public_api_element(function_name)
10288            {
10289                issues.push(serde_json::json!({
10290                    "type": "Potentially Breaking API Function",
10291                    "category": "breaking_changes",
10292                    "severity": "high",
10293                    "function": {
10294                        "id": function.id.to_hex(),
10295                        "name": function.name,
10296                        "file": function.file.display().to_string(),
10297                        "location": {
10298                            "start_line": function.span.start_line,
10299                            "end_line": function.span.end_line
10300                        }
10301                    },
10302                    "description": format!("Function '{}' might remove functionality - potential breaking change", function.name),
10303                    "recommendation": "Ensure proper deprecation process and provide alternatives"
10304                }));
10305            }
10306        }
10307
10308        Ok(issues)
10309    }
10310
10311    /// Analyze API documentation coverage
10312    async fn analyze_api_documentation_coverage(
10313        &self,
10314        server: &CodePrismMcpServer,
10315        exclude_patterns: &[String],
10316    ) -> Result<Vec<serde_json::Value>> {
10317        let mut issues = Vec::new();
10318        let functions = server
10319            .graph_store()
10320            .get_nodes_by_kind(codeprism_core::NodeKind::Function);
10321
10322        for function in functions {
10323            if exclude_patterns
10324                .iter()
10325                .any(|pattern| function.file.to_string_lossy().contains(pattern))
10326            {
10327                continue;
10328            }
10329
10330            let function_name = &function.name;
10331
10332            // Only check documentation for public API functions
10333            if self.is_public_api_element(function_name) {
10334                // This is a simplified check - in a real implementation, you'd check for actual docstrings/comments
10335                let likely_undocumented = !function_name.contains("test")
10336                    && !function_name.contains("helper")
10337                    && !function_name.starts_with('_');
10338
10339                if likely_undocumented {
10340                    let function_lines = function.span.end_line - function.span.start_line + 1;
10341
10342                    if function_lines > 5 {
10343                        // Only flag substantial functions
10344                        issues.push(serde_json::json!({
10345                            "type": "Undocumented API Function",
10346                            "category": "documentation",
10347                            "severity": "medium",
10348                            "function": {
10349                                "id": function.id.to_hex(),
10350                                "name": function.name,
10351                                "file": function.file.display().to_string(),
10352                                "location": {
10353                                    "start_line": function.span.start_line,
10354                                    "end_line": function.span.end_line
10355                                }
10356                            },
10357                            "description": format!("Public function '{}' may lack adequate documentation", function.name),
10358                            "lines_of_code": function_lines,
10359                            "recommendation": "Add comprehensive documentation including parameters, return values, and usage examples"
10360                        }));
10361                    }
10362                }
10363            }
10364        }
10365
10366        Ok(issues)
10367    }
10368
10369    /// Analyze API compatibility concerns
10370    async fn analyze_api_compatibility(
10371        &self,
10372        server: &CodePrismMcpServer,
10373        exclude_patterns: &[String],
10374        api_version: Option<&str>,
10375    ) -> Result<Vec<serde_json::Value>> {
10376        let mut issues = Vec::new();
10377        let functions = server
10378            .graph_store()
10379            .get_nodes_by_kind(codeprism_core::NodeKind::Function);
10380
10381        for function in functions {
10382            if exclude_patterns
10383                .iter()
10384                .any(|pattern| function.file.to_string_lossy().contains(pattern))
10385            {
10386                continue;
10387            }
10388
10389            let function_name = &function.name;
10390
10391            // Check for functions that might have compatibility issues
10392            if self.is_public_api_element(function_name) {
10393                let references = server.graph_query().find_references(&function.id)?;
10394                let usage_count = references.len();
10395
10396                // Functions with high usage are critical for compatibility
10397                if usage_count > 10 {
10398                    issues.push(serde_json::json!({
10399                        "type": "High-Impact API Function",
10400                        "category": "compatibility",
10401                        "severity": "high",
10402                        "function": {
10403                            "id": function.id.to_hex(),
10404                            "name": function.name,
10405                            "file": function.file.display().to_string(),
10406                            "location": {
10407                                "start_line": function.span.start_line,
10408                                "end_line": function.span.end_line
10409                            }
10410                        },
10411                        "description": format!("Function '{}' has {} usages - changes require careful compatibility planning", function.name, usage_count),
10412                        "usage_count": usage_count,
10413                        "api_version": api_version.unwrap_or("unknown"),
10414                        "recommendation": "Maintain backward compatibility or provide clear migration path"
10415                    }));
10416                }
10417            }
10418        }
10419
10420        Ok(issues)
10421    }
10422
10423    /// Check if an API element is considered public
10424    fn is_public_api_element(&self, name: &str) -> bool {
10425        // This is a simplified heuristic - in practice, you'd use language-specific visibility rules
10426        !name.starts_with('_')
10427            && !name.contains("private")
10428            && !name.contains("internal")
10429            && !name.contains("test")
10430            && !name.contains("helper")
10431            && !name.contains("util")
10432    }
10433
10434    /// Get API recommendations based on found issues
10435    fn get_api_recommendations(&self, issues: &[serde_json::Value]) -> Vec<String> {
10436        let mut recommendations = Vec::new();
10437
10438        let critical_count = issues
10439            .iter()
10440            .filter(|i| i.get("severity").and_then(|s| s.as_str()) == Some("critical"))
10441            .count();
10442
10443        let high_count = issues
10444            .iter()
10445            .filter(|i| i.get("severity").and_then(|s| s.as_str()) == Some("high"))
10446            .count();
10447
10448        if critical_count > 0 {
10449            recommendations.push(format!(
10450                "CRITICAL: Address {} critical API issues immediately",
10451                critical_count
10452            ));
10453        }
10454
10455        if high_count > 0 {
10456            recommendations.push(format!(
10457                "HIGH PRIORITY: Review {} high-impact API concerns",
10458                high_count
10459            ));
10460        }
10461
10462        // Category-specific recommendations
10463        let documentation_count = issues
10464            .iter()
10465            .filter(|i| i.get("category").and_then(|c| c.as_str()) == Some("documentation"))
10466            .count();
10467
10468        if documentation_count > 0 {
10469            recommendations.push(
10470                "Improve API documentation coverage for better developer experience".to_string(),
10471            );
10472        }
10473
10474        let breaking_changes_count = issues
10475            .iter()
10476            .filter(|i| i.get("category").and_then(|c| c.as_str()) == Some("breaking_changes"))
10477            .count();
10478
10479        if breaking_changes_count > 0 {
10480            recommendations.push(
10481                "Review potential breaking changes and implement proper deprecation process"
10482                    .to_string(),
10483            );
10484        }
10485
10486        let versioning_count = issues
10487            .iter()
10488            .filter(|i| i.get("category").and_then(|c| c.as_str()) == Some("versioning"))
10489            .count();
10490
10491        if versioning_count > 0 {
10492            recommendations.push(
10493                "Establish consistent API versioning strategy and migration paths".to_string(),
10494            );
10495        }
10496
10497        let compatibility_count = issues
10498            .iter()
10499            .filter(|i| i.get("category").and_then(|c| c.as_str()) == Some("compatibility"))
10500            .count();
10501
10502        if compatibility_count > 0 {
10503            recommendations
10504                .push("Maintain backward compatibility for high-usage API functions".to_string());
10505        }
10506
10507        if recommendations.is_empty() {
10508            recommendations.push(
10509                "No significant API surface issues detected with current analysis".to_string(),
10510            );
10511        } else {
10512            recommendations
10513                .push("Implement API design guidelines and review processes".to_string());
10514            recommendations
10515                .push("Consider semantic versioning and changelog maintenance".to_string());
10516            recommendations.push("Set up automated API compatibility testing".to_string());
10517        }
10518
10519        recommendations
10520    }
10521}