"""LLM-based parameter extractor implementation."""

import json
from typing import Dict, Any, Optional, List
from ..models.intent_result import ParameterResult
from ..utils.path_resolver import PathResolver


class LLMParameterExtractor:
    """Extract parameters from user input using LLM with structured JSON output."""

    def __init__(self, llm_client: Any, confidence_threshold: float = 0.7, model_name: str = "gpt-4"):
        """Initialize extractor.
        
        Args:
            llm_client: LLM client instance
            confidence_threshold: Minimum confidence for extraction
            model_name: Model name to use
        """
        self.llm = llm_client
        self.confidence_threshold = confidence_threshold
        self.model_name = model_name
        self.path_resolver = PathResolver()

    def _build_extraction_prompt(self, action_id: str, required_params: List[str], system_context: Optional[Dict] = None) -> str:
        """Build prompt for parameter extraction.
        
        Args:
            action_id: Target action identifier
            required_params: List of required parameter names
            system_context: System context with common paths
            
        Returns:
            System prompt for extraction
        """
        examples = {
            "folder.create": "Input: 'create folder test123 in C:/temp' -> {\"name\": \"test123\", \"path\": \"C:/temp\"}",
            "file.copy": "Input: 'copy file_a.txt to file_b.txt' -> {\"source\": \"file_a.txt\", \"destination\": \"file_b.txt\"}",
            "file.move": "Input: 'move doc_x.txt to doc_y.txt' -> {\"source\": \"doc_x.txt\", \"destination\": \"doc_y.txt\"}",
            "file.rename": "Input: 'rename 1.txt to din.txt' -> {\"path\": \"1.txt\", \"new_name\": \"din.txt\"}",
            "file.write": "Input: 'write hello123 to test.txt' -> {\"path\": \"test.txt\", \"content\": \"hello123\"}",
            "file.delete": "Input: 'delete folder test in C:/temp' -> {\"path\": \"C:/temp/test\"}",
            "file.read": "Input: 'read file C:/temp/test.txt' -> {\"path\": \"C:/temp/test.txt\"}",
            "system.volume": "Input: 'mute volume' -> {\"action\": \"mute\"}, Input: 'unmute volume' -> {\"action\": \"unmute\"}",
            "app.install": "Input: 'install facebook' -> {\"app_name\": \"facebook\"}",
            "app.open": "Input: 'open chrome' -> {\"app_name\": \"chrome\"}",
            "app.uninstall": "Input: 'uninstall spotify' -> {\"app_name\": \"spotify\"}"
        }
        example = examples.get(action_id, "")
        
        context_info = ""
        if system_context:
            paths = system_context.get("common_paths", {})
            context_info = f"\n\nSystem Context:\n- Desktop: {paths.get('desktop', 'N/A')}\n- Documents: {paths.get('documents', 'N/A')}\n- Downloads: {paths.get('downloads', 'N/A')}\n- User: {system_context.get('user', 'N/A')}"
        
        return f"""Extract EXACT parameters from user input for: {action_id}

Required: {', '.join(required_params)}

Example: {example}{context_info}

Return ONLY valid JSON:
{{
  "parameters": {{"param1": "value1"}},
  "confidence": 0.95,
  "missing_fields": []
}}

Rules:
- For location shortcuts ("desktop", "documents", "downloads"), resolve to full paths using system context
- For app.install/app.open/app.uninstall: app_name = application name (facebook, chrome, spotify, etc.)
- For system.volume: action = "mute" if user says mute/silence, "unmute" if user says unmute/restore
- Extract EXACT values from input (preserve spelling exactly)
- For file.rename: path = CURRENT filename (before 'to'/'with'), new_name = NEW filename (after 'to'/'with')
  Example: 'rename 1.txt to din.txt' -> path = '1.txt', new_name = 'din.txt'
  Example: 'rename file 1.txt with din.txt' -> path = '1.txt', new_name = 'din.txt'
- For file.delete/file.read: path = FULL path (combine folder name + location)
  Example: 'delete folder test in C:/temp' -> path = 'C:/temp/test'
- For folder.create: name = folder name, path = parent directory
  Example: 'create folder test on desktop' -> name = 'test', path = '<desktop_path>'
- source/destination = exact file paths
- content = exact text content
- DO NOT modify, correct, or interpret values
- If parameter not found, add to missing_fields"""

    async def extract(
        self,
        user_input: str,
        action_id: str,
        required_params: List[str],
        context: Optional[Dict[str, Any]] = None
    ) -> ParameterResult:
        """Extract parameters from user input.
        
        Args:
            user_input: User's natural language input
            action_id: Target action identifier
            required_params: List of required parameter names
            context: Optional context information
            
        Returns:
            ParameterResult with extracted parameters
        """
        system_context = self.path_resolver.get_system_context()
        system_prompt = self._build_extraction_prompt(action_id, required_params, system_context)
        
        messages = [
            {"role": "system", "content": system_prompt},
            {"role": "user", "content": user_input}
        ]

        if context:
            messages.append({"role": "system", "content": f"Context: {json.dumps(context)}"})

        try:
            response = await self._call_llm(messages)
            result = self._parse_response(response, required_params)
            return result
            
        except Exception as e:
            print(f"[DEBUG] Extract exception: {e}")  # Debug
            return ParameterResult(
                parameters={},
                missing_fields=required_params,
                confidence=0.0,
                metadata={"error": str(e)}
            )

    async def _call_llm(self, messages: list) -> str:
        """Call LLM and get response.
        
        Args:
            messages: Conversation messages
            
        Returns:
            LLM response text
        """
        try:
            response = self.llm.chat.completions.create(
                model=self.model_name,
                messages=messages,
                temperature=0.1
            )
            content = response.choices[0].message.content
            return content
        except Exception as e:
            raise

    def _parse_response(self, response: str, required_params: List[str]) -> ParameterResult:
        """Parse LLM JSON response.
        
        Args:
            response: JSON string from LLM
            required_params: List of required parameters
            
        Returns:
            ParameterResult object
        """
        try:
            # Extract JSON from response (handle markdown code blocks)
            if "```json" in response:
                response = response.split("```json")[1].split("```")[0].strip()
            elif "```" in response:
                response = response.split("```")[1].split("```")[0].strip()
            
            # Extract only JSON object (remove text after closing brace)
            import re
            json_match = re.search(r'\{[^{}]*\{[^}]*\}[^{}]*\}', response)
            if json_match:
                response = json_match.group(0)
            
            # Clean up malformed JSON
            response = re.sub(r'0\s+end', '0.95', response)
            response = re.sub(r',\s*}', '}', response)
            response = re.sub(r',\s*]', ']', response)
            
            data = json.loads(response)
            
            parameters = data.get("parameters", {})
            confidence = float(data.get("confidence", 0.0))
            missing = data.get("missing_fields", [])
            
            # Validate all required params are accounted for
            found_params = set(parameters.keys())
            required_set = set(required_params)
            actual_missing = list(required_set - found_params)
            
            return ParameterResult(
                parameters=parameters,
                missing_fields=actual_missing or missing,
                confidence=confidence
            )
            
        except (json.JSONDecodeError, KeyError, ValueError) as e:
            return ParameterResult(
                parameters={},
                missing_fields=required_params,
                confidence=0.0,
                metadata={"parse_error": str(e)}
            )

    def extract_sync(
        self,
        user_input: str,
        action_id: str,
        required_params: List[str],
        context: Optional[Dict[str, Any]] = None
    ) -> ParameterResult:
        """Synchronous version of extract (for testing without async).
        
        Args:
            user_input: User's natural language input
            action_id: Target action identifier
            required_params: List of required parameter names
            context: Optional context information
            
        Returns:
            ParameterResult with extracted parameters
        """
        # Mock implementation for testing
        parameters = {}
        missing = []
        words = user_input.split()
        user_lower = user_input.lower()
        
        # Try to extract JSON from input first
        import re
        json_match = re.search(r'\{[^}]+\}', user_input)
        if json_match:
            try:
                json_data = json.loads(json_match.group(0))
                # Merge JSON data into parameters if keys match required_params
                for key in required_params:
                    if key in json_data:
                        parameters[key] = json_data[key]
            except json.JSONDecodeError:
                pass
        
        # Extract name parameter (for folder.create, file.write)
        if "name" in required_params:
            for i, word in enumerate(words):
                if word.lower() in ["named", "called", "name"]:
                    if i + 1 < len(words):
                        parameters["name"] = words[i + 1]
                        break
            if "name" not in parameters:
                # Try to find a name-like word (not a keyword)
                for word in words:
                    if word.lower() not in ["create", "folder", "file", "in", "at", "to", "from", "a", "the"]:
                        if not ("/" in word or "\\" in word or ":" in word):
                            parameters["name"] = word
                            break
            if "name" not in parameters:
                missing.append("name")
        
        # Extract path parameter with smart resolution
        if "path" in required_params:
            # Special handling for venv/virtualenv - extract full path
            if action_id == "env.setup_virtualenv":
                # Look for full Windows path (D:\... or C:\...)
                for word in words:
                    if (":" in word and "path:" not in word.lower()) or ("\\" in word and len(word) > 5):
                        parameters["path"] = word.replace("\\\\", "\\")
                        break
                # If no full path, look for path after keywords
                if "path" not in parameters:
                    for i, word in enumerate(words):
                        if word.lower() in ["in", "at", "inside", "path:", "path"]:
                            if i + 1 < len(words):
                                path_parts = []
                                for j in range(i + 1, len(words)):
                                    if words[j].lower() not in ["the", "specified", "folder", "directory"]:
                                        path_parts.append(words[j])
                                if path_parts:
                                    parameters["path"] = " ".join(path_parts).replace("\\\\", "\\")
                                    break
                if "path" not in parameters:
                    parameters["path"] = "venv"
            # Special handling for folder.create - extract full path when provided
            elif action_id == "folder.create":
                # Check if full path is provided (D:\... or C:\...)
                for word in words:
                    if (":" in word and "path:" not in word.lower()) or ("\\" in word and len(word) > 10):
                        # This is the parent directory path
                        parameters["path"] = word.replace("\\\\", "\\")
                        break
                # If no full path found, use default search
                if "path" not in parameters:
                    path_found = False
                    for word in words:
                        if "/" in word or "\\" in word or ":" in word:
                            parameters["path"] = word.replace("//", "/").replace("\\\\", "\\")
                            path_found = True
                            break
                    if not path_found:
                        location_keywords = ["desktop", "documents", "downloads", "pictures", "videos", "music", "home", "temp"]
                        for keyword in location_keywords:
                            if keyword in user_lower:
                                parameters["path"] = self.path_resolver.resolve(keyword)
                                path_found = True
                                break
                    if not path_found:
                        missing.append("path")
            # Special handling for file.rename - extract filename BEFORE 'to'/'with'
            elif action_id == "file.rename":
                import os
                source_filename = None
                
                # Find the filename before 'to' or 'with'
                for i, word in enumerate(words):
                    if word.lower() in ["to", "with"]:
                        # Look backwards for filename
                        for j in range(i - 1, -1, -1):
                            if "." in words[j] and not words[j].startswith("."):
                                source_filename = words[j]
                                break
                        break
                
                if source_filename:
                    search_paths = [
                        self.path_resolver.resolve("desktop"),
                        self.path_resolver.resolve("documents"),
                        self.path_resolver.resolve("downloads"),
                        os.getcwd()
                    ]
                    
                    # Search for source file (1 level deep only)
                    found_paths = []
                    for base_path in search_paths:
                        potential_path = os.path.join(base_path, source_filename)
                        if os.path.exists(potential_path):
                            found_paths.append(potential_path)
                        # Check one level deep
                        try:
                            for item in os.listdir(base_path):
                                item_path = os.path.join(base_path, item)
                                if os.path.isdir(item_path):
                                    sub_path = os.path.join(item_path, source_filename)
                                    if os.path.exists(sub_path):
                                        found_paths.append(sub_path)
                        except (PermissionError, OSError):
                            pass
                    
                    if len(found_paths) > 1:
                        parameters["path"] = found_paths[0]
                        parameters["_multiple_matches"] = found_paths
                    elif len(found_paths) == 1:
                        parameters["path"] = found_paths[0]
                    else:
                        parameters["path"] = source_filename
                else:
                    missing.append("path")
            elif action_id.startswith("file.") or action_id.startswith("folder."):
                # Universal file/folder path extraction with smart search
                filename = None
                folder = None
                
                for i, word in enumerate(words):
                    # Look for filename/foldername (has extension or is a name)
                    if "." in word and not word.startswith("."):
                        filename = word
                    elif word.lower() not in ["file", "folder", "in", "the", "a", "create", "delete", "move", "copy", "read"]:
                        if not filename and "/" not in word and "\\" not in word:
                            filename = word
                    # Look for folder context (after "in" keyword)
                    if word.lower() == "in" and i + 1 < len(words):
                        folder = words[i + 1]
                        if folder.lower() == "folder" and i + 2 < len(words):
                            folder = words[i + 2]
                        break
                
                if filename:
                    import os
                    search_paths = [
                        self.path_resolver.resolve("desktop"),
                        self.path_resolver.resolve("documents"),
                        self.path_resolver.resolve("downloads"),
                        os.getcwd()
                    ]
                    
                    if folder:
                        # Search for folder first, then combine with filename
                        found_folder = None
                        for base_path in search_paths:
                            potential_path = os.path.join(base_path, folder)
                            if os.path.exists(potential_path) and os.path.isdir(potential_path):
                                found_folder = potential_path
                                break
                        
                        if found_folder:
                            parameters["path"] = os.path.join(found_folder, filename)
                        else:
                            parameters["path"] = f"{folder}/{filename}"
                    else:
                        # Search for file/folder in common locations (max 2 levels deep)
                        found_paths = []  # Store all matches
                        for base_path in search_paths:
                            # Check directly in base path
                            potential_path = os.path.join(base_path, filename)
                            if os.path.exists(potential_path):
                                found_paths.append(potential_path)
                            # Check one level deep only
                            try:
                                for item in os.listdir(base_path):
                                    item_path = os.path.join(base_path, item)
                                    if os.path.isdir(item_path):
                                        sub_path = os.path.join(item_path, filename)
                                        if os.path.exists(sub_path):
                                            found_paths.append(sub_path)
                            except (PermissionError, OSError):
                                pass
                        
                        if len(found_paths) > 1:
                            # Multiple files found - return error with options
                            parameters["path"] = found_paths[0]
                            parameters["_multiple_matches"] = found_paths
                        elif len(found_paths) == 1:
                            parameters["path"] = found_paths[0]
                        else:
                            parameters["path"] = filename
                else:
                    missing.append("path")
            else:
                # Try to find path-like words or location shortcuts
                path_found = False
                for word in words:
                    if "/" in word or "\\" in word or ":" in word:
                        parameters["path"] = word.replace("//", "/").replace("\\\\", "\\")
                        path_found = True
                        break
                
                # If no explicit path, look for location keywords
                if not path_found:
                    location_keywords = ["desktop", "documents", "downloads", "pictures", "videos", "music", "home", "temp"]
                    for keyword in location_keywords:
                        if keyword in user_lower:
                            parameters["path"] = self.path_resolver.resolve(keyword)
                            path_found = True
                            break
                
                if not path_found:
                    missing.append("path")
        
        # Extract source parameter with smart search
        if "source" in required_params:
            import os
            source_name = None
            source_folder = None
            
            # Find filename (has extension)
            for i, word in enumerate(words):
                if "." in word and not word.startswith("."):
                    source_name = word
                    # Check if folder is specified after filename
                    if i + 1 < len(words) and words[i + 1].lower() == "in" and i + 2 < len(words):
                        source_folder = words[i + 2]
                        if source_folder.lower() == "folder" and i + 3 < len(words):
                            source_folder = words[i + 3]
                    break
            
            if source_name:
                search_paths = [
                    self.path_resolver.resolve("desktop"),
                    self.path_resolver.resolve("documents"),
                    self.path_resolver.resolve("downloads"),
                    os.getcwd()
                ]
                
                if source_folder:
                    # Search for folder first, then combine with filename
                    found_source = None
                    for base_path in search_paths:
                        folder_path = os.path.join(base_path, source_folder)
                        if os.path.exists(folder_path) and os.path.isdir(folder_path):
                            file_path = os.path.join(folder_path, source_name)
                            if os.path.exists(file_path):
                                found_source = file_path
                                break
                    parameters["source"] = found_source if found_source else source_name
                else:
                    # Search for source file (1 level deep only)
                    found_source = None
                    for base_path in search_paths:
                        potential_path = os.path.join(base_path, source_name)
                        if os.path.exists(potential_path):
                            found_source = potential_path
                            break
                        # Check one level deep
                        try:
                            for item in os.listdir(base_path):
                                item_path = os.path.join(base_path, item)
                                if os.path.isdir(item_path):
                                    sub_path = os.path.join(item_path, source_name)
                                    if os.path.exists(sub_path):
                                        found_source = sub_path
                                        break
                        except (PermissionError, OSError):
                            pass
                        if found_source:
                            break
                    parameters["source"] = found_source if found_source else source_name
            else:
                missing.append("source")
        
        # Extract destination parameter with smart resolution
        if "destination" in required_params:
            import os
            for i, word in enumerate(words):
                if word.lower() in ["to", "into", "destination"]:
                    if i + 1 < len(words):
                        dest_name = words[i + 1]
                        # Check if it's a location keyword
                        location_keywords = ["desktop", "documents", "downloads", "pictures", "videos", "music"]
                        if dest_name.lower() in location_keywords:
                            parameters["destination"] = self.path_resolver.resolve(dest_name)
                        else:
                            # Search for destination folder
                            search_paths = [
                                self.path_resolver.resolve("desktop"),
                                self.path_resolver.resolve("documents"),
                                self.path_resolver.resolve("downloads"),
                                os.getcwd()
                            ]
                            found_dest = None
                            for base_path in search_paths:
                                potential_path = os.path.join(base_path, dest_name)
                                if os.path.exists(potential_path) and os.path.isdir(potential_path):
                                    found_dest = potential_path
                                    break
                            parameters["destination"] = found_dest if found_dest else dest_name
                        break
            if "destination" not in parameters:
                missing.append("destination")
        
        # Extract new_name parameter (for file.rename)
        if "new_name" in required_params:
            for i, word in enumerate(words):
                if word.lower() in ["to", "with"]:
                    if i + 1 < len(words):
                        parameters["new_name"] = words[i + 1]
                        break
            if "new_name" not in parameters:
                missing.append("new_name")
        
        # Extract content parameter (for file.write)
        if "content" in required_params:
            for i, word in enumerate(words):
                if word.lower() in ["write", "content"]:
                    if i + 1 < len(words):
                        # Take remaining words as content
                        parameters["content"] = " ".join(words[i + 1:])
                        break
            if "content" not in parameters:
                missing.append("content")
        
        # Extract setting and value parameters (for system.settings)
        if "setting" in required_params:
            if "volume" in user_lower or "sound" in user_lower or "audio" in user_lower:
                parameters["setting"] = "volume"
            elif "internet" in user_lower or "network" in user_lower or "wifi" in user_lower:
                parameters["setting"] = "network"
            else:
                missing.append("setting")
        
        if "value" in required_params:
            if "mute" in user_lower or "off" in user_lower or "disable" in user_lower:
                parameters["value"] = "mute"
            elif "unmute" in user_lower or "on" in user_lower or "enable" in user_lower:
                parameters["value"] = "on"
            else:
                for word in words:
                    if word.isdigit():
                        parameters["value"] = word
                        break
                if "value" not in parameters:
                    missing.append("value")
        
        # Extract action parameter (for system.volume)
        if "action" in required_params:
            if "mute" in user_lower:
                parameters["action"] = "mute"
            elif "unmute" in user_lower:
                parameters["action"] = "unmute"
            elif "set" in user_lower or "change" in user_lower:
                parameters["action"] = "set"
            elif "off" in user_lower or "disable" in user_lower or "turn off" in user_lower:
                parameters["action"] = "off"
            elif "on" in user_lower or "enable" in user_lower or "turn on" in user_lower:
                parameters["action"] = "on"
            else:
                parameters["action"] = "mute"  # default
        
        # Extract app_name parameter
        if "app_name" in required_params:
            app_keywords = ["install", "uninstall", "remove", "update", "open", "launch", "start", "close", "kill", "version", "app", "application", "program"]
            for i, word in enumerate(words):
                if word.lower() in app_keywords and i + 1 < len(words):
                    # Check if next word contains dots (like Spotify.Spotify)
                    if "." in words[i + 1]:
                        parameters["app_name"] = words[i + 1]
                    else:
                        parameters["app_name"] = words[i + 1]
                    break
            if "app_name" not in parameters:
                for word in words:
                    if word.lower() not in app_keywords + ["in", "my", "system", "the", "a"]:
                        parameters["app_name"] = word
                        break
            if "app_name" not in parameters:
                missing.append("app_name")
        
        # Extract file_type parameter
        if "file_type" in required_params:
            for word in words:
                if word.startswith("."):
                    parameters["file_type"] = word
                    break
            if "file_type" not in parameters:
                missing.append("file_type")
        
        # Extract schedule parameter
        if "schedule" in required_params:
            schedule_keywords = ["daily", "weekly", "monthly", "hourly", "startup", "boot", "login"]
            for word in words:
                if word.lower() in schedule_keywords:
                    parameters["schedule"] = word.lower()
                    break
            if "schedule" not in parameters:
                parameters["schedule"] = "daily"  # default
        
        # Extract enabled parameter
        if "enabled" in required_params:
            if "enable" in user_lower or "on" in user_lower:
                parameters["enabled"] = True
            elif "disable" in user_lower or "off" in user_lower:
                parameters["enabled"] = False
            else:
                missing.append("enabled")
        
        # Extract level parameter (for system.volume)
        if "level" in required_params:
            for word in words:
                if word.isdigit():
                    parameters["level"] = int(word)
                    break
        
        # Extract host parameter
        if "host" in required_params:
            for word in words:
                if "." in word or word.lower().startswith("http"):
                    parameters["host"] = word
                    break
            if "host" not in parameters:
                # Look for any word that could be a hostname or IP
                for word in words:
                    if word.lower() not in ["ping", "host", "to", "check", "connectivity", "a", "the"]:
                        parameters["host"] = word
                        break
            if "host" not in parameters:
                missing.append("host")
        

        # Extract project_path parameter
        if "project_path" in required_params:
            # Look for path after keywords
            for i, word in enumerate(words):
                if word.lower() in ["in", "at", "for", "project"]:
                    # Collect remaining words as path
                    remaining = words[i + 1:]
                    if remaining:
                        path = " ".join(remaining)
                        # Check if it looks like a path
                        if "\\" in path or "/" in path or ":" in path:
                            parameters["project_path"] = path
                            break
            # If not found, look for any path-like word
            if "project_path" not in parameters:
                for word in words:
                    if "\\" in word or "/" in word or ":" in word:
                        parameters["project_path"] = word
                        break
            if "project_path" not in parameters:
                missing.append("project_path")
        
        # Extract url parameter (for browser.open)
        if "url" in required_params:
            if "youtube" in user_lower:
                parameters["url"] = "https://youtube.com"
                if "search" in user_lower:
                    search_terms = [w for w in words if w not in ["open", "youtube", "search", "for", "and"]]
                    if search_terms:
                        parameters["query"] = " ".join(search_terms)
            elif "google" in user_lower:
                parameters["url"] = "https://google.com"
            else:
                for word in words:
                    if "http" in word or "www" in word:
                        parameters["url"] = word
                        break
            if "url" not in parameters:
                missing.append("url")
        
        # Extract pattern parameter (for file.search)
        if "pattern" in required_params:
            # Look for filename pattern after 'search', 'for', 'find'
            search_keywords = ["search", "find", "for", "locate"]
            for i, word in enumerate(words):
                if word.lower() in search_keywords and i + 1 < len(words):
                    # Next word is the pattern
                    pattern_word = words[i + 1]
                    # Skip common words
                    if pattern_word.lower() not in ["for", "the", "a", "file", "files", "in", "my"]:
                        parameters["pattern"] = pattern_word
                        break
            
            # If not found, look for any filename-like word
            if "pattern" not in parameters:
                for word in words:
                    if "." in word and not word.startswith("."):
                        parameters["pattern"] = word
                        break
            
            if "pattern" not in parameters:
                missing.append("pattern")
        
        # Extract version parameter (for env.setup_java, env.setup_python, etc.)
        if "version" in required_params:
            for word in words:
                if word.isdigit() or (word.replace(".", "").isdigit()):
                    parameters["version"] = word
                    break
            if "version" not in parameters:
                missing.append("version")
        
        # Extract artifact_path parameter (for deploy.local)
        if "artifact_path" in required_params:
            import os
            import glob
            # Look for file with extension (.jar, .war, .zip, etc.)
            artifact_name = None
            for word in words:
                if "." in word and not word.startswith("."):
                    artifact_name = word
                    break
            
            if not artifact_name:
                # Look for common artifact keywords and search for files
                for word in words:
                    if word.lower() in ["jar", "war", "zip", "tar"]:
                        # Search for any file with this extension
                        search_paths = [
                            os.getcwd(),
                            self.path_resolver.resolve("desktop"),
                            self.path_resolver.resolve("downloads"),
                            self.path_resolver.resolve("documents")
                        ]
                        for base_path in search_paths:
                            pattern = os.path.join(base_path, f"*.{word.lower()}")
                            matches = glob.glob(pattern)
                            if matches:
                                parameters["artifact_path"] = matches[0]
                                break
                        if "artifact_path" in parameters:
                            break
            
            if "artifact_path" not in parameters and artifact_name:
                # Search for artifact in common locations
                search_paths = [
                    os.getcwd(),
                    self.path_resolver.resolve("desktop"),
                    self.path_resolver.resolve("downloads"),
                    self.path_resolver.resolve("documents")
                ]
                
                found_artifact = None
                for base_path in search_paths:
                    potential_path = os.path.join(base_path, artifact_name)
                    if os.path.exists(potential_path):
                        found_artifact = potential_path
                        break
                
                if found_artifact:
                    parameters["artifact_path"] = found_artifact
            
            if "artifact_path" not in parameters:
                missing.append("artifact_path")
        
        # Extract target_path parameter (for deploy.local)
        if "target_path" in required_params:
            import os
            # Look for "to" keyword followed by path
            for i, word in enumerate(words):
                if word.lower() in ["to", "into", "at"]:
                    if i + 1 < len(words):
                        target = words[i + 1]
                        # Check if it's a location keyword
                        if target.lower() in ["desktop", "documents", "downloads"]:
                            parameters["target_path"] = self.path_resolver.resolve(target)
                        elif ":" in target or "\\" in target or "/" in target:
                            parameters["target_path"] = target
                        else:
                            # Assume it's a relative path in current directory
                            parameters["target_path"] = os.path.join(os.getcwd(), target)
                        break
            
            if "target_path" not in parameters:
                # Default to current directory if not specified
                parameters["target_path"] = os.getcwd()
        
        # Extract log_path parameter (for logs.check, logs.clear)
        if "log_path" in required_params:
            # Look for any path-like word (contains : or \ or /)
            for word in words:
                if (":" in word or "\\" in word or "/" in word) and len(word) > 3:
                    parameters["log_path"] = word.replace("/", "\\")
                    break
            if "log_path" not in parameters:
                missing.append("log_path")
        
        # Extract script_path parameter (for script.run) - CHECK BEFORE install_path
        if "script_path" in required_params:
            import os
            # Look for path after "script" keyword - may contain spaces
            script_idx = -1
            for i, word in enumerate(words):
                if word.lower() in ["script", "run"]:
                    script_idx = i
            
            if script_idx >= 0 and script_idx + 1 < len(words):
                # Collect all remaining words as they might form a path with spaces
                remaining = words[script_idx + 1:]
                potential_path = " ".join(remaining)
                
                # Check if it's a valid path
                if os.path.exists(potential_path):
                    parameters["script_path"] = potential_path
                else:
                    # Try to find the longest valid path prefix
                    for i in range(len(remaining), 0, -1):
                        test_path = " ".join(remaining[:i])
                        if os.path.exists(test_path):
                            parameters["script_path"] = test_path
                            break
            
            # Fallback: look for any path-like word
            if "script_path" not in parameters:
                for word in words:
                    if (":" in word or "\\" in word or "/" in word) and len(word) > 3:
                        parameters["script_path"] = word.replace("/", "\\")
                        break
            
            if "script_path" not in parameters:
                missing.append("script_path")
        
        # Extract var_name and var_value parameters (for env.configure_vars)
        if "var_name" in required_params:
            # Look for var_name= or var_name followed by value
            for i, word in enumerate(words):
                if "var_name=" in word.lower():
                    # Handle var_name=value or var_name= value
                    value = word.split("=", 1)[1].strip()
                    if value:  # var_name=value (no space)
                        parameters["var_name"] = value.upper()
                    elif i + 1 < len(words):  # var_name= value (with space)
                        # Collect words until var_value
                        name_parts = []
                        for j in range(i + 1, len(words)):
                            if words[j].lower() in ["var_value", "var_value="] or "var_value=" in words[j].lower():
                                break
                            name_parts.append(words[j])
                        if name_parts:
                            parameters["var_name"] = "_".join(name_parts).upper()
                    break
                elif word.lower() == "var_name" and i + 1 < len(words):
                    # Collect words until we hit var_value or end
                    name_parts = []
                    for j in range(i + 1, len(words)):
                        if words[j].lower() in ["var_value", "var_value="] or "var_value=" in words[j].lower():
                            break
                        name_parts.append(words[j])
                    if name_parts:
                        parameters["var_name"] = "_".join(name_parts).upper()
                    break
            if "var_name" not in parameters:
                missing.append("var_name")
        
        if "var_value" in required_params:
            # Look for var_value= or var_value followed by value
            for i, word in enumerate(words):
                if "var_value=" in word.lower():
                    # Handle var_value=value or var_value= value
                    value = word.split("=", 1)[1].strip()
                    if value:  # var_value=value (no space)
                        parameters["var_value"] = value
                    elif i + 1 < len(words):  # var_value= value (with space)
                        parameters["var_value"] = " ".join(words[i + 1:])
                    break
                elif word.lower() == "var_value" and i + 1 < len(words):
                    # Collect remaining words as value
                    parameters["var_value"] = " ".join(words[i + 1:])
                    break
            if "var_value" not in parameters:
                missing.append("var_value")
        
        # Extract install_path parameter (for env.setup_java, etc.) - ONLY if it's a required param
        if "install_path" in required_params:
            # Look for Windows-style paths - any word containing a colon (like D: or C:)
            for word in words:
                if ":" in word and len(word) > 2:  # Must be more than just "D:"
                    # Make sure it's not part of a URL (http:// or postgresql://)
                    if not word.lower().startswith(("http:", "https:", "ftp:", "postgresql:", "mysql:", "mongodb:")):
                        parameters["install_path"] = word.replace("/", "\\")
                        break
            # install_path is optional, don't add to missing if not found
        
        # Extract repository_path parameter (for git.pull)
        if "repository_path" in required_params or "repo_path" in required_params:
            import os
            param_name = "repository_path" if "repository_path" in required_params else "repo_path"
            
            # Look for local path first
            for word in words:
                # Check if it's a local path (but not a URL)
                if ("\\" in word or ("/" in word and not word.startswith(("http:", "https:", "git@")))) and ":" in word:
                    parameters[param_name] = word
                    break
            
            # If no local path found, check for git URL
            if param_name not in parameters:
                for word in words:
                    if "github.com" in word.lower() or "gitlab.com" in word.lower() or "bitbucket.org" in word.lower() or word.endswith(".git"):
                        parameters["_git_url"] = word  # Store URL for reference
                        
                        # Search upward for git repository root
                        current = os.getcwd()
                        while current:
                            if os.path.exists(os.path.join(current, ".git")):
                                parameters[param_name] = current
                                break
                            parent = os.path.dirname(current)
                            if parent == current:  # Reached root
                                break
                            current = parent
                        
                        # If no git repo found, use current directory
                        if param_name not in parameters:
                            parameters[param_name] = os.getcwd()
                        break
            
            # If still not found, use current directory as default
            if param_name not in parameters:
                parameters[param_name] = os.getcwd()
        
        # Extract branch parameter (for git operations) - always extract if present
        for i, word in enumerate(words):
            if "branch=" in word.lower():
                parameters["branch"] = word.split("=", 1)[1]
                break
            elif word.lower() == "branch" and i + 1 < len(words):
                parameters["branch"] = words[i + 1]
                break
        
        # Extract remote parameter (for git operations) - always extract if present
        for i, word in enumerate(words):
            if "remote=" in word.lower():
                parameters["remote"] = word.split("=", 1)[1]
                break
            elif word.lower() == "remote" and i + 1 < len(words):
                parameters["remote"] = words[i + 1]
                break
        
        # Extract port parameter (for firewall.open_port, network operations)
        if "port" in required_params:
            for word in words:
                if word.isdigit() and 1 <= int(word) <= 65535:
                    parameters["port"] = int(word)
                    break
            if "port" not in parameters:
                missing.append("port")
        
        # Extract username parameter (for user operations)
        if "username" in required_params:
            # Look for username=value or username value patterns
            for i, word in enumerate(words):
                if "username=" in word.lower():
                    parameters["username"] = word.split("=", 1)[1]
                    break
                elif word.lower() == "username" and i + 1 < len(words):
                    parameters["username"] = words[i + 1]
                    break
            if "username" not in parameters:
                missing.append("username")
        
        # Extract new_password parameter (for user.change_password) - ALWAYS try to extract
        # Look for new_password=value or password=value patterns
        for word in words:
            if "new_password=" in word.lower():
                parameters["new_password"] = word.split("=", 1)[1]
                break
            elif "password=" in word.lower() and "new_password" not in parameters:
                parameters["new_password"] = word.split("=", 1)[1]
                break
        
        confidence = 0.8 if not missing else 0.4
        
        return ParameterResult(
            parameters=parameters,
            missing_fields=missing,
            confidence=confidence
        )
