"""
Connection error normalization for user-friendly feedback.
Maps database-specific errors to actionable messages.
"""

from enum import Enum
from typing import Optional
from dataclasses import dataclass
import re


class ErrorCategory(Enum):
    AUTH_FAILED = "auth_failed"
    NETWORK_UNREACHABLE = "network_unreachable"
    DATABASE_NOT_FOUND = "database_not_found"
    SCHEMA_NOT_FOUND = "schema_not_found"
    TABLE_NOT_FOUND = "table_not_found"
    PERMISSION_DENIED = "permission_denied"
    SSL_ERROR = "ssl_error"
    TIMEOUT = "timeout"
    INVALID_CONFIG = "invalid_config"
    UNKNOWN = "unknown"


@dataclass
class NormalizedError:
    category: ErrorCategory
    message: str
    next_steps: list[str]
    original_error: str
    field_hint: Optional[str] = None  # Which form field is likely wrong


# Error patterns per database
ERROR_PATTERNS = {
    "postgresql": [
        (r"password authentication failed", ErrorCategory.AUTH_FAILED, ["Verify username and password", "Ensure user exists in PostgreSQL"]),
        (r"could not connect to server.*Connection refused", ErrorCategory.NETWORK_UNREACHABLE, ["Verify host and port", "Check if PostgreSQL is running", "Check firewall rules"]),
        (r"database .* does not exist", ErrorCategory.DATABASE_NOT_FOUND, ["Verify database name", "Check spelling"]),
        (r"SSL.*certificate", ErrorCategory.SSL_ERROR, ["Verify SSL certificate paths", "Check certificate validity"]),
        (r"permission denied", ErrorCategory.PERMISSION_DENIED, ["Check user privileges", "Contact database administrator"]),
        (r"timeout", ErrorCategory.TIMEOUT, ["Check network connectivity", "Increase timeout settings"]),
    ],

    "snowflake": [
        (r"Incorrect username or password", ErrorCategory.AUTH_FAILED, ["Verify username and password", "Check account identifier format"]),
        (r"JWT token is invalid", ErrorCategory.AUTH_FAILED, ["Verify private key matches public key in Snowflake", "Check key pair configuration"]),
        (r"account .* does not exist", ErrorCategory.INVALID_CONFIG, ["Verify account identifier", "Include region if required (e.g., xy12345.us-east-1)"]),
        (r"Warehouse .* does not exist", ErrorCategory.INVALID_CONFIG, ["Verify warehouse name", "Check warehouse is created and accessible"]),
        (r"Database .* does not exist", ErrorCategory.DATABASE_NOT_FOUND, ["Verify database name", "Check user has access to database"]),
        (r"IP .* is not allowed", ErrorCategory.NETWORK_UNREACHABLE, ["Add your IP to Snowflake network policy", "Contact Snowflake administrator"]),
    ],

    "bigquery": [
        (r"Could not deserialize key data", ErrorCategory.AUTH_FAILED, ["Verify service account JSON is valid", "Re-download credentials from GCP Console"]),
        (r"403.*Access Denied", ErrorCategory.PERMISSION_DENIED, ["Verify service account has BigQuery permissions", "Check IAM roles in GCP Console"]),
        (r"404.*Not found: Project", ErrorCategory.INVALID_CONFIG, ["Verify project ID", "Check project exists and is accessible"]),
        (r"404.*Not found: Dataset", ErrorCategory.SCHEMA_NOT_FOUND, ["Verify dataset name", "Check dataset exists in project"]),
    ],

    "redshift": [
        (r"password authentication failed", ErrorCategory.AUTH_FAILED, ["Verify username and password", "Ensure user exists in Redshift"]),
        (r"could not connect to server", ErrorCategory.NETWORK_UNREACHABLE, ["Verify cluster endpoint", "Check VPC security groups", "Ensure cluster is publicly accessible or VPN is connected"]),
        (r"database .* does not exist", ErrorCategory.DATABASE_NOT_FOUND, ["Verify database name"]),
    ],

    "mysql": [
        (r"Access denied for user", ErrorCategory.AUTH_FAILED, ["Verify username and password", "Check user host permissions"]),
        (r"Can't connect to MySQL server", ErrorCategory.NETWORK_UNREACHABLE, ["Verify host and port", "Check if MySQL is running"]),
        (r"Unknown database", ErrorCategory.DATABASE_NOT_FOUND, ["Verify database name"]),
        (r"SSL connection error", ErrorCategory.SSL_ERROR, ["Verify SSL certificate paths", "Check certificate validity"]),
    ],

    "clickhouse": [
        (r"Authentication failed", ErrorCategory.AUTH_FAILED, ["Verify username and password"]),
        (r"Connection refused", ErrorCategory.NETWORK_UNREACHABLE, ["Verify host and port", "Check if ClickHouse is running"]),
        (r"Database .* doesn't exist", ErrorCategory.DATABASE_NOT_FOUND, ["Verify database name"]),
    ],

    "databricks": [
        (r"Invalid access token", ErrorCategory.AUTH_FAILED, ["Generate new Personal Access Token in Databricks", "Verify token has not expired"]),
        (r"Could not resolve host", ErrorCategory.NETWORK_UNREACHABLE, ["Verify workspace URL", "Check network connectivity"]),
        (r"HTTP 404", ErrorCategory.INVALID_CONFIG, ["Verify HTTP path for SQL warehouse", "Check warehouse exists"]),
    ],

    "athena": [
        (r"InvalidAccessKeyId", ErrorCategory.AUTH_FAILED, ["Verify AWS access key ID"]),
        (r"SignatureDoesNotMatch", ErrorCategory.AUTH_FAILED, ["Verify AWS secret access key"]),
        (r"Access Denied", ErrorCategory.PERMISSION_DENIED, ["Check IAM permissions for Athena and S3", "Verify S3 staging directory access"]),
        (r"Database .* not found", ErrorCategory.DATABASE_NOT_FOUND, ["Verify schema/database name in Glue catalog"]),
    ],

    # Default patterns for databases without specific patterns
    "_default": [
        (r"authentication|password|credential|login failed", ErrorCategory.AUTH_FAILED, ["Verify username and password"]),
        (r"connection refused|could not connect|unreachable|host", ErrorCategory.NETWORK_UNREACHABLE, ["Verify host and port", "Check network connectivity"]),
        (r"database.*not exist|unknown database", ErrorCategory.DATABASE_NOT_FOUND, ["Verify database name"]),
        (r"permission denied|access denied|not authorized", ErrorCategory.PERMISSION_DENIED, ["Check user permissions"]),
        (r"ssl|certificate|tls", ErrorCategory.SSL_ERROR, ["Check SSL configuration"]),
        (r"timeout|timed out", ErrorCategory.TIMEOUT, ["Check network connectivity", "Increase timeout"]),
    ],
}

# Field hints for common error categories
FIELD_HINTS = {
    ErrorCategory.AUTH_FAILED: "user or password",
    ErrorCategory.NETWORK_UNREACHABLE: "host or port",
    ErrorCategory.DATABASE_NOT_FOUND: "database",
    ErrorCategory.SCHEMA_NOT_FOUND: "schema",
    ErrorCategory.SSL_ERROR: "SSL certificate fields",
    ErrorCategory.INVALID_CONFIG: "account or connection details",
}


def normalize_error(database_type: str, error: Exception) -> NormalizedError:
    """
    Convert database-specific error to normalized, user-friendly format.
    
    Args:
        database_type: The database type (e.g., 'postgresql', 'snowflake')
        error: The original exception
    
    Returns:
        NormalizedError with category, message, and actionable next steps
    """
    error_str = str(error).lower()
    original_error = str(error)

    # Get patterns for this database type, fallback to default
    patterns = ERROR_PATTERNS.get(database_type, []) + ERROR_PATTERNS["_default"]

    for pattern, category, next_steps in patterns:
        if re.search(pattern, error_str, re.IGNORECASE):
            return NormalizedError(
                category=category,
                message=_get_user_message(category),
                next_steps=next_steps,
                original_error=original_error,
                field_hint=FIELD_HINTS.get(category),
            )

    # Unknown error
    return NormalizedError(
        category=ErrorCategory.UNKNOWN,
        message="An unexpected error occurred while connecting to the database.",
        next_steps=["Check connection details", "Review error message below", "Contact support if issue persists"],
        original_error=original_error,
        field_hint=None,
    )


def _get_user_message(category: ErrorCategory) -> str:
    """Get user-friendly message for error category."""
    messages = {
        ErrorCategory.AUTH_FAILED: "Authentication failed. Please check your credentials.",
        ErrorCategory.NETWORK_UNREACHABLE: "Unable to reach the database server.",
        ErrorCategory.DATABASE_NOT_FOUND: "The specified database was not found.",
        ErrorCategory.SCHEMA_NOT_FOUND: "The specified schema was not found.",
        ErrorCategory.TABLE_NOT_FOUND: "The specified table was not found.",
        ErrorCategory.PERMISSION_DENIED: "You don't have permission to perform this action.",
        ErrorCategory.SSL_ERROR: "SSL/TLS connection error. Check certificate configuration.",
        ErrorCategory.TIMEOUT: "Connection timed out.",
        ErrorCategory.INVALID_CONFIG: "Invalid connection configuration.",
        ErrorCategory.UNKNOWN: "An unexpected error occurred.",
    }
    return messages.get(category, messages[ErrorCategory.UNKNOWN])


def to_api_response(normalized: NormalizedError) -> dict:
    """Convert NormalizedError to API response format."""
    return {
        "success": False,
        "error": {
            "category": normalized.category.value,
            "message": normalized.message,
            "next_steps": normalized.next_steps,
            "field_hint": normalized.field_hint,
            "details": normalized.original_error,
        }
    }
