import logging

from datetime import date, timedelta

from app import app # This is required to initialize the database.
from data.database import Repository, LogEntry, RepositoryActionCount, db_random_func
from workers.worker import Worker

POLL_PERIOD_SECONDS = 10

logger = logging.getLogger(__name__)

def count_repository_actions():
  """ Aggregates repository actions from the LogEntry table and writes them to
      the RepositoryActionCount table. Returns the number of repositories for
      which actions were logged. Returns 0 when there is no more work.
      """
  try:
    # Get a random repository to count.
    today = date.today()
    yesterday = today - timedelta(days=1)
    has_yesterday_actions = (RepositoryActionCount
                             .select(RepositoryActionCount.repository)
                             .where(RepositoryActionCount.date == yesterday))

    to_count = (Repository
                .select()
                .where(~(Repository.id << (has_yesterday_actions)))
                .order_by(db_random_func()).get())

    logger.debug('Counting: %s', to_count.id)

    actions = (LogEntry
               .select()
               .where(LogEntry.repository == to_count,
                      LogEntry.datetime >= yesterday,
                      LogEntry.datetime < today)
               .count())

    # Create the row.
    try:
      RepositoryActionCount.create(repository=to_count, date=yesterday, count=actions)
      return 1
    except:
      logger.exception('Exception when writing count')
  except Repository.DoesNotExist:
    logger.debug('No further repositories to count')

  return 0


class RepositoryActionCountWorker(Worker):
  def __init__(self):
    super(RepositoryActionCountWorker, self).__init__()
    self.add_operation(self._count_repository_actions, POLL_PERIOD_SECONDS)

  def _count_repository_actions(self):
    """ Counts actions for a random repository for the previous day. """
    count_repository_actions()

if __name__ == "__main__":
  worker = RepositoryActionCountWorker()
  worker.start()