import os, sys
import json
import logging
import traceback
from uuid import uuid4, UUID
from datetime import datetime

from harvest.commons.notifications.base_notification import BaseNotification
from harvest.commons.notifications.project_notification import ProjectNotification
from harvest.commons.notifications.place_notification import PlaceNotification
from harvest.commons.notifications.target_notification import TargetNotification
from harvest.commons.notifications.photo_notification import PhotoNotification
from harvest.commons.notifications.project_user_notification import ProjectUserNotification

class NotificationFactory():
  __stream_record = {}
  __created_at = ""
  __updated_at = ""
  host = None
  port = None
  formatter = logging.Formatter('[%(levelname)s]\t%(asctime)s.%(msecs)dZ\t%(aws_request_id)s\t[%(module)s#%(funcName)s %(lineno)d]\t%(message)s')
  logger = logging.getLogger()

  def __init__(self, host, port, stream_record=None):
    if stream_record:
      self.set_stream_record(stream_record)
    self.host = host
    self.port = port

    for handler in self.logger.handlers:
      handler.setFormatter(self.formatter)
      handler.setLevel(logging.DEBUG)

    self.logger = logging.getLogger(__name__)
    self.logger.setLevel(logging.DEBUG)

  def serialize(self, stream_record):
    if "NewImage" in stream_record["dynamodb"]:
      stream_record["dynamodb"]["NewImage"] = { k:list(v.values())[0] for k, v in stream_record["dynamodb"]["NewImage"].items() }

    if "OldImage" in stream_record["dynamodb"]:
      stream_record["dynamodb"]["OldImage"] = { k:list(v.values())[0] for k, v in stream_record["dynamodb"]["OldImage"].items() }

    if "Keys" in stream_record["dynamodb"]:
      stream_record["dynamodb"]["Keys"] = { k:list(v.values())[0] for k, v in stream_record["dynamodb"]["Keys"].items() }
    return stream_record

  def set_stream_record(self, stream_record):
    self.logger.info("setting stream record: %s" % str(stream_record))
    self.__stream_record = self.serialize(stream_record)
  
  def __select_notification_type(self):
    new_record = old_record = {}
    if "NewImage" in self.__stream_record["dynamodb"]:
      new_record = self.__stream_record["dynamodb"]["NewImage"]
    if "OldImage" in self.__stream_record["dynamodb"]:
      old_record = self.__stream_record["dynamodb"]["OldImage"]

    self.logger.info("split new record: %s" % str(new_record))
    self.logger.info("split old record: %s" % str(old_record))

    arn = self.__stream_record['eventSourceARN']
    src_table = arn.split(':')[5].split('/')[1]
    self.logger.info("happened event source arn: %s" % str(arn))
    self.logger.info("happened event table: %s" % str(src_table))

    notification = {}
    try:
      if src_table == "Projects":
        notification = ProjectNotification(self.__stream_record, self.host, self.port)
  
      elif src_table == "Places":
        notification = PlaceNotification(self.__stream_record, self.host, self.port)
  
      elif src_table == "Targets":
        
        if "photos" in old_record and "photos" in new_record and old_record["photos"] != new_record["photos"]:
          notification = PhotoNotification(self.__stream_record, self.host, self.port)
        else:
          notification = TargetNotification(self.__stream_record, self.host, self.port)
        
      elif src_table == "Roles":
        notification = ProjectUserNotification(self.__stream_record, self.host, self.port)

    except Exception as e:
      self.logger.error("select notification type failed... ")
      self.logger.exception(e)
  
    self.logger.info("selected notification type: %s" % notification.__class__.__name__)
    return notification

  def generate(self):
    notification = self.__select_notification_type()
    if isinstance(notification, BaseNotification):
      return notification.generate()
