import importlib
from enum import Enum
from types import ModuleType
from typing import Dict, TextIO

from osbuild.solver.exceptions import InvalidAPIVersionError
from osbuild.solver.model import DepsolveResult, DumpResult, SearchResult
from osbuild.solver.request import SolverRequest


class SolverAPIVersion(Enum):
    V1 = 1
    V2 = 2

    def __str__(self) -> str:
        return self.name.lower()


def get_api_module(api_version: SolverAPIVersion) -> ModuleType:
    try:
        return importlib.import_module(f"osbuild.solver.api.v{api_version.value}")
    except ImportError as e:
        raise InvalidAPIVersionError(f"Failed to import solver API module for version: {api_version.value}") from e


def parse_request(request_dict: Dict) -> SolverRequest:
    """
    Parse a request dict into a SolverRequest object

    Detects API version from the request (defaults to V1) and
    uses the appropriate version-specific parser.
    """
    # Get API version from the request, default to V1, because the current (V1)
    # API implementation does not set any version field.
    # pylint: disable=fixme
    # XXX: remove the default and make it an error once V1 is deprecated.
    version_num = request_dict.get("api_version", 1)
    try:
        api_version = SolverAPIVersion(version_num)
    except ValueError as e:
        raise InvalidAPIVersionError(f"Invalid API version: {e}") from e

    api_module = get_api_module(api_version)
    return api_module.parse_request(request_dict)


def serialize_response_depsolve(
        api_version: SolverAPIVersion, solver: str, result: DepsolveResult, writer: TextIO) -> None:
    """
    Serializes a Solver API response for the DEPSOLVE command.

    NOTE: The actual types returned by the API version specific implementations
          of these functions will differ across implementations. It does not
          make sense to define it in the main proxy serializers.
    """
    api_module = get_api_module(api_version)
    api_module.serialize_response_depsolve(solver, result, writer)


def serialize_response_dump(
        api_version: SolverAPIVersion, solver: str, result: DumpResult, writer: TextIO) -> None:
    """
    Serializes a Solver API response for the DUMP command.

    NOTE: The actual types returned by the API version specific implementations
          of these functions will differ across implementations. It does not
          make sense to define it in the main proxy serializers.
    """
    api_module = get_api_module(api_version)
    api_module.serialize_response_dump(solver, result, writer)


def serialize_response_search(
        api_version: SolverAPIVersion, solver: str, result: SearchResult, writer: TextIO) -> None:
    """
    Serializes a Solver API response for the SEARCH command.

    NOTE: The actual types returned by the API version specific implementations
          of these functions will differ across implementations. It does not
          make sense to define it in the main proxy serializers.
    """
    api_module = get_api_module(api_version)
    api_module.serialize_response_search(solver, result, writer)
