"""Profile command extension with OpenAI wizard and validation.

This module extends the profile command functionality with:
- OpenAI profile creation wizard with step-by-step prompts
- Masked API key input (shows first 3 chars + ... + last 4 chars)
- Profile validation using Phase 7a config extension
- Profile testing with optional API call
- Provider auto-detection from API key format
- Support for Azure OpenAI profiles

Phase 7c: Profile Command Extension (200-250 lines)
"""

import asyncio
import logging
import re
from typing import Any, Dict, Optional, List
from dataclasses import dataclass

from ..config.loader import (
    ConfigurationValidationError,
    detect_provider_from_api_key,
    validate_provider_type,
    validate_openai_config,
    mask_api_key,
)
from ..config.migration import detect_provider_from_profile
from ..events.models import CommandResult, CommandCategory


logger = logging.getLogger(__name__)


# =============================================================================
# Data Classes for Profile Wizard
# =============================================================================

@dataclass
class ProfileWizardState:
    """State for profile creation wizard."""
    step: int = 0
    profile_name: str = ""
    provider: str = "auto"
    api_key: str = ""
    model: str = "gpt-4"
    temperature: float = 0.7
    max_tokens: int = 4096
    base_url: str = ""
    organization: str = ""
    # Advanced settings
    description: str = ""
    timeout: int = 0  # 0 means no timeout (infinity)
    supports_tools: bool = True
    streaming: bool = True
    errors: List[str] = None
    configure_advanced: bool = False  # Whether user wants advanced settings

    def __post_init__(self):
        if self.errors is None:
            self.errors = []


# =============================================================================
# Profile Wizard Configuration
# =============================================================================

class ProfileWizardConfig:
    """Configuration for profile creation wizard."""

    # Basic wizard steps (in order)
    BASIC_STEPS = [
        "profile_name",
        "provider",
        "api_key",
        "model",
        "temperature",
        "max_tokens",
        "base_url",
        "organization",
    ]

    # Advanced steps (shown after advanced_settings_prompt if user chooses yes)
    ADVANCED_STEPS = [
        "description",
        "timeout",
        "supports_tools",
        "streaming",
    ]

    @property
    def WIZARD_STEPS(self) -> List[str]:
        """Get current wizard steps (may change based on user choices).

        This is a property to allow dynamic step lists based on state.
        The actual implementation in ProfileCreationWizard handles this dynamically.
        """
        # This is just a reference - the actual wizard uses state to determine steps
        return self.BASIC_STEPS + ["advanced_settings_prompt"] + self.ADVANCED_STEPS

    # Step definitions
    STEP_DEFINITIONS = {
        "profile_name": {
            "prompt": "Enter profile name",
            "help": "Profile name (e.g., openai-prod, claude-dev)",
            "required": True,
            "validator": "_validate_profile_name",
        },
        "provider": {
            "prompt": "Select provider",
            "help": "Provider type (auto/OpenAI/Anthropic/Azure OpenAI)",
            "required": False,
            "default": "auto",
            "options": ["auto", "openai", "anthropic", "azure_openai"],
            "validator": "_validate_provider",
        },
        "api_key": {
            "prompt": "Enter API key",
            "help": "API key (will be masked as sk-...-xyz)",
            "required": True,
            "password": True,
            "validator": "_validate_api_key",
        },
        "model": {
            "prompt": "Enter model",
            "help": "Model identifier (e.g., gpt-4, claude-3-sonnet)",
            "required": False,
            "default": "gpt-4",
            "validator": None,
        },
        "temperature": {
            "prompt": "Enter temperature",
            "help": "Sampling temperature (0.0-2.0, default: 0.7)",
            "required": False,
            "default": "0.7",
            "validator": "_validate_temperature",
        },
        "max_tokens": {
            "prompt": "Enter max tokens",
            "help": "Maximum tokens (default: 4096)",
            "required": False,
            "default": "4096",
            "validator": "_validate_max_tokens",
        },
        "base_url": {
            "prompt": "Enter base URL",
            "help": "Custom base URL (optional)",
            "required": False,
            "default": "",
            "validator": "_validate_base_url",
        },
        "organization": {
            "prompt": "Enter organization",
            "help": "Organization ID (OpenAI only, optional)",
            "required": False,
            "default": "",
            "validator": None,
        },
        "advanced_settings_prompt": {
            "prompt": "Configure advanced settings?",
            "help": "Add timeout, description, tool calling, streaming (y/n)",
            "required": False,
            "default": "n",
            "options": ["y", "n", "yes", "no"],
            "validator": "_validate_yes_no",
        },
        "description": {
            "prompt": "Enter description",
            "help": "Profile description (optional)",
            "required": False,
            "default": "",
            "validator": None,
        },
        "timeout": {
            "prompt": "Enter timeout",
            "help": "Request timeout in milliseconds (0 = no timeout, default: 0)",
            "required": False,
            "default": "0",
            "validator": "_validate_timeout",
        },
        "supports_tools": {
            "prompt": "Enable tool calling?",
            "help": "Support function/tool calling (y/n, default: y)",
            "required": False,
            "default": "y",
            "options": ["y", "n", "yes", "no"],
            "validator": "_validate_yes_no",
        },
        "streaming": {
            "prompt": "Enable streaming?",
            "help": "Stream responses (y/n, default: y)",
            "required": False,
            "default": "y",
            "options": ["y", "n", "yes", "no"],
            "validator": "_validate_yes_no",
        },
    }


# =============================================================================
# Profile Creation Wizard
# =============================================================================

class ProfileCreationWizard:
    """Wizard for creating OpenAI/LLM profiles with validation and testing."""

    def __init__(self, profile_manager, config_manager=None):
        """Initialize profile creation wizard.

        Args:
            profile_manager: Profile manager for creating profiles
            config_manager: Optional config manager for validation
        """
        self.profile_manager = profile_manager
        self.config_manager = config_manager
        self.state = ProfileWizardState()
        self.config = ProfileWizardConfig()
        self.logger = logger

    def reset(self) -> None:
        """Reset wizard state."""
        self.state = ProfileWizardState()

    def get_current_steps(self) -> List[str]:
        """Get current step list based on advanced settings choice.

        The flow is:
        1. Run BASIC_STEPS
        2. Show advanced_settings_prompt (yes/no for advanced settings)
        3. If yes, run ADVANCED_STEPS
        4. Complete

        Returns:
            List of step names for current wizard flow
        """
        # Always include basic steps first
        steps = list(self.config.BASIC_STEPS)

        # Add advanced settings prompt after basic steps
        # We'll determine if advanced steps are included when processing the prompt
        steps.append("advanced_settings_prompt")

        # If user has chosen to configure advanced settings, include advanced steps
        if self.state.configure_advanced:
            steps.extend(self.config.ADVANCED_STEPS)

        return steps

    def get_current_step(self) -> str:
        """Get current wizard step name."""
        current_steps = self.get_current_steps()
        if self.state.step < len(current_steps):
            return current_steps[self.state.step]
        return "complete"

    def get_step_definition(self, step_name: str) -> Optional[Dict[str, Any]]:
        """Get step definition by name."""
        return self.config.STEP_DEFINITIONS.get(step_name)

    def advance_step(self) -> str:
        """Advance to next wizard step.

        Returns:
            Next step name
        """
        self.state.step += 1
        return self.get_current_step()

    def is_complete(self) -> bool:
        """Check if wizard is complete."""
        current_steps = self.get_current_steps()
        return self.state.step >= len(current_steps)

    # ========================================================================
    # Input Processing
    # ========================================================================

    def process_input(self, input_value: str) -> CommandResult:
        """Process input for current wizard step.

        Args:
            input_value: User input value

        Returns:
            Command result with next step or completion
        """
        current_step = self.get_current_step()

        if current_step == "complete":
            return self._complete_profile()

        step_def = self.get_step_definition(current_step)
        if not step_def:
            return CommandResult(
                success=False,
                message=f"Invalid step: {current_step}",
                display_type="error"
            )

        # Trim input
        input_value = input_value.strip()

        # Handle empty input for optional fields
        if not input_value and not step_def.get("required", False):
            default_value = step_def.get("default", "")
            self._set_step_value(current_step, default_value)
            return self._advance_to_next_step()

        # Validate input
        validator_name = step_def.get("validator")
        if validator_name:
            validation_result = self._validate_input(validator_name, input_value)
            if not validation_result.success:
                return validation_result

        # Handle advanced_settings_prompt specially
        if current_step == "advanced_settings_prompt":
            self._set_step_value(current_step, input_value)
            # Check if user wants advanced settings
            wants_advanced = input_value.lower() in ("y", "yes")
            if wants_advanced:
                self.state.configure_advanced = True
            # Continue to next step
            return self._advance_to_next_step()

        # Set value and advance
        self._set_step_value(current_step, input_value)
        return self._advance_to_next_step()

    def _set_step_value(self, step: str, value: str) -> None:
        """Set value for wizard step.

        Args:
            step: Step name
            value: Value to set
        """
        if step == "profile_name":
            self.state.profile_name = value
        elif step == "provider":
            self.state.provider = value
        elif step == "api_key":
            self.state.api_key = value
        elif step == "model":
            self.state.model = value
        elif step == "temperature":
            self.state.temperature = float(value)
        elif step == "max_tokens":
            self.state.max_tokens = int(value)
        elif step == "base_url":
            self.state.base_url = value
        elif step == "organization":
            self.state.organization = value
        elif step == "description":
            self.state.description = value
        elif step == "timeout":
            self.state.timeout = int(value)
        elif step == "supports_tools":
            self.state.supports_tools = value.lower() in ("y", "yes")
        elif step == "streaming":
            self.state.streaming = value.lower() in ("y", "yes")
        elif step == "advanced_settings_prompt":
            # This is handled in process_input, not here
            pass

    def _advance_to_next_step(self) -> CommandResult:
        """Advance to next step and return prompt.

        Returns:
            Command result with next step prompt
        """
        next_step = self.advance_step()

        if next_step == "complete":
            # Show summary and ask for confirmation
            return self._show_summary()

        step_def = self.get_step_definition(next_step)
        prompt = step_def["prompt"]
        help_text = step_def.get("help", "")
        options = step_def.get("options")

        message = f"\n{prompt}"
        if help_text:
            message += f"\n  ({help_text})"
        if options:
            message += f"\n  Options: {', '.join(options)}"
        message += "\n"

        return CommandResult(
            success=True,
            message=message,
            display_type="info",
            data={"step": next_step, "wizard_state": self._get_state_summary()}
        )

    def _get_state_summary(self) -> Dict[str, Any]:
        """Get summary of current wizard state.

        Returns:
            Dictionary with wizard state summary
        """
        summary = {
            "profile_name": self.state.profile_name,
            "provider": self.state.provider,
            "api_key": mask_api_key(self.state.api_key) if self.state.api_key else "<not set>",
            "model": self.state.model,
            "temperature": self.state.temperature,
            "max_tokens": self.state.max_tokens,
            "base_url": self.state.base_url or "<default>",
            "organization": self.state.organization or "<not set>",
        }

        # Add advanced settings if configured
        if self.state.configure_advanced:
            if self.state.description:
                summary["description"] = self.state.description
            summary["timeout"] = f"{self.state.timeout}ms" if self.state.timeout > 0 else "no timeout"
            summary["supports_tools"] = "yes" if self.state.supports_tools else "no"
            summary["streaming"] = "yes" if self.state.streaming else "no"

        return summary

    def _show_summary(self) -> CommandResult:
        """Show profile summary and ask for confirmation.

        Returns:
            Command result with summary
        """
        summary = self._get_state_summary()

        message = "\nProfile Summary:\n"
        for key, value in summary.items():
            message += f"  {key}: {value}\n"
        message += "\nPress Enter to create profile, or 'cancel' to abort"

        return CommandResult(
            success=True,
            message=message,
            display_type="info",
            data={"action": "confirm_create", "wizard_state": summary}
        )

    def confirm_creation(self) -> CommandResult:
        """Confirm and create profile.

        Returns:
            Command result with creation status
        """
        return self._complete_profile()

    # ========================================================================
    # Profile Creation
    # ========================================================================

    def _complete_profile(self) -> CommandResult:
        """Complete profile creation with validation and testing.

        Returns:
            Command result with creation status
        """
        # Build profile configuration
        profile_config = self._build_profile_config()

        # Validate profile configuration
        validation_result = self._validate_profile_config(profile_config)
        if not validation_result.success:
            return validation_result

        # Auto-detect provider if set to auto
        if self.state.provider == "auto" and self.state.api_key:
            detected_provider = detect_provider_from_api_key(self.state.api_key)
            profile_config["provider"] = detected_provider
            self.logger.info(f"Auto-detected provider: {detected_provider}")

        # Create profile
        try:
            profile = self.profile_manager.create_profile(
                name=self.state.profile_name,
                base_url=profile_config.get("base_url", ""),
                model=self.state.model,
                api_key=self.state.api_key,
                temperature=self.state.temperature,
                description=profile_config.get("description", "Created via profile wizard"),
                timeout=self.state.timeout,
                streaming=self.state.streaming,
                supports_tools=self.state.supports_tools,
                provider=profile_config.get("provider", "custom"),
                save_to_config=True
            )

            if profile:
                # Test profile (optional)
                test_result = self._test_profile(profile)

                message = f"\n[ok] Created profile: {self.state.profile_name}"
                message += f"\n  Provider: {profile_config.get('provider', 'auto')}"
                message += f"\n  Model: {self.state.model}"
                message += f"\n  API Key: {mask_api_key(self.state.api_key)}"

                # Show advanced settings if configured
                if self.state.configure_advanced:
                    if self.state.description:
                        message += f"\n  Description: {self.state.description}"
                    timeout_display = f"{self.state.timeout}ms" if self.state.timeout > 0 else "no timeout"
                    message += f"\n  Timeout: {timeout_display}"
                    message += f"\n  Tool calling: {'enabled' if self.state.supports_tools else 'disabled'}"
                    message += f"\n  Streaming: {'enabled' if self.state.streaming else 'disabled'}"

                if test_result.success:
                    message += f"\n{test_result.message}"
                else:
                    message += f"\n[warn] Profile test skipped or failed"

                return CommandResult(
                    success=True,
                    message=message,
                    display_type="success",
                    data={"profile_name": self.state.profile_name, "test_result": test_result.data}
                )
            else:
                return CommandResult(
                    success=False,
                    message=f"\n[err] Failed to create profile '{self.state.profile_name}'. May already exist.",
                    display_type="error"
                )

        except Exception as e:
            self.logger.error(f"Error creating profile: {e}")
            return CommandResult(
                success=False,
                message=f"\n[err] Error creating profile: {str(e)}",
                display_type="error"
            )

    def _build_profile_config(self) -> Dict[str, Any]:
        """Build profile configuration from wizard state.

        Returns:
            Profile configuration dictionary
        """
        config = {
            "provider": self.state.provider,
            "model": self.state.model,
            "temperature": self.state.temperature,
            "max_tokens": self.state.max_tokens,
        }

        if self.state.base_url:
            config["base_url"] = self.state.base_url

        if self.state.organization:
            config["organization"] = self.state.organization

        if self.state.api_key:
            config["api_key"] = self.state.api_key

        # Advanced settings
        if self.state.description:
            config["description"] = self.state.description
        else:
            config["description"] = "Created via profile wizard"

        config["timeout"] = self.state.timeout
        config["supports_tools"] = self.state.supports_tools
        config["streaming"] = self.state.streaming

        return config

    # ========================================================================
    # Validation
    # ========================================================================

    def _validate_input(self, validator_name: str, value: str) -> CommandResult:
        """Validate input using validator method.

        Args:
            validator_name: Name of validator method
            value: Value to validate

        Returns:
            Command result with validation status
        """
        validator = getattr(self, validator_name, None)
        if not validator:
            return CommandResult(success=True, message="", display_type="info")

        try:
            result = validator(value)
            if not result.success:
                return result
            return CommandResult(success=True, message="", display_type="info")
        except Exception as e:
            return CommandResult(
                success=False,
                message=f"\n[err] Validation error: {str(e)}",
                display_type="error"
            )

    def _validate_profile_name(self, value: str) -> CommandResult:
        """Validate profile name.

        Args:
            value: Profile name to validate

        Returns:
            Command result with validation status
        """
        if not value:
            return CommandResult(
                success=False,
                message="\n[err] Profile name is required",
                display_type="error"
            )

        if len(value) < 3:
            return CommandResult(
                success=False,
                message="\n[err] Profile name must be at least 3 characters",
                display_type="error"
            )

        if not re.match(r'^[a-zA-Z0-9_-]+$', value):
            return CommandResult(
                success=False,
                message="\n[err] Profile name can only contain letters, numbers, hyphens, and underscores",
                display_type="error"
            )

        # Check if profile already exists
        existing_profiles = self.profile_manager.get_profile_names()
        if value in existing_profiles:
            return CommandResult(
                success=False,
                message=f"\n[err] Profile '{value}' already exists. Choose a different name.",
                display_type="error"
            )

        return CommandResult(success=True, message="", display_type="info")

    def _validate_provider(self, value: str) -> CommandResult:
        """Validate provider type.

        Args:
            value: Provider to validate

        Returns:
            Command result with validation status
        """
        if not value:
            # Use default
            return CommandResult(success=True, message="", display_type="info")

        value_lower = value.lower()
        valid_providers = ["auto", "openai", "anthropic", "azure_openai"]

        if value_lower not in valid_providers:
            return CommandResult(
                success=False,
                message=f"\n[err] Invalid provider '{value}'. Must be one of: {', '.join(valid_providers)}",
                display_type="error"
            )

        return CommandResult(success=True, message="", display_type="info")

    def _validate_api_key(self, value: str) -> CommandResult:
        """Validate API key format.

        Args:
            value: API key to validate

        Returns:
            Command result with validation status
        """
        if not value:
            return CommandResult(
                success=False,
                message="\n[err] API key is required",
                display_type="error"
            )

        # Check minimum length
        if len(value) < 10:
            return CommandResult(
                success=False,
                message="\n[err] API key appears too short (min 10 characters)",
                display_type="error"
            )

        # Detect provider from key format (for warning)
        detected = detect_provider_from_api_key(value)
        if detected != "auto" and self.state.provider != "auto" and self.state.provider != detected:
            self.logger.warning(
                f"API key format suggests '{detected}' but provider is set to '{self.state.provider}'"
            )

        return CommandResult(success=True, message="", display_type="info")

    def _validate_temperature(self, value: str) -> CommandResult:
        """Validate temperature value.

        Args:
            value: Temperature to validate

        Returns:
            Command result with validation status
        """
        try:
            temp = float(value)
            if not 0.0 <= temp <= 2.0:
                return CommandResult(
                    success=False,
                    message=f"\n[err] Temperature must be between 0.0 and 2.0, got {temp}",
                    display_type="error"
                )
            return CommandResult(success=True, message="", display_type="info")
        except ValueError:
            return CommandResult(
                success=False,
                message=f"\n[err] Temperature must be a number, got '{value}'",
                display_type="error"
            )

    def _validate_max_tokens(self, value: str) -> CommandResult:
        """Validate max tokens value.

        Args:
            value: Max tokens to validate

        Returns:
            Command result with validation status
        """
        try:
            tokens = int(value)
            if tokens < 1:
                return CommandResult(
                    success=False,
                    message=f"\n[err] Max tokens must be >= 1, got {tokens}",
                    display_type="error"
                )
            return CommandResult(success=True, message="", display_type="info")
        except ValueError:
            return CommandResult(
                success=False,
                message=f"\n[err] Max tokens must be an integer, got '{value}'",
                display_type="error"
            )

    def _validate_base_url(self, value: str) -> CommandResult:
        """Validate base URL.

        Args:
            value: Base URL to validate

        Returns:
            Command result with validation status
        """
        if not value:
            return CommandResult(success=True, message="", display_type="info")

        # Basic URL validation
        url_pattern = re.compile(
            r'^(https?://)?'  # http:// or https:// (optional)
            r'([a-zA-Z0-9-]+\.)+'  # domain
            r'[a-zA-Z]{2,}'  # TLD
            r'(:\d+)?'  # optional port
            r'(/.*)?$'  # optional path
        )

        if not url_pattern.match(value) and "localhost" not in value and "127.0.0.1" not in value:
            return CommandResult(
                success=False,
                message=f"\n[err] Invalid URL format: {value}",
                display_type="error"
            )

        return CommandResult(success=True, message="", display_type="info")

    def _validate_yes_no(self, value: str) -> CommandResult:
        """Validate yes/no input.

        Args:
            value: Yes/no value to validate

        Returns:
            Command result with validation status
        """
        if not value:
            # Use default
            return CommandResult(success=True, message="", display_type="info")

        value_lower = value.lower()
        if value_lower not in ("y", "n", "yes", "no"):
            return CommandResult(
                success=False,
                message="\n[err] Please enter 'y' or 'n'",
                display_type="error"
            )

        return CommandResult(success=True, message="", display_type="info")

    def _validate_timeout(self, value: str) -> CommandResult:
        """Validate timeout value.

        Args:
            value: Timeout to validate (milliseconds, 0 = no timeout)

        Returns:
            Command result with validation status
        """
        if not value:
            # Use default
            return CommandResult(success=True, message="", display_type="info")

        try:
            timeout = int(value)
            if timeout < 0:
                return CommandResult(
                    success=False,
                    message=f"\n[err] Timeout must be >= 0 (0 = no timeout), got {timeout}",
                    display_type="error"
                )
            return CommandResult(success=True, message="", display_type="info")
        except ValueError:
            return CommandResult(
                success=False,
                message=f"\n[err] Timeout must be an integer (milliseconds), got '{value}'",
                display_type="error"
            )

    def _validate_profile_config(self, config: Dict[str, Any]) -> CommandResult:
        """Validate complete profile configuration.

        Args:
            config: Profile configuration to validate

        Returns:
            Command result with validation status
        """
        provider = config.get("provider", "auto")

        try:
            # Validate provider type
            validate_provider_type(provider)

            # Provider-specific validation
            if provider == "openai":
                validate_openai_config(config)

            return CommandResult(success=True, message="", display_type="info")

        except ConfigurationValidationError as e:
            return CommandResult(
                success=False,
                message=f"\n[err] Configuration validation failed: {str(e)}",
                display_type="error"
            )

    # ========================================================================
    # Profile Testing
    # ========================================================================

    def _test_profile(self, profile) -> CommandResult:
        """Test profile with optional API call.

        Args:
            profile: Profile to test

        Returns:
            Command result with test status
        """
        # For now, just validate the profile structure
        # Actual API testing can be added later as optional
        try:
            # Check if profile has required fields
            if not profile.model:
                return CommandResult(
                    success=False,
                    message="\n[warn] Profile test: missing model",
                    display_type="warning",
                    data={"tested": False, "reason": "missing_model"}
                )

            # Check if API key is available
            api_key = profile.api_token or profile.get_endpoint()
            if not api_key:
                return CommandResult(
                    success=False,
                    message="\n[warn] Profile test: no API key (will use env var)",
                    display_type="warning",
                    data={"tested": False, "reason": "no_api_key"}
                )

            return CommandResult(
                success=True,
                message="\n[ok] Profile validation passed",
                display_type="success",
                data={"tested": True, "validation": "passed"}
            )

        except Exception as e:
            return CommandResult(
                success=False,
                message=f"\n[warn] Profile test error: {str(e)}",
                display_type="warning",
                data={"tested": False, "error": str(e)}
            )


# =============================================================================
# Helper Functions
# =============================================================================

def get_provider_display_name(provider: str) -> str:
    """Get display name for provider.

    Args:
        provider: Provider type

    Returns:
        Display name
    """
    display_names = {
        "openai": "OpenAI",
        "anthropic": "Anthropic",
        "azure_openai": "Azure OpenAI",
        "auto": "Auto-detect"
    }
    return display_names.get(provider, provider)


def create_profile_wizard(profile_manager, config_manager=None) -> ProfileCreationWizard:
    """Factory function to create profile wizard instance.

    Args:
        profile_manager: Profile manager
        config_manager: Optional config manager

    Returns:
        ProfileCreationWizard instance
    """
    return ProfileCreationWizard(profile_manager, config_manager)
