import json
import logging

from .abstract_op_service_monitor import AbstractOPServiceMonitor
from .op_json_encoder import OPJSONEncoderFallback


# This structure describes the order / priority for printing out request state information - the lists are read from top
# to bottom, and keys that come first in a list will be printed instead of any following keys.
STATE_GROUPS = [
  [ 'profile_validated', 'profile' ],
  [ 'input_data_validated', 'input_data' ]
]


# key -> (header, transform)
STATE_KEY_OUTPUTS = {
  'profile': 'p', # Input profile
  'profile_validated': 'pv', # Input profile (validated)
  'input_data': 'i', # Input data
  'input_data_validated': 'iv' # Input data (validated)
}


class RequestMonitor(AbstractOPServiceMonitor):

  def __init__(self):
    self.logger = logging.getLogger('op-request')

  def on_route_start(self, state):
    self.logger.info(json.dumps({ '_': 0, 'r': state['route'], 'ip': state['ip'], 'ua': state['ua'] }, separators=(',', ':')))

  def on_route_end(self, state):
    msg = { '_': 1, 'r': state['route'], 'ip': state['ip'], 'ua': state['ua'], 'c': state['response_code'] }
    for state_group in STATE_GROUPS:
      for key in state_group:
        if key in state:
          msg[ STATE_KEY_OUTPUTS[key] ] = state[key]
          break
    if 'o' in msg:
      # This is a special case: this output is already serialized
      del msg['o']

    packed = json.dumps(msg, cls=OPJSONEncoderFallback, separators=(',', ':'))
    if 'response_data' in state:
      # The 'response_data' is a special case because it is already serialized (and potentially large), so we can avoid
      # reserializing it if we just inject it directly
      packed = packed[:-1] + ',"o":' + state['response_data'] + '}'
    self.logger.info(packed)
