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