"""Client for interacting with ISS location data storage."""

import logging
from abc import ABC, abstractmethod

import firebase_admin
from cfg_environ.config import Config
from firebase_admin import credentials, firestore

from .iss_location import ISSLocation


class ISSLocationClient(ABC):
  '''
  Abstract base class for storing and reading ISS location data.
  '''

  @abstractmethod
  def add_iss_location(self, iss_location: ISSLocation) -> object:
    '''
    Add ISS location data to data store.
    
    :param self: Current ISSLocationClient instance.
    :param iss_location: ISS location data to add.
    :type iss_location: ISSLocation
    :return: Data store object added
    :rtype: object
    '''
    pass

  @abstractmethod
  def get_iss_locations(self, ts_from: int, ts_to: int) -> list:
    '''
    Get ISS location data on the UNIX timestamp window [ts_from, ts_to]
    
    :param self: Current ISSLocationClient instance.
    :param ts_from: UNIX timestamp for lower bound.
    :type ts_from: int
    :param ts_to: UNIX timestamp for upper bound.
    :type ts_to: int
    :return: List of ISSLocation objects.
    :rtype: list
    '''
    pass


class ISSLocationFirestoreClient(ISSLocationClient):
  '''
  Google Cloud Firestore client implementation for storing and reading 
  ISS location data.
  '''

  def __init__(
      self,
      config: Config,
      collection_name: str = 'iss_locations',
      logger: logging.Logger = logging.getLogger(__name__)
  ) -> None:
    self._config = config
    self._logger = logger
    self._firestore_client = None
    self._collection_name = collection_name

  def add_iss_location(self, iss_location: ISSLocation) -> object:
    timeout = self.firestore_config['CREATE']['TIMEOUT'] * 1000

    self._logger.warning('Adding iss_location [iss_location=%s, timeout=%s]',
                         iss_location, timeout)

    document_tuple = self.firestore_client.collection(
        self._collection_name).add(iss_location.iss_dict, timeout=timeout)
    document = document_tuple[1]

    self._logger.info('Added iss_location [document=%s]', document)

    return document

  def get_iss_locations(self, ts_from: int, ts_to: int) -> list:
    timeout = self.firestore_config['READ']['TIMEOUT'] * 1000
    self._logger.info(
        'Retrieving ISS location data [ts_from=%s, ts_to=%s, timeout=%s]',
        ts_from, ts_to, timeout)

    documents = self.firestore_client.collection(self._collection_name).where(
        'ts', '>=', ts_from).where('ts', '<=',
                                   ts_to).order_by('ts').get(timeout=timeout)

    iss_locations = [
        ISSLocation.from_dict(document.to_dict()) for document in documents
    ]

    self._logger.info('Retrieved ISS location data [iss_locations=%s]',
                      iss_locations)

    return iss_locations

  @property
  def firestore_config(self) -> dict:
    firestore_config = self._config.read_dict('FIRESTORE_CLIENT_CONFIG')

    return firestore_config

  @property
  def firestore_client(self) -> firestore.Client:
    if self._firestore_client is None:
      credentials_ad = credentials.ApplicationDefault()
      firebase_admin.initialize_app(credentials_ad)

      database_id = self.firestore_config['DATABASE_ID']

      self._logger.info('Initializing Firestore client [configuration=%s]',
                        self.firestore_config)

      self._firestore_client = firestore.client(database_id=database_id)

    return self._firestore_client
