from __future__ import annotations

import logging
from pathlib import Path
from typing import Optional

from mockmesh.config.resolver import ConfigResolver, Resolution, ResolutionTier
from mockmesh.core.engine import MockMeshEngine
from mockmesh.core.errors import InterceptError, MockMeshError, UnknownOperationError
from mockmesh.core.fallback import FallbackConfig
from mockmesh.core.registry import PluginRegistry
from mockmesh.plugins.base import BasePlugin
from mockmesh.response.engine import MockResponse, ResponseEngine
from mockmesh.storage.manager import StorageManager

__all__ = [
    "initialize", "shutdown", "engine", "register_plugin",
    "register_handler", "register_fallback",
    "MockMeshEngine", "BasePlugin", "MockResponse", "ResponseEngine",
    "StorageManager", "ConfigResolver", "Resolution", "ResolutionTier",
    "MockMeshError", "InterceptError", "UnknownOperationError", "FallbackConfig"
]

_active_engine: Optional[MockMeshEngine] = None


def initialize(
    config_path:        Optional[str | Path] = None,
    storage_path:       Optional[str | Path] = None,
    log_level:          int  = logging.DEBUG,
    console_log:        bool = False,
    json_console:       bool = True,
    plugins:            Optional[list] = None,
    responses_path:     Optional[str | Path] = None,
    use_json_log:       Optional[bool] = None,
    fallback_mode:      str = "mock",
    on_intercept_error: Optional[callable] = None,
) -> MockMeshEngine:
    global _active_engine  # noqa: PLW0603
    if _active_engine is not None:
        return _active_engine
    if use_json_log is not None:
        console_log  = True
        json_console = use_json_log
    _active_engine = MockMeshEngine(
        config_path=config_path,
        storage_path=storage_path,
        log_level=log_level,
        console_log=console_log,
        json_console=json_console,
        plugins=plugins,
        responses_path=responses_path,
        fallback_mode=fallback_mode,
        on_intercept_error=on_intercept_error,
    )
    _active_engine.start()
    return _active_engine


def shutdown() -> None:
    global _active_engine  # noqa: PLW0603
    if _active_engine is not None:
        _active_engine.stop()
        _active_engine = None


def engine(
    config_path:        Optional[str | Path] = None,
    storage_path:       Optional[str | Path] = None,
    log_level:          int  = logging.DEBUG,
    console_log:        bool = False,
    json_console:       bool = True,
    plugins:            Optional[list] = None,
    responses_path:     Optional[str | Path] = None,
    use_json_log:       Optional[bool] = None,
    fallback_mode:      str = "mock",
    on_intercept_error: Optional[callable] = None,
) -> MockMeshEngine:
    if use_json_log is not None:
        console_log  = True
        json_console = use_json_log
    return MockMeshEngine(
        config_path=config_path,
        storage_path=storage_path,
        log_level=log_level,
        console_log=console_log,
        json_console=json_console,
        plugins=plugins,
        responses_path=responses_path,
        fallback_mode=fallback_mode,
        on_intercept_error=on_intercept_error,
    )


def register_plugin(plugin: BasePlugin) -> None:
    PluginRegistry.instance().register(plugin)


def register_handler(provider: str, operation: str, handler_fn: callable) -> None:
    if _active_engine is None:
        raise MockMeshError("MockMesh not initialized — call initialize() first")
    _active_engine.register_handler(provider, operation, handler_fn)


def register_fallback(provider: str, fallback_fn: callable) -> None:
    if _active_engine is None:
        raise MockMeshError("MockMesh not initialized — call initialize() first")
    _active_engine.register_fallback(provider, fallback_fn)


