from typing import Any, Dict, List, Optional

from axipy.da.data_object import DataObject

from ..schema import Schema
from .data_provider import DataProvider
from .provider_utils import OpenMode
from .source import Destination, Source

__all__: List[str] = [
    "OgrSource",
    "OgrDestination",
    "OgrDataProvider",
]


class OgrSource(Source):
    pass


class OgrDestination(Destination):
    pass


class OgrDataProvider(DataProvider):
    """
    Провайдер для векторных данных OGR.

    Note:
        Ссылку на провайдер можно получить через глобальную переменную :attr:`axipy.provider_manager.ogr`.

    .. seealso::
       Пример использования см :ref:`ref-converter-ogr`
    """

    @staticmethod
    def _identifier() -> str:
        return "OgrDataProvider"

    def get_source(
        self,
        data: str,
        dataobject: Optional[str] = None,
        alias: Optional[str] = None,
        encoding: str = "utf8",
        open_data: Optional[dict] = None,
    ) -> Source:
        """
        Создает источник данных.

        Args:
          data: Источник данных или имя файла.
          dataobject: Наименование таблицы. Если не указано, будет выбрано по умолчанию.
          alias: Псевдоним для открываемой таблицы.
          encoding: Кодировка.
          open_data: Параметры OGR. Передаются как пары параметр-значения, которые в конечном итоге рассматриваются как дополнительные
            параметры при открытии в функции `GDALOpenEx <https://gdal.org/en/latest/api/raster_c_api.html>`_
            Конкретные параметры необходимо смотреть в разделе "Dataset open options" для рассматриваемого источника.
        """
        pars: Dict[str, Any] = {
            "src": data,
            "dataobject": dataobject,
            "charset": encoding,
        }
        if open_data is not None:
            pars["data"] = {"openOptions": open_data}
        return OgrSource(Source._provider(self.id), Source._alias(alias), pars)

    def open(
        self,
        data: str,
        dataobject: Optional[str] = None,
        alias: Optional[str] = None,
        encoding: str = "utf8",
        open_data: Optional[dict] = None,
    ) -> DataObject:
        """
        Открывает объект данных.

        Args:
          data: Источник данных или имя файла.
          dataobject: Наименование таблицы. Если не указано, будет выбрано по умолчанию.
          alias: Псевдоним для открываемой таблицы.
          encoding: Кодировка.
          open_data: Параметры OGR. Передаются как пары параметр-значения, которые в конечном итоге рассматриваются как дополнительные
            параметры при открытии в функции `GDALOpenEx <https://gdal.org/en/latest/api/raster_c_api.html>`_
            Конкретные параметры необходимо смотреть в разделе "Dataset open options" для рассматриваемого источника.
        """
        return self.get_source(data, dataobject, alias, encoding, open_data).open()

    def file_extensions(self) -> List[str]:
        return list(filter(lambda v: v not in ["shp", "shz"], super().file_extensions()))

    def get_destination(
        self,
        filepath: str,
        dataobject: str,
        schema: Schema,
        open_mode: OpenMode = OpenMode.Create,
        create_data: Optional[dict] = None,
        # driver_name: str = None,
    ) -> Destination:
        """
        Создает назначение объекта данных.

        Args:
          filepath: Источник данных или имя файла.
          dataobject: Наименование таблицы
          schema: Схема таблицы.
          open_mode: Режим открытия файла. В случае :attr:`OpenMode.Append` будет производиться дополнение к существующему файлу.
          create_data: Параметры OGR. Разделены на два раздел, которые организуются так же как словари :class:`dict`.

            * `"lco"` - используется при создании слоя как дополнительные параметры. Соответствуют "Layer creation options" у рассматриваемого источника
            * `"dsco"` - используется при создании источника данных как дополнительные параметры. Соответствуют "Database creation options"
            * `"driver"` - явное указание используемого драйвера"

        .. seealso::
            :ref:`ref-converter-ogr`
        """

        pars: Dict[str, Any] = {
            "dataobject": dataobject,
            ("append" if open_mode == OpenMode.Append else "create"): True,
        }

        if create_data is not None:
            pars["data"] = {}
            pars["data"]["createOptions"] = create_data

        # if create_data is not None or driver_name is not None:
        #     pars["data"] = {}
        #     if create_data is not None:
        #         pars["data"]["createOptions"] = create_data
        #     if driver_name is not None:
        #         pars["data"]["driverName"] = driver_name

        return OgrDestination(schema, Source._provider(self.id), Source._table_file(filepath), pars)

    def create_open(self) -> DataObject:
        """
        Attention:
            Не поддерживается.

        Raises:
            NotImplementedError
        """
        raise NotImplementedError
