import json
import logging
import decimal

from harvest.exception import HarvestAbstractException

def make_response_headers_for_cors():
  return {
      "Access-Control-Allow-Headers": "Content-Type,Authorization,X-Amz-Date,X-Api-Key,X-Amz-Security-Token",
      "Access-Control-Allow-Methods": "OPTIONS,GET,POST,PUT,DELETE",
      "Access-Control-Allow-Origin": "*"
  }
  
def make_base_error_obj():
  return {
    "error": {
      "title": "",
      "message": "",
      "code": 0,
      "ref_url": ""
    }
  }

def make_response(status_code=200, body=None):

  logger = logging.getLogger(__name__)
  logger.addHandler(logging.NullHandler())
  logger.setLevel(logging.DEBUG)

  headers = make_response_headers_for_cors()

  if isinstance(body, HarvestAbstractException):
    ret = make_base_error_obj()
    ret["error"]["title"] = body.title
    ret["error"]["code"] = body.code
    ret["error"]["message"] = body.message
    body = ret
  elif isinstance(body, Exception):
    ret = make_base_error_obj()
    ret["error"]["title"] = "Unknown Internal Error"
    ret["error"]["code"] = 999
    ret["error"]["message"] = "unknown internal error."
    body = ret

  if "ResponseMetadata" in body:
    if body["ResponseMetadata"]["HTTPStatusCode"] == 200:
      body = {"message": "successfully"}

  try:
    body = json.dumps(body, cls = DecimalEncoder)
  except (NameError, ValueError, TypeError) as e:
    logger.error("json pare failed.")
    logger.exception(e)
    status_code = 500
    body = ""
  finally:
    logger.info("response http status code: {}".format(status_code))
    logger.info("response http headers: {}".format(headers))
    if len(body) <= 500:
      logger.info("response http body: {}".format(body))
    else:
      logger.info("response http body: {}...".format(body[:500]))

    return {
        "statusCode": status_code,
        "headers": headers,
        "body": body
    }

class DecimalEncoder(json.JSONEncoder):
  def default(self, o):
    if isinstance(o, decimal.Decimal):
      if float(o).is_integer():
        return int(o)
      else:
        return float(o)
    return super(DecimalEncoder, self).default(o)
