'''
Reports alarms by making calls to an op-issue-traker service, which in turn are integrated into the op-dev management
dashboard.


Note: this implementation contains references to a buffering system - I would prefer to de-dupe issues before sending
them off to the server to save bandwidth, but I'm having some issues getting it to work correctly. I've left it
commented out for now.
The problem is that within the context of wsgi, your threads do not share data. This DOES work in regular python
(i.e. if you start your service with the --soft option). I would prefer that this behavior were the same within
the wsgi context, so longer term, I need to figure out how to fix that, and then our logic should work as-is.
https://inneka.com/programming/python/python-wsgi-multiprocessing-and-shared-data/
'''

import signal
import traceback

from op_service_client import OPServiceClient
from threading import Event, Thread

from ..abstract_base_reporter import AbstractBaseReporter


class Reporter(AbstractBaseReporter):


  BUFFER_TIME_S = 10
  def __init__(self, url=None, auth=None):
    '''
    Parameters:
      url: the string URL of the issue-tracker service
      auth: the auth configuration for connecting to the issue-tracker service
        {
          'route': <str>, # The route on the issue-tracker service that provides a valid token
          'params': <anything> # The params passed to the specified route to retrieve a valid token
        }
    '''
    self.issue_tracker_service = OPServiceClient(url, auth)

    # Minimize our API calls by using a buffer that is checked and dumped periodically
    # Warning: there is a chance that we will miss reporting some exceptions with this pattern if they happen within
    # 'BUFFER_TIME_S' seconds of a server going down, but the risk seems pretty minimal. Adding the signal hooks also
    # mitigates that.
    # self._issue_buffer = []
    
    # class Terminate(Exception):
    #   pass

    # exception_buffer_wait_event = Event()

    # def run():
    #   try:
    #     while not exception_buffer_wait_event.wait(self.BUFFER_TIME_S):
    #       self._submit_buffer()
    #   except Terminate:
    #     self._submit_buffer()

    # buffer_thread = Thread(target=run)

    # def handle():
    #   raise Terminate()

    # signal.signal(signal.SIGTERM, handle)
    # signal.signal(signal.SIGINT, handle)

    # buffer_thread.start()


  def _submit_buffer(self):
    try:
      by_msg = {}
      for issue in self._issue_buffer:
        existing_issue = by_msg.get(issue['msg'])
        if existing_issue:
          existing_issue['count']['n'] += 1
          existing_issue['count']['t_start'] = min(existing_issue['count']['t_start'], issue['count']['t_start'])
          existing_issue['count']['t_end'] = max(existing_issue['count']['t_end'], issue['count']['t_end'])
        else:
          by_msg[issue['msg']] = issue
      issues = list(by_msg.values())
      if issues:
        self.issue_tracker_service.call('report-issues', { 'issues': issues })
    except Exception as e:
      logging.error('Failed to report issues', e)
    finally:
      self._issue_buffer = []


  REPORT_ISSUE_KEYS = [ 'domain', 'exception', 'request', 'task', 'metadata', 'count' ]
  def _report_issue_unsafe(self, msg, **kwargs):
    issue = { 'msg': msg }
    for key, value in kwargs.items():
      if (value is not None) and (key in self.REPORT_ISSUE_KEYS):
        issue[key] = value

    # self._issue_buffer.append(issue)

    self.issue_tracker_service.call('report-issue', { 'issue': issue })
