from __future__ import absolute_import
from typing import List, Dict
from aoa.api_client import AoaClient

import abc


class BaseApi(object):
    path = ''

    def __init__(self, aoa_client=None):
        """
        constructor for api

        Parameters:
           aoa_client (AoaClient): AoaClient to use with api, if not specified will create a new AoaClient object
        """
        if aoa_client is None:
            aoa_client = AoaClient()
        self.aoa_client = aoa_client

    @abc.abstractmethod
    def _get_header_params(self):
        pass

    def generate_params(self, header_params: List[str], header_vals: List[str]):
        """
        returns generated parameters

        Parameters:
           header_params (List[str]): list of parameter names
           header_vals (List[str]): list of parameter values

        Returns:
            (dict): generated parameters
        """
        return dict(zip(header_params, header_vals))

    def required_params(self, param_names: List[str], dict_obj: Dict[str, str]):
        """
        checks required parameters, raises exception if the required parameter is missing in the dictionary

        Parameters:
           param_names (List[str]): list of required parameter names
           dict_obj (Dict[str, str]): dictionary to check for required parameters
        """
        for param in param_names:
            if param not in dict_obj:
                raise ValueError("Missing required value " + str(param))

    def find_all(self, projection: str = None, page: int = None, size: int = None, sort: str = None):
        """
        returns all entities

        Parameters:
           projection (str): projection type
           page (int): page number
           size (int): number of records in a page
           sort (str): column name and sorting order
           e.g. name?asc: sort name in ascending order, name?desc: sort name in descending order

        Returns:
            (dict): all entities
        """
        header_params = self._get_header_params()

        query_vars = ['projection', 'sort', 'page', 'size', 'sort']
        query_vals = [projection, sort, page, size, sort]
        query_params = self.generate_params(query_vars, query_vals)

        return self.aoa_client.get_request(
            self.path,
            header_params,
            query_params)

    def find_by_archived(self, archived: bool = False, projection: str = None, page: int = None, size: int = None, sort: str = None):
        """
        returns all entities by archived

        Parameters:
           projection (str): projection type
           page (int): page number
           size (int): number of records in a page
           sort (str): column name and sorting order e.g. name?asc / name?desc
           archived (bool): whether to return archived or unarchived entities

        Returns:
            (dict): all entities
        """
        header_params = self._get_header_params()

        query_vars = ['projection', 'sort', 'page', 'size', 'sort', 'archived']
        query_vals = [projection, sort, page, size, sort, archived]
        query_params = self.generate_params(query_vars, query_vals)

        return self.aoa_client.get_request(
            self.path + "search/findByArchived",
            header_params,
            query_params)

    def find_by_id(self, id: str, projection: str = None):
        """
        returns the entity

        Parameters:
           id (str): entity id(uuid) to find
           projection (str): projection type

        Returns:
            (dict): entity
        """
        header_params = self._get_header_params()

        query_vars = ['projection']
        query_vals = [projection]
        query_params = self.generate_params(query_vars, query_vals)

        return self.aoa_client.get_request(
            self.path + id,
            header_params,
            query_params)

    def archive(self, id: str):
        """
        archives the entity
        Parameters:
           id (str): entity id(uuid) to archive
           projection (str): projection type
        Returns:
            (dict): entity
        """
        header_params = self._get_header_params()

        return self.aoa_client.post_request(
            "/api/archives/" + self.type + "/" + id,
            header_params,
            {},
            {})

    def unarchive(self, id: str):
        """
        unarchives the entity
        Parameters:
           id (str): entity id(uuid) to unarchive
           projection (str): projection type
        Returns:
            (dict): entity
        """
        header_params = self._get_header_params()

        return self.aoa_client.delete_request(
            "/api/archives/" + self.type + "/" + id,
            header_params,
            {},
            {})
