"""
Модуль с миксином для операций чтения из Bitrix24 API.

Содержит методы для получения данных из API Bitrix24 с учетом
особенностей разных типов сущностей.
"""

from typing import Any, ClassVar

from fast_bitrix24 import Bitrix

from app.domain.entities.base_entity import BitrixEntity
from app.infrastructure.bitrix.mixins.error_handling import (
    BitrixErrorHandlingMixin,
)
from app.infrastructure.logging.logger import logger


class BitrixReadMixin[T: BitrixEntity](BitrixErrorHandlingMixin):
    """
    Миксин для операций чтения данных из Bitrix24 API.

    Предоставляет методы для получения сущностей и их списков.
    """

    _bitrix_list_method: ClassVar[str]
    _bitrix_get_method: ClassVar[str]
    _bitrix_fields_method: ClassVar[str]
    _entity_factory: type[T]

    _id_param_name: ClassVar[str] = "ID"
    _filter_param_name: ClassVar[str] = "filter"
    _select_param_name: ClassVar[str] = "select"
    _order_param_name: ClassVar[str] = "order"
    _start_param_name: ClassVar[str] = "start"

    def __init__(self, bitrix: Bitrix):
        """
        Инициализация миксина.

        :param bitrix: Клиент для работы с API Bitrix24
        """
        self.bitrix = bitrix

    async def get_by_id(self, entity_id: int) -> T | None:
        """
        Получение сущности по идентификатору.

        :param entity_id: Идентификатор сущности
        :return: Объект сущности или None, если сущность не найдена
        """
        error_message = (
            f"Ошибка при получении {self._format_entity_name(self._entity_factory)} "
            f"с ID={entity_id}"
        )

        try:
            response = await self._safe_call(
                self.bitrix.call,
                error_message,
                None,
                self._bitrix_get_method,
                {self._id_param_name: entity_id},
                raw=True,
            )

            if not response or "result" not in response:
                logger.warning(f"{error_message}: получен некорректный ответ")
                return None

            result = response.get("result")
            if not result:
                return None

            return await self._process_entity(result)
        except Exception as e:
            logger.error(f"{error_message}: {e}")
            return None

    async def list_entities(
        self,
        filter_params: dict[str, Any] | None = None,
        select_fields: list[str] | None = None,
        order: dict[str, str] | None = None,
        start: int = 0,
        limit: int = 50,
    ) -> list[T]:
        """
        Получение списка сущностей с возможностью фильтрации.

        :param filter_params: Параметры фильтрации
        :param select_fields: Список полей для выбора
        :param order: Параметры сортировки
        :param start: Начальная позиция выборки
        :param limit: Максимальное количество возвращаемых записей
        :return: Список сущностей
        """
        error_message = (
            f"Ошибка при получении списка сущностей "
            f"{self._format_entity_name(self._entity_factory)}"
        )

        try:
            params: dict[str, Any] = {
                self._start_param_name: start,
            }

            if filter_params:
                params[self._filter_param_name] = filter_params

            if select_fields:
                params[self._select_param_name] = select_fields
            else:
                params[self._select_param_name] = ["*", "UF_*"]

            if order:
                params[self._order_param_name] = order

            b_results: dict[str, list[dict[str, Any]]] = await self._safe_call(
                self.bitrix.call,
                error_message,
                {},
                self._bitrix_list_method,
                items=params,
                raw=True,
            )
            results = b_results.get("result", [])[:limit]

            results = results[:limit]

            entities: list[T] = []

            for result in results:
                entity = await self._process_entity(result)
                if entity:
                    entities.append(entity)

            return entities
        except Exception as e:
            logger.error(f"{error_message}: {e}")
            return []

    async def get_fields(self) -> dict[str, Any]:
        """
        Получение описания полей сущности.

        :return: Словарь с описанием полей сущности
        """
        error_message = (
            f"Ошибка при получении описания полей сущности "
            f"{self._format_entity_name(self._entity_factory)}"
        )

        response = await self._safe_call(
            self.bitrix.call,
            error_message,
            None,
            self._bitrix_fields_method,
        )

        if not response or "result" not in response:
            logger.warning(f"{error_message}: получен некорректный ответ")
            return {}

        return response.get("result", {})

    async def _process_entity(self, data: dict[str, Any]) -> T | None:
        """
        Обработка данных сущности из API.

        Метод для переопределения в дочерних классах для
        добавления дополнительной логики обработки.

        :param data: Данные сущности из API
        :return: Объект сущности или None
        """
        try:
            return self._entity_factory.from_bitrix(data)
        except Exception as e:
            entity_id = data.get("ID", "неизвестный ID")
            logger.error(
                f"Ошибка при обработке сущности "
                f"{self._format_entity_name(self._entity_factory)} "
                f"с ID={entity_id}: {e}",
            )
            return None
