#!/usr/bin/env python3
#
# Copyright (c) 2025 Stormux
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.

"""AI providers for the AI Assistant plugin."""

import logging
import json
import requests
from abc import ABC, abstractmethod

logger = logging.getLogger(__name__)

class AIProvider(ABC):
    """Abstract base class for AI providers."""
    
    def __init__(self, api_key=None, model=None, **kwargs):
        self.api_key = api_key
        self.model = model
        self.kwargs = kwargs
        
    @abstractmethod
    def describe_screen(self, screenshot_data, accessibility_data):
        """Generate a description of the current screen."""
        pass
        
    @abstractmethod
    def answer_question(self, question, screenshot_data, accessibility_data):
        """Answer a question about the current screen/focus."""
        pass
        
    @abstractmethod
    def suggest_actions(self, request, screenshot_data, accessibility_data):
        """Suggest actions to accomplish a user's request."""
        pass
        
    @abstractmethod
    def analyze_images(self, user_question, screenshot_data, accessibility_data):
        """Analyze images visible on screen, focusing on visual content rather than UI elements."""
        pass
        
    def _prepare_system_prompt(self, task_type):
        """Prepare system prompt based on task type."""
        if task_type == "image":
            base_prompt = """You are an AI assistant helping a screen reader user analyze image files. You have access to a single image file that the user has selected for analysis.

The user is using the Cthulhu screen reader, so they cannot see images visually. Your task is to provide detailed visual descriptions of the image content to make it accessible.

"""
        else:
            base_prompt = """You are an AI assistant helping a screen reader user navigate and interact with computer applications. You have access to:

1. A screenshot of the current screen
2. Detailed accessibility tree information about UI elements
3. Information about the currently focused element

The user is using the Cthulhu screen reader, so they cannot see the screen visually. Your responses should be clear, concise, and focused on accessibility.
**Critical**: If there are any codes, or information like an ID, be sure to include it in your output.

"""
        
        if task_type == "describe":
            return base_prompt + """Your task: Provide a clear, structured description of what's on the screen. Focus on:
- Main UI elements and their layout
- Current focus location
- Available actions and navigation options
- Any important visual information not captured in accessibility data

Keep descriptions concise but informative."""

        elif task_type == "question":
            return base_prompt + """Your task: Answer the user's question about the current screen or focused element. Use both the screenshot and accessibility data to provide accurate, helpful information.

Be specific and actionable in your responses."""

        elif task_type == "action":
            return base_prompt + """Your task: I WILL EXECUTE THE ACTION IMMEDIATELY - provide the structured response format only.

🚨 CRITICAL RULES:
- I am the action execution system - I WILL perform the action, not give instructions
- NEVER provide programming code, implementation steps, or "how to" instructions  
- NEVER mention ASCII codes, KEY_DOWN events, or technical implementation details
- Always use ACTION TYPE: COPY, TYPE, CLICK, SCROLL, or NAVIGATE
- Be direct about what I will do

STRICT ACTION TYPE MAPPING:
- "find [element] and enter [text]" → ACTION TYPE: TYPE (I will locate element and type text)
- "type [text]" → ACTION TYPE: TYPE (I will type the specified text)
- "copy [text] to clipboard" → ACTION TYPE: COPY (I will copy to clipboard)
- "click [element]" → ACTION TYPE: CLICK (I will click the element)

MANDATORY RESPONSE FORMAT:

**ACTION ANALYSIS**: I will [specific action] 
**TARGET ELEMENT**: [element description]
**ACTION TYPE**: [TYPE/COPY/CLICK/SCROLL/NAVIGATE]
**SAFETY CHECK**: [any concerns]  
**STEP-BY-STEP**: What I will execute (NO CODE, NO IMPLEMENTATION DETAILS)

Example for "find edit box and enter text":
**ACTION ANALYSIS**: I will locate the edit box and type the specified text into it
**TARGET ELEMENT**: Text input field ("What's on your mind?" edit box)
**ACTION TYPE**: TYPE
**SAFETY CHECK**: This will input text into the focused text field
**STEP-BY-STEP**: 
1. Locate the edit box in the interface
2. Focus on the edit box
3. Type the requested text into the field

🚨 NEVER GIVE PROGRAMMING CODE OR TECHNICAL INSTRUCTIONS"""

        elif task_type == "image":
            return base_prompt + """Your task: Analyze and describe any images visible on the screen, focusing on visual content rather than UI elements.

IMPORTANT IMAGE ANALYSIS GUIDELINES:
- Focus ONLY on the visual content of images (photos, diagrams, graphics, artwork)
- IGNORE UI elements like buttons, menus, toolbars, window frames
- Describe what you see IN the images: objects, people, scenes, colors, text within images
- If multiple images are visible, describe each one separately
- For photographs: describe the scene, subjects, lighting, composition
- For diagrams/charts: describe the data, relationships, labels shown
- For screenshots within images: describe the content being shown
- Be detailed about visual elements that a screen reader user cannot access

If no images are clearly visible on screen, say so clearly.

Keep descriptions informative and well-structured."""

        return base_prompt



class ClaudeCodeProvider(AIProvider):
    """Claude Code CLI provider - uses installed Claude Code application."""
    
    def __init__(self, **kwargs):
        super().__init__(**kwargs)  
        # No API key needed - uses Claude Code CLI directly
        
    def describe_screen(self, screenshot_data, accessibility_data):
        """Generate a description using Claude Code CLI."""
        try:
            prompt = self._build_prompt("describe", None, accessibility_data)
            return self._call_claude_code(prompt)
        except Exception as e:
            logger.error(f"Claude Code describe error: {e}")
            return f"Error getting screen description: {e}"
            
    def answer_question(self, question, screenshot_data, accessibility_data):
        """Answer a question using Claude Code CLI."""
        try:
            prompt = self._build_prompt("question", question, accessibility_data)
            return self._call_claude_code(prompt)
        except Exception as e:
            logger.error(f"Claude Code question error: {e}")
            return f"Error answering question: {e}"
            
    def suggest_actions(self, request, screenshot_data, accessibility_data):
        """Suggest actions using Claude Code CLI."""
        try:
            prompt = self._build_prompt("action", request, accessibility_data)
            return self._call_claude_code(prompt)
        except Exception as e:
            logger.error(f"Claude Code action error: {e}")
            return f"Error suggesting actions: {e}"
            
    def analyze_images(self, user_question, screenshot_data, accessibility_data):
        """Analyze images visible on screen using Claude Code CLI."""
        try:
            prompt = self._build_prompt("image", user_question, accessibility_data)
            
            # If we have image data, save it to a temporary file for Claude Code
            temp_image_path = None
            if screenshot_data:
                import tempfile
                import base64
                import os
                
                # Create temporary file with appropriate extension
                image_format = screenshot_data.get('format', 'png')
                suffix = f".{image_format}"
                
                with tempfile.NamedTemporaryFile(delete=False, suffix=suffix) as temp_file:
                    # Decode base64 image data and write to temp file
                    image_data = base64.b64decode(screenshot_data['data'])
                    temp_file.write(image_data)
                    temp_image_path = temp_file.name
                
                try:
                    # Call Claude Code with the image file path
                    result = self._call_claude_code(prompt, temp_image_path)
                    return result
                finally:
                    # Clean up temporary file
                    if os.path.exists(temp_image_path):
                        os.unlink(temp_image_path)
            else:
                # No image data, just call with text prompt
                return self._call_claude_code(prompt)
                
        except Exception as e:
            logger.error(f"Claude Code image analysis error: {e}")
            return f"Error analyzing images: {e}"
            
    def _build_prompt(self, task_type, user_input, accessibility_data):
        """Build the complete prompt for Claude Code."""
        import json
        
        system_prompt = self._get_system_prompt(task_type)
        
        if task_type == "image":
            # For image analysis, minimize accessibility data weight
            if user_input == "ANALYZE_SINGLE_IMAGE_FILE":
                prompt = f"{system_prompt}\n\nAnalyze and describe the single image file provided. Focus on visual content only - describe what you see in the image: objects, people, scenery, colors, text, composition, and any other visual details."
            else:
                prompt = f"{system_prompt}\n\nCurrent screen context (focus on images):\n"
                if user_input:
                    prompt += f"User question about images: {user_input}\n\n"
                prompt += "Analyze and describe any images visible on this screen. Focus on visual content, not UI elements."
        else:
            # Standard prompt with full accessibility data
            prompt = f"{system_prompt}\n\nCurrent accessibility information:\n```json\n{json.dumps(accessibility_data, indent=2)}\n```\n\n"
            
            if task_type == "describe":
                prompt += "Please describe what's on this screen."
            elif task_type == "question":
                prompt += f"User question: {user_input}"
            elif task_type == "action":
                prompt += f"User wants to: {user_input}\n\nProvide the action analysis in the required format."
            
        return prompt
        
    def _call_claude_code(self, prompt, image_path=None):
        """Call Claude Code CLI with the prompt and optional image."""
        import subprocess
        import tempfile
        import os
        
        try:
            # Build the command
            cmd = ['claude', '--print', '--output-format', 'text']
            
            # For accessibility analysis, skip permission checks to allow automatic access
            cmd.append('--dangerously-skip-permissions')
            
            # If we have an image path, include it in the prompt
            if image_path:
                prompt = f"Please analyze and describe the image at {image_path}. {prompt}"
            
            # Add the prompt
            cmd.append(prompt)
            
            # Call Claude Code CLI
            result = subprocess.run(
                cmd,
                capture_output=True,
                text=True,
                timeout=120  # Longer timeout for image analysis
            )
            
            if result.returncode == 0:
                return result.stdout.strip()
            else:
                error_msg = f"Claude Code CLI error: {result.stderr}"
                logger.error(error_msg)
                return error_msg
                
        except subprocess.TimeoutExpired:
            error_msg = "Claude Code CLI timed out"
            logger.error(error_msg)
            return error_msg
        except Exception as e:
            error_msg = f"Error calling Claude Code CLI: {e}"
            logger.error(error_msg)
            return error_msg
    
    def _get_system_prompt(self, task_type):
        """Get system prompt for Claude Code."""
        if task_type == "image":
            base_prompt = """You are Claude Code helping a screen reader user analyze image files. You have access to a single image file that the user has selected for analysis.

The user is using the Cthulhu screen reader and cannot see images visually. Provide detailed visual descriptions of the image content to make it accessible.

"""
        else:
            base_prompt = """You are Claude Code helping a screen reader user navigate and interact with computer applications. You have expert understanding of terminal commands, programming, and accessibility.

The user is using the Cthulhu screen reader and cannot see the screen visually. Provide expert technical assistance.

"""
        
        if task_type == "action":
            return base_prompt + """CRITICAL: I WILL EXECUTE THE ACTION IMMEDIATELY.

🚨 EXPERT COMMAND UNDERSTANDING:
- "type echo 'hello world'" → Extract exactly: echo 'hello world'
- "run ls -la" → Extract exactly: ls -la  
- "execute ./configure --prefix=/usr" → Extract exactly: ./configure --prefix=/usr

MANDATORY FORMAT:
**ACTION ANALYSIS**: I will [specific action]
**TARGET ELEMENT**: [element description] 
**ACTION TYPE**: [TYPE/COPY/CLICK/SCROLL/NAVIGATE]
**SAFETY CHECK**: [assessment]
**STEP-BY-STEP**: What I will execute"""

        elif task_type == "describe":
            return base_prompt + "Provide technical descriptions focusing on development tools, terminals, and accessibility elements."

        elif task_type == "question":
            return base_prompt + "Answer with expert technical knowledge about programming, terminals, and system operations."
            
        elif task_type == "image":
            return base_prompt + """Your task: Analyze and describe any images visible on the screen, focusing on visual content rather than UI elements.

IMPORTANT IMAGE ANALYSIS GUIDELINES:
- Focus ONLY on the visual content of images (photos, diagrams, graphics, artwork)
- IGNORE UI elements like buttons, menus, toolbars, window frames
- Describe what you see IN the images: objects, people, scenes, colors, text within images
- If multiple images are visible, describe each one separately
- For photographs: describe the scene, subjects, lighting, composition
- For diagrams/charts: describe the data, relationships, labels shown
- For screenshots within images: describe the content being shown
- Be detailed about visual elements that a screen reader user cannot access

If no images are clearly visible on screen, say so clearly.

Keep descriptions informative and well-structured."""

        return base_prompt


class CodexProvider(AIProvider):
    """Codex CLI provider - uses installed Codex CLI."""

    def __init__(self, codex_path=None, **kwargs):
        super().__init__(**kwargs)
        self.codex_path = codex_path or self._resolve_codex_path()

    def describe_screen(self, screenshot_data, accessibility_data):
        """Generate a description using Codex CLI."""
        try:
            prompt = self._build_prompt("describe", None, accessibility_data)
            return self._call_codex(prompt, screenshot_data)
        except Exception as e:
            logger.error(f"Codex describe error: {e}")
            return f"Error getting screen description: {e}"

    def answer_question(self, question, screenshot_data, accessibility_data):
        """Answer a question using Codex CLI."""
        try:
            prompt = self._build_prompt("question", question, accessibility_data)
            return self._call_codex(prompt, screenshot_data)
        except Exception as e:
            logger.error(f"Codex question error: {e}")
            return f"Error answering question: {e}"

    def suggest_actions(self, request, screenshot_data, accessibility_data):
        """Suggest actions using Codex CLI."""
        try:
            prompt = self._build_prompt("action", request, accessibility_data)
            return self._call_codex(prompt, screenshot_data)
        except Exception as e:
            logger.error(f"Codex action error: {e}")
            return f"Error suggesting actions: {e}"

    def analyze_images(self, user_question, screenshot_data, accessibility_data):
        """Analyze images visible on screen using Codex CLI."""
        try:
            prompt = self._build_prompt("image", user_question, accessibility_data)
            return self._call_codex(prompt, screenshot_data)
        except Exception as e:
            logger.error(f"Codex image analysis error: {e}")
            return f"Error analyzing images: {e}"

    def _build_prompt(self, task_type, user_input, accessibility_data):
        """Build the complete prompt for Codex CLI."""
        system_prompt = self._prepare_system_prompt(task_type)

        if task_type == "image":
            if user_input == "ANALYZE_SINGLE_IMAGE_FILE":
                prompt = (
                    f"{system_prompt}\n\nAnalyze and describe the single image file provided. "
                    "Focus on visual content only - describe what you see in the image: objects, "
                    "people, scenery, colors, text, composition, and any other visual details."
                )
            else:
                prompt = f"{system_prompt}\n\nCurrent screen context (focus on images):\n"
                if user_input:
                    prompt += f"User question about images: {user_input}\n\n"
                prompt += "Analyze and describe any images visible on this screen. Focus on visual content, not UI elements."
        else:
            prompt = (
                f"{system_prompt}\n\nCurrent accessibility information:\n"
                f"```json\n{json.dumps(accessibility_data, indent=2)}\n```\n\n"
            )

            if task_type == "describe":
                prompt += "Please describe what's on this screen."
            elif task_type == "question":
                prompt += f"User question: {user_input}"
            elif task_type == "action":
                prompt += f"User wants to: {user_input}\n\nProvide the action analysis in the required format."

        return prompt

    def _resolve_codex_path(self):
        import shutil
        import os

        codex_path = shutil.which('codex')
        if not codex_path and os.path.isfile('/usr/bin/codex'):
            codex_path = '/usr/bin/codex'
        return codex_path

    def _call_codex(self, prompt, screenshot_data):
        """Call Codex CLI with the prompt and optional image."""
        import subprocess
        import tempfile
        import os
        import base64

        if not self.codex_path:
            return "Codex CLI not found"

        output_path = None
        image_path = None
        try:
            # Write screenshot to a temp file if available
            if screenshot_data:
                image_format = screenshot_data.get('format', 'png')
                suffix = f".{image_format}"
                with tempfile.NamedTemporaryFile(delete=False, suffix=suffix) as temp_file:
                    image_data = base64.b64decode(screenshot_data['data'])
                    temp_file.write(image_data)
                    image_path = temp_file.name

            with tempfile.NamedTemporaryFile(delete=False) as output_file:
                output_path = output_file.name

            cmd = [
                self.codex_path,
                'exec',
                '--skip-git-repo-check',
                '--color',
                'never',
                '--output-last-message',
                output_path,
                '-'
            ]

            if image_path:
                cmd.extend(['-i', image_path])

            result = subprocess.run(
                cmd,
                input=prompt,
                capture_output=True,
                text=True,
                timeout=120
            )

            if result.returncode != 0:
                error_msg = result.stderr.strip() or result.stdout.strip() or "Codex CLI error"
                logger.error(error_msg)
                return f"Codex CLI error: {error_msg}"

            response_text = ""
            if output_path and os.path.exists(output_path):
                with open(output_path, 'r') as f:
                    response_text = f.read().strip()

            if not response_text:
                response_text = result.stdout.strip()

            return response_text or "No response from Codex"

        except subprocess.TimeoutExpired:
            error_msg = "Codex CLI timed out"
            logger.error(error_msg)
            return error_msg
        except Exception as e:
            error_msg = f"Error calling Codex CLI: {e}"
            logger.error(error_msg)
            return error_msg
        finally:
            if image_path and os.path.exists(image_path):
                try:
                    os.unlink(image_path)
                except Exception:
                    pass
            if output_path and os.path.exists(output_path):
                try:
                    os.unlink(output_path)
                except Exception:
                    pass


class OllamaProvider(AIProvider):
    """Ollama local AI provider."""
    
    def __init__(self, model="llama3.2-vision", base_url="http://localhost:11434", **kwargs):
        super().__init__(model=model, **kwargs)
        self.base_url = base_url
        
    def describe_screen(self, screenshot_data, accessibility_data):
        """Generate a description using Ollama."""
        try:
            prompt = self._build_prompt("describe", None, accessibility_data)
            return self._make_request(prompt, screenshot_data)
        except Exception as e:
            logger.error(f"Ollama describe error: {e}")
            return f"Error getting screen description: {e}"
            
    def answer_question(self, question, screenshot_data, accessibility_data):
        """Answer a question using Ollama."""
        try:
            prompt = self._build_prompt("question", question, accessibility_data)
            return self._make_request(prompt, screenshot_data)
        except Exception as e:
            logger.error(f"Ollama question error: {e}")
            return f"Error answering question: {e}"
            
    def suggest_actions(self, request, screenshot_data, accessibility_data):
        """Suggest actions using Ollama."""
        try:
            prompt = self._build_prompt("action", request, accessibility_data)
            return self._make_request(prompt, screenshot_data)
        except Exception as e:
            logger.error(f"Ollama action error: {e}")
            return f"Error suggesting actions: {e}"
            
    def analyze_images(self, user_question, screenshot_data, accessibility_data):
        """Analyze images visible on screen using Ollama."""
        try:
            prompt = self._build_prompt("image", user_question, accessibility_data)
            return self._make_request(prompt, screenshot_data)
        except Exception as e:
            logger.error(f"Ollama image analysis error: {e}")
            return f"Error analyzing images: {e}"
            
    def _build_prompt(self, task_type, user_input, accessibility_data):
        """Build the complete prompt for Ollama."""
        system_prompt = self._prepare_system_prompt(task_type)
        
        if task_type == "image":
            # For image analysis, minimize accessibility data weight
            if user_input == "ANALYZE_SINGLE_IMAGE_FILE":
                prompt = f"{system_prompt}\n\nAnalyze and describe the single image file provided. Focus on visual content only - describe what you see in the image: objects, people, scenery, colors, text, composition, and any other visual details."
            else:
                prompt = f"{system_prompt}\n\nCurrent screen context (focus on images):\n"
                if user_input:
                    prompt += f"User question about images: {user_input}\n\n"
                prompt += "Analyze and describe any images visible on this screen. Focus on visual content, not UI elements."
        else:
            # Standard prompt with full accessibility data
            prompt = f"{system_prompt}\n\nCurrent accessibility information:\n```json\n{json.dumps(accessibility_data, indent=2)}\n```\n\n"
            
            if task_type == "describe":
                prompt += "Please describe what's on this screen."
            elif task_type == "question":
                prompt += f"User question: {user_input}"
            elif task_type == "action":
                prompt += f"User wants to: {user_input}\n\nPlease suggest specific steps to accomplish this."
            
        return prompt
        
    def _make_request(self, prompt, screenshot_data):
        """Make request to Ollama API."""
        try:
            # For Ollama, we'll use the generate endpoint
            payload = {
                "model": self.model,
                "prompt": prompt,
                "stream": False
            }
            
            # Add image data if available and model supports vision
            if screenshot_data and "vision" in self.model.lower():
                payload["images"] = [screenshot_data['data']]
            
            # Use longer timeout for vision models as they're much slower
            timeout = 180 if screenshot_data and "vision" in self.model.lower() else 60
            
            response = requests.post(
                f"{self.base_url}/api/generate",
                json=payload,
                timeout=timeout
            )
            
            if response.status_code == 200:
                result = response.json()
                return result.get('response', 'No response from Ollama')
            else:
                error_msg = f"Ollama API error {response.status_code}: {response.text}"
                logger.error(error_msg)
                return error_msg
                
        except requests.RequestException as e:
            error_msg = f"Network error contacting Ollama: {e}"
            logger.error(error_msg)
            return error_msg
        except Exception as e:
            error_msg = f"Unexpected error with Ollama API: {e}"
            logger.error(error_msg)
            return error_msg


class GeminiProvider(AIProvider):
    """Google Gemini AI provider using Google's Gemini API."""
    
    def __init__(self, api_key, model="gemini-1.5-flash", **kwargs):
        super().__init__(api_key, model, **kwargs)
        self.base_url = f"https://generativelanguage.googleapis.com/v1beta/models/{self.model}:generateContent"
        
    def describe_screen(self, screenshot_data, accessibility_data):
        """Generate a description using Gemini."""
        try:
            prompt = self._build_prompt("describe", None, accessibility_data)
            return self._make_request(prompt, screenshot_data)
        except Exception as e:
            logger.error(f"Gemini describe error: {e}")
            return f"Error getting screen description: {e}"
            
    def answer_question(self, question, screenshot_data, accessibility_data):
        """Answer a question using Gemini."""
        try:
            prompt = self._build_prompt("question", question, accessibility_data)
            return self._make_request(prompt, screenshot_data)
        except Exception as e:
            logger.error(f"Gemini question error: {e}")
            return f"Error answering question: {e}"
            
    def suggest_actions(self, request, screenshot_data, accessibility_data):
        """Suggest actions using Gemini."""
        try:
            prompt = self._build_prompt("action", request, accessibility_data)
            return self._make_request(prompt, screenshot_data)
        except Exception as e:
            logger.error(f"Gemini action error: {e}")
            return f"Error suggesting actions: {e}"
            
    def analyze_images(self, user_question, screenshot_data, accessibility_data):
        """Analyze images visible on screen using Gemini."""
        try:
            prompt = self._build_prompt("image", user_question, accessibility_data)
            return self._make_request(prompt, screenshot_data)
        except Exception as e:
            logger.error(f"Gemini image analysis error: {e}")
            return f"Error analyzing images: {e}"
            
    def _build_prompt(self, task_type, user_input, accessibility_data):
        """Build the complete prompt for Gemini."""
        system_prompt = self._prepare_system_prompt(task_type)
        
        if task_type == "image":
            if user_input == "ANALYZE_SINGLE_IMAGE_FILE":
                prompt = f"{system_prompt}\n\nAnalyze and describe the single image file provided. Focus on visual content only - describe what you see in the image: objects, people, scenery, colors, text, composition, and any other visual details."
            else:
                prompt = f"{system_prompt}\n\nCurrent screen context (focus on images):\n"
                if user_input:
                    prompt += f"User question about images: {user_input}\n\n"
                prompt += "Analyze and describe any images visible on this screen. Focus on visual content, not UI elements."
        else:
            prompt = f"{system_prompt}\n\nCurrent accessibility information:\n```json\n{json.dumps(accessibility_data, indent=2)}\n```\n\n"
            
            if task_type == "describe":
                prompt += "Please describe what's on this screen."
            elif task_type == "question":
                prompt += f"User question: {user_input}"
            elif task_type == "action":
                prompt += f"User wants to: {user_input}\n\nPlease suggest specific steps to accomplish this."
            
        return prompt
        
    def _make_request(self, prompt, screenshot_data):
        """Make request to Gemini API."""
        try:
            parts = [{"text": prompt}]
            
            # Add image if available
            if screenshot_data:
                parts.append({
                    "inline_data": {
                        "mime_type": f"image/{screenshot_data['format']}",
                        "data": screenshot_data['data']
                    }
                })
            
            payload = {
                "contents": [{
                    "parts": parts
                }]
            }
            
            response = requests.post(
                f"{self.base_url}?key={self.api_key}",
                headers={"Content-Type": "application/json"},
                json=payload,
                timeout=30
            )
            
            if response.status_code == 200:
                result = response.json()
                if 'candidates' in result and len(result['candidates']) > 0:
                    return result['candidates'][0]['content']['parts'][0]['text']
                else:
                    return "No response from Gemini"
            else:
                error_msg = f"Gemini API error {response.status_code}: {response.text}"
                logger.error(error_msg)
                return error_msg
                
        except requests.RequestException as e:
            error_msg = f"Network error contacting Gemini: {e}"
            logger.error(error_msg)
            return error_msg
        except Exception as e:
            error_msg = f"Unexpected error with Gemini API: {e}"
            logger.error(error_msg)
            return error_msg


def create_provider(provider_type, **kwargs):
    """Factory function to create AI providers."""
    if provider_type == "claude_code":
        return ClaudeCodeProvider(**kwargs)
    elif provider_type == "codex":
        return CodexProvider(**kwargs)
    elif provider_type == "ollama":
        return OllamaProvider(**kwargs)
    elif provider_type == "gemini":
        return GeminiProvider(**kwargs)
    else:
        raise ValueError(f"Unknown provider type: {provider_type}")
