from typing import List, Optional, cast

from axipy.da.data_object import Table

from .data_provider import DataProvider
from .source import Destination, Schema, Source

__all__: List[str] = [
    "CsvSource",
    "CsvDestination",
    "CsvDataProvider",
]


class CsvSource(Source):
    pass


class CsvDestination(Destination):
    pass


class CsvDataProvider(DataProvider):
    """
    Файловый провайдер: Текст с разделителями.

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

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

    def get_source(
        self,
        filepath: str,
        with_header: bool = True,
        delimiter: str = ",",
        encoding: str = "utf8",
        alias: Optional[str] = None,
    ) -> Source:
        """
        Создает источник данных.

        Args:
            filepath: Путь к файлу.
            with_header: Признак того, что в первой строке содержатся имена
                атрибутов таблицы.
            delimiter: Разделитель полей.
            encoding: Кодировка.
            alias: Псевдоним для открываемой таблицы.
        """
        return CsvSource(
            Source._provider(self.id),
            Source._table_file(filepath),
            Source._alias(alias),
            {"delimiter": delimiter, "hasNamesRow": with_header, "charset": encoding},
        )

    def open(
        self,
        filepath: str,
        with_header: bool = True,
        delimiter: str = ",",
        encoding: str = "utf8",
        alias: Optional[str] = None,
    ) -> Table:
        """
        Открывает объект данных.

        Args:
            filepath: Путь к файлу.
            with_header: Признак того, что в первой строке содержатся имена атрибутов таблицы.
            delimiter: Разделитель полей.
            encoding: Кодировка.
            alias: Псевдоним для открываемой таблицы.
        """
        return cast(Table, self.get_source(filepath, with_header, delimiter, encoding, alias).open())

    def get_destination(
        self,
        filepath: str,
        schema: Schema,
        with_header: bool = True,
        delimiter: str = ";",
        encoding: str = "utf8",
    ) -> Destination:
        """
        Создает назначение объекта данных.

        Args:
            filepath: Путь к файлу.
            schema: Схема таблицы.
            with_header: Признак того, что в первой строке содержатся имена
                атрибутов таблицы.
            delimiter: Разделитель полей.
            encoding: Кодировка.
        """
        return CsvDestination(
            schema,
            Source._provider(self.id),
            Source._table_file(filepath),
            {"delimiter": delimiter, "hasNamesRow": with_header, "charset": encoding},
        )

    def create_open(
        self,
        filepath: str,
        schema: Schema,
        with_header: bool = True,
        delimiter: str = ";",
        encoding: str = "utf8",
    ) -> Table:
        """
        Создает и открывает объект данных.

        Args:
            filepath: Путь к файлу.
            schema: Схема таблицы.
            with_header: Признак того, что в первой строке содержатся имена
                атрибутов таблицы.
            delimiter: Разделитель полей.
            encoding: Кодировка.
        """
        return cast(Table, self.get_destination(filepath, schema, with_header, delimiter, encoding).create_open())
