# Copyright (c) 2025 Patrick Motsch
# All rights reserved.
"""
Utility service for common operations across the gateway.
Provides centralized access to configuration, events, and other utilities.
Core service - not requested by features directly.
"""

import logging
from typing import Any, Optional, Dict, Callable, List
from modules.shared.configuration import APP_CONFIG
from modules.shared.eventManagement import eventManager
from modules.shared.timeUtils import getUtcTimestamp
from modules.shared import jsonUtils

logger = logging.getLogger(__name__)


class UtilsService:
    """Utility service providing common operations."""

    def __init__(self, context, get_service: Callable[[str], Any]):
        """Initialize with service center context and resolver."""
        self._context = context
        self._get_service = get_service

    # ===== Event handling =====

    def eventRegisterCron(self, job_id: str, func: Callable, cron_kwargs: Dict[str, Any],
                         replace_existing: bool = True, coalesce: bool = True,
                         max_instances: int = 1, misfire_grace_time: int = 1800):
        """Register a cron job with the event manager."""
        try:
            eventManager.registerCron(
                jobId=job_id,
                func=func,
                cronKwargs=cron_kwargs,
                replaceExisting=replace_existing,
                coalesce=coalesce,
                maxInstances=max_instances,
                misfireGraceTime=misfire_grace_time
            )
            logger.info(f"Registered cron job '{job_id}' with schedule: {cron_kwargs}")
        except Exception as e:
            logger.error(f"Error registering cron job '{job_id}': {str(e)}")

    def eventRegisterInterval(self, job_id: str, func: Callable, seconds: Optional[int] = None,
                            minutes: Optional[int] = None, hours: Optional[int] = None,
                            replace_existing: bool = True, coalesce: bool = True,
                            max_instances: int = 1, misfire_grace_time: int = 1800):
        """Register an interval job with the event manager."""
        try:
            eventManager.registerInterval(
                jobId=job_id,
                func=func,
                seconds=seconds,
                minutes=minutes,
                hours=hours,
                replaceExisting=replace_existing,
                coalesce=coalesce,
                maxInstances=max_instances,
                misfireGraceTime=misfire_grace_time
            )
            logger.info(f"Registered interval job '{job_id}' (h={hours}, m={minutes}, s={seconds})")
        except Exception as e:
            logger.error(f"Error registering interval job '{job_id}': {str(e)}")

    def eventRemove(self, job_id: str):
        """Remove a scheduled job from the event manager."""
        try:
            eventManager.remove(job_id)
            logger.info(f"Removed job '{job_id}'")
        except Exception as e:
            logger.error(f"Error removing job '{job_id}': {str(e)}")

    def configGet(self, key: str, default: Any = None, user_id: str = "system") -> Any:
        """Get a configuration value with optional default."""
        try:
            return APP_CONFIG.get(key, default, user_id)
        except Exception as e:
            logger.error(f"Error getting config '{key}': {str(e)}")
            return default

    def timestampGetUtc(self) -> float:
        """Get current UTC timestamp."""
        try:
            return getUtcTimestamp()
        except Exception as e:
            logger.error(f"Error getting UTC timestamp: {str(e)}")
            return 0.0

    # ===== Debug Tools =====

    def writeDebugFile(self, content: str, fileType: str, documents: Optional[List] = None) -> None:
        """Wrapper to write debug files via shared debugLogger."""
        try:
            from modules.shared.debugLogger import writeDebugFile as _writeDebugFile
            _writeDebugFile(content, fileType, documents)
        except Exception:
            pass

    def debugLogToFile(self, message: str, context: str = "DEBUG"):
        """Wrapper to log debug messages via shared debugLogger."""
        try:
            from modules.shared.debugLogger import debugLogToFile as _debugLogToFile
            _debugLogToFile(message, context)
        except Exception:
            pass

    def storeDebugMessageAndDocuments(self, message, currentUser, mandateId=None, featureInstanceId=None):
        """Wrapper to store debug messages and documents via interfaceDbChat."""
        try:
            from modules.interfaces.interfaceDbChat import storeDebugMessageAndDocuments as _storeDebugMessageAndDocuments
            _storeDebugMessageAndDocuments(message, currentUser, mandateId=mandateId, featureInstanceId=featureInstanceId)
        except Exception:
            pass

    def writeDebugArtifact(self, fileName: str, obj: Any):
        """Backward-compatible wrapper that now writes via writeDebugFile."""
        try:
            import json
            if isinstance(obj, (dict, list)):
                content = json.dumps(obj, ensure_ascii=False, indent=2)
            else:
                content = str(obj)
            from modules.shared.debugLogger import writeDebugFile as _writeDebugFile
            _writeDebugFile(content, fileName)
        except Exception:
            pass

    # ===== Prompt sanitization =====

    def sanitizePromptContent(self, content: str, contentType: str = "text") -> str:
        """Centralized prompt content sanitization."""
        if not content:
            return ""
        try:
            import re
            content_str = str(content)
            sanitized = re.sub(r'[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]', '', content_str)
            if contentType == "userinput":
                sanitized = sanitized.replace('{', '{{').replace('}', '}}')
                sanitized = sanitized.replace('"', '\\"').replace("'", "\\'")
                return f"'{sanitized}'"
            elif contentType == "json":
                sanitized = sanitized.replace('\\', '\\\\').replace('"', '\\"')
                sanitized = sanitized.replace('\n', '\\n').replace('\r', '\\r').replace('\t', '\\t')
            elif contentType == "document":
                sanitized = sanitized.replace('\\', '\\\\').replace('"', '\\"').replace("'", "\\'")
                sanitized = sanitized.replace('\n', '\\n').replace('\r', '\\r').replace('\t', '\\t')
            else:
                sanitized = sanitized.replace('\\', '\\\\').replace('"', '\\"').replace("'", "\\'")
                sanitized = sanitized.replace('\n', '\\n').replace('\r', '\\r').replace('\t', '\\t')
            return sanitized
        except Exception as e:
            logger.error(f"Error sanitizing prompt content: {str(e)}")
            return "[ERROR: Content could not be safely sanitized]"

    # ===== JSON utility wrappers =====

    def jsonStripCodeFences(self, text: str) -> str:
        return jsonUtils.stripCodeFences(text)

    def jsonExtractFirstBalanced(self, text: str) -> str:
        return jsonUtils.extractFirstBalancedJson(text)

    def jsonNormalizeText(self, text: str) -> str:
        return jsonUtils.normalizeJsonText(text)

    def jsonExtractString(self, text: str) -> str:
        return jsonUtils.extractJsonString(text)

    def jsonTryParse(self, text) -> tuple:
        return jsonUtils.tryParseJson(text)

    # ===== Enum utility functions =====

    def mapToEnum(self, enum_class, value_str, default_value):
        """Map string value to enum."""
        if not value_str:
            return default_value
        for enum_item in enum_class:
            if enum_item.value.lower() == value_str.lower():
                return enum_item
        return default_value
