from abc import ABC, abstractmethod
from typing import Any, Callable, List

from django.contrib.auth import get_user_model

from baserow.core.registry import Instance, Registry

User = get_user_model()

ExporterFunc = Callable[[Any, bool], None]


class TableExporter(Instance, ABC):
    """
    This abstract class is the base for a particular way of exporting a table and views
    of a table. A TableExporter defines which views it supports and then the user
    will be able to use the exporter to export views of those types. Additionally if
    can_export_table returns True a the user will also be allowed export a table
    without specifying a particular view.
    """

    def before_job_create(self, user, table, view, export_options):
        """
        This method is called just before an export job is created. It can be used to
        do some additional checking of the provided values.

        :param user: The user that requested the creation of the job.
        :type user: User
        :param table: The table that must be exported.
        :type table: Table
        :param view: The view that must be exported.
        :type view: None or View
        :param export_options: The additional user provided export options.
        :type export_options: dict
        """

    @property
    @abstractmethod
    def file_extension(self) -> str:
        """
        The file extension used for any files generated by this exporter e.g. '.csv'
        :return a file extension starting with a dot.
        """

    @property
    @abstractmethod
    def can_export_table(self) -> bool:
        """
        Whether or not this exporter supports just exporting a table without a view.
        """

    @property
    @abstractmethod
    def supported_views(self) -> List[str]:
        """
        The list of view types supported by this exporter.
        """

    @property
    @abstractmethod
    def option_serializer_class(self):
        """
        The serializer used for any exporter specific options this exporter might need.
        These will be passed after validation to the .write_to_file method of the
        QuerysetSerializer returned by queryset_serializer_class below.
        """

    @property
    @abstractmethod
    def queryset_serializer_class(self):
        """
        A QuerysetSerializer class which implements this table exporter's specific
        type of export.
        """


class TableExporterRegistry(Registry):
    """
    The TableExporterRegistry allows you to register new TableExporters which allow the
    user to export tables and/or views of tables.
    """

    name = "table_exporter"

    def get_option_serializer_map(self):
        return {
            table_exporter_type.type: table_exporter_type.option_serializer_class
            for table_exporter_type in self.registry.values()
        }


table_exporter_registry = TableExporterRegistry()
