from abc import ABC, abstractmethod
from typing import Union

class VinterAPIABC(ABC):
    
    @abstractmethod
    def __init__(self, api_key: str, asset_type: str):
        """This function takes in an api_key and asset_type and sets them as attributes of the class

        Parameters
        ----------
        api_key : str
            Your API key.
        asset_type : str
            The type of asset you want to get data for. The acceptable asset types listed in the AssetType enum.
        """
        pass

    @abstractmethod
    def get_all_active_symbols(self, frequency: str = None, symbol_only: bool = False) -> Union[list, dict]:
        """This function returns a dictionary of all the active symbols

        Returns
        -------
            A dictionary of all the active symbols

        """
        pass

    @abstractmethod
    def _get_url_by_asset_type(self, symbol: str) -> str:
        """This function takes in a symbol and returns the url to use to get the data

        Parameters
        ----------
        symbol : str
            The symbol of the asset you want to get data for.

        Returns
        -------
            The url to use to get the data

        """
        pass

    @abstractmethod
    def get_latest_data(self, symbol: str, limit: int = 1) -> dict:
        """It takes a symbol and a limit as parameters, and returns a dictionary of the latest data for
        that symbol

        Parameters
        ----------
        symbol : str
            The symbol of the asset you want to get data for.
        limit : int
            The number of data points to return.

        Returns
        -------
            A dictionary of the latest data for the symbol and limit.

        """
        pass

    @abstractmethod
    def get_latest_value(self, symbol: str) -> float:
        """This function takes in a symbol and returns the latest value for that symbol

        Parameters
        ----------
        symbol : str
            The symbol of the asset you want to get data for.

        Returns
        -------
            The latest value for the symbol

        """
        pass
    
    @abstractmethod
    def _filter_by_symbol(self, data: list, symbol: str) -> list:
        """This function takes in a list of data and a symbol and returns a list of data for that symbol

        Parameters
        ----------
        data : list
            A list of data
        symbol : str
            The symbol of the asset you want to get data for.

        Returns
        -------
            A list of data for the symbol

        """
        pass

    @abstractmethod
    def _get_active_asset_data(self, symbol: str) -> dict:
        """This function returns the data for the active asset

        Parameters
        ----------
        symbol : str
            The symbol of the asset you want to get data for.

        Returns
        -------
            A dictionary of the data for the active asset

        """
        pass

    @abstractmethod
    def get_current_rebalance_weight(self, symbol: str) -> dict:
        """This function returns the current rebalance weight of multi_assets symbol

        Returns
        -------
            Weight of the current rebalance of the multi_assets symbol
            
            OR
            
            ValueError if the symbol is not a present in the list of active symbols for asset_type multi_assets

        """
        pass

    @abstractmethod
    def get_contributions(self, symbol: str) -> dict:
        """This function returns the contributions of the single_assets symbol

        Returns
        -------
            A dictionary of the contributions of the single_assets symbol

            OR

            ValueError if the symbol is not a present in the list of active symbols for asset_type single_assets

        """
        pass

    @abstractmethod
    def get_previous_rebalance_date(self, symbol: str) -> Union[str, None]:
        """This function returns the previous rebalance date of multi_assets symbol

        Returns
        -------
            Date of the previous rebalance of the multi_assets symbol
            
            OR
            
            ValueError if the symbol is not a present in the list of active symbols for asset_type multi_assets
            
            OR
            
            None if the symbol Rebalance is not scheduled

        """
        pass

    @abstractmethod
    def get_previous_review_date(self, symbol: str) -> Union[str, None]:
        """This function returns the previous review date of multi_assets symbol

        Returns
        -------
            Date of the previous review of the multi_assets symbol
            
            OR
            
            ValueError if the symbol is not a present in the list of active symbols for asset_type multi_assets
            
            OR
            
            None if the symbol Review is not scheduled

        """
        pass

    @abstractmethod
    def get_next_review_date(self, symbol: str) -> Union[str, None]:
        """This function returns the next review date of multi_assets symbol

        Returns
        -------
            Date of the next review of the multi_assets symbol
            
            OR
            
            ValueError if the symbol is not a present in the list of active symbols for asset_type multi_assets
            
            OR
            
            None if the symbol Review is not scheduled

        """
        pass

    @abstractmethod
    def get_next_rebalance_date(self, symbol: str) -> Union[str, None]:
        """This function returns the next rebalance date of multi_assets symbol

        Returns
        -------
            Date of the next rebalance of the multi_assets symbol
            
            OR
            
            ValueError if the symbol is not a present in the list of active symbols for asset_type multi_assets
            
            OR
            
            None if the symbol Rebalance is not scheduled

        """
        pass

    @abstractmethod
    def get_next_rebalance_weight(self, symbol: str) -> Union[str, None]:
        """This function returns the next rebalance weight of multi_assets symbol

        Returns
        -------
            Weight of the next rebalance of the multi_assets symbol
            
            OR
            
            ValueError if the symbol is not a present in the list of active symbols for asset_type multi_assets
            
            OR

            None if the symbol Rebalance is not present in the payload

        """
        pass

    @abstractmethod
    def get_data_by_date(self, symbol: str, dates: Union[str, list]) -> dict:
        """This function takes in a symbol and a date and returns a dictionary of the data for that date

        This function is only for daily data.
        
        Parameters
        ----------
        symbol : str
            The symbol of the asset you want to get data for.
        date : str | list
            The date of the data you want to get. format: YYYY-MM-DD

        Returns
        -------
            A dictionary of the data

        """
        pass
           
    @abstractmethod
    def get_data_by_time(self, symbol: str, start: str, end: str = None, limit: int = 1000) -> dict:
        """This function takes in a symbol and a start and end date and returns a dictionary of the data
        for that period

        Parameters
        ----------
        symbol : str
            The symbol of the asset you want to get data for.
        start : str
            The start datatime . format: YYYY-MM-DDTHH:MM:SSZ or YYYY-MM-DDTHH:MM:SS.sssZ
        end : str
            The end datatime. format: YYYY-MM-DDTHH:MM:SSZ or YYYY-MM-DDTHH:MM:SS.sssZ

        Returns
        -------
            A dictionary of the data

        """
        pass

