import json
import signal
import traceback

from datetime import datetime, timezone
from op_service.logging_config import get_relative_sys_filename
from op_service_client import OPJSONEncoder
from threading import Event, Thread

from .abstract_op_service_monitor import AbstractOPServiceMonitor
from .op_json_encoder import OPJSONEncoderFallback
from .env import OP_DEV_METADATA


class OPErrorMonitor(AbstractOPServiceMonitor):


  def __init__(self, reporter):
    self.reporter = reporter


  def on_route_end(self, request_state):
    if (request_state['response_code'] < 500):
      return

    # Any 500-level error surfaced here should have 'exc_info' attached
    exc_type, exc_value, exc_traceback = request_state['exc_info']
    stack_summary = traceback.extract_tb(exc_traceback)
    cause = stack_summary[-1]
    rel_file = get_relative_sys_filename(cause.filename)

    msg = '%s -> %s - %s %s#%s' % (request_state['route'], request_state['response_code'], exc_type.__name__, rel_file, cause.lineno)
    now = datetime.now(timezone.utc)
    issue = {
      'exception': {
        'msg': repr(exc_value),
        'traceback': stack_summary.format()
      },
      'request': {
        'route': request_state['route'],
        'profile': request_state.get('profile_validated'),
        'input_data': request_state.get('input_data'),
        'response_code': request_state['response_code'],
        'response_data': request_state.get('response_data')
      },
      'metadata': OP_DEV_METADATA,
      'count': {
        'n': 1,
        't_start': now.isoformat(),
        't_end': now.isoformat()
      }
    }

    for key in [ 'profile', 'input_data', 'response_data' ]:
      if issue['request'][key]:
        issue['request'][key] = json.dumps(issue['request'][key], cls=OPJSONEncoderFallback)

    self.reporter.report_issue(msg, **issue)
