#!/usr/bin/python3
#encoding:utf-8


import os
import datetime
import json
import traceback
import requests
# user---  pip3 install pycryptodome
# root---  apt install python3-pycryptodome
from Crypto.Cipher import AES
import hashlib


__config__ = {
  'log_dir_path':'log'
}


def log(text, data):
  index = 1
  name = os.path.join(
    __config__['log_dir_path'],
    'payment_log_' + datetime.datetime.now().strftime('%Y%m%d%H%M%S%f') + '_1')
  while os.path.exists(name+ '.txt'):
    index += 1
    name = '_'.join(name.split('_')[:-1])+ '_'+str(index)
  savefile = open(name + '.txt', 'w', encoding="utf-8")
  try:
    savefile.write(str(text))
    savefile.write('\n')
  except:
    pass
  try:
    savefile.write(str(data))
  except:
    pass
  savefile.close()


def get_payment_form(payment_data):
  ok, key_values, ref = False, None, None
  try:
    amount = str(payment_data["amountcent_int"]/100)
    key_values = {
      "merchant_id":payment_data["merchant_id"],
      "order_id":payment_data["uid"],
      "currency":payment_data["currency_str"],
      "amount":amount,
      "redirect_url":payment_data["url_success"],
      "cancel_url":payment_data["url_cancel"],
      "language":"EN"
    }
    plainText=""
    for key, value in key_values.items():
      plainText += "%s=%s&" % (key, value)

    def pad(data):
      length = 16 - (len(data) % 16)
      data += chr(length)*length
      return data

    iv = b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f'
    plainText = pad(plainText)
    encDigest = hashlib.md5()
    encDigest.update(payment_data["encryption_key"].encode())
    xxx = encDigest.digest()
    enc_cipher = AES.new(xxx, AES.MODE_CBC, iv)
    encrypted_data = enc_cipher.encrypt(plainText.encode('utf-8')).hex()
    key_values["encRequest"] = encrypted_data
    key_values["access_code"] = payment_data["accessCode"]
    ok = True
  except:
    log("error2", str(traceback.format_exc())) # ошибка получения данных
  return ok, key_values, ref


def pad(data):
  length = 16 - (len(data) % 16)
  data += chr(length)*length
  return data

def encrypt_json(json_dict, workingKey):
  plainText=json.dumps(json_dict)
  iv = b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f'
  plainText = pad(plainText)
  encDigest = hashlib.md5()
  encDigest.update(workingKey.encode())
  xxx = encDigest.digest()
  enc_cipher = AES.new(xxx, AES.MODE_CBC, iv)
  encrypted_data = enc_cipher.encrypt(plainText.encode('utf-8')).hex()
  return encrypted_data

def decrypt_json(response_text, workingKey):
  header = "status=0&enc_response="
  cipherText = response_text[len(header):]
  cipherText
  iv = b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f'
  decDigest = hashlib.md5()
  decDigest.update(workingKey.encode())
  encryptedText = bytes.fromhex(cipherText)
  xxx = decDigest.digest()
  dec_cipher = AES.new(xxx, AES.MODE_CBC, iv)
  decryptedText = dec_cipher.decrypt(encryptedText)
  cut_binary_json = decryptedText[:decryptedText.rfind(b'}')+1]
  json_str = cut_binary_json.decode('ascii')
  json_dict = json.loads(json_str)
  return json_dict

def request_response(command, request_dict, payment_data):
  encrypted_data = encrypt_json(request_dict, payment_data["encryption_key"])
  post_data = {
    "enc_request":encrypted_data,
    "access_code":payment_data["accessCode"],
    "command":command,
    "request_type":"JSON",
    "response_type":"JSON",
    "version":"1.1"
  }
  response = requests.post(payment_data["api_url"], data=post_data).text
  invoice_response = decrypt_json(response, payment_data["encryption_key"])
  return invoice_response

def get_payment_link2(payment_data):
  ok, payment_link, ref = False, None, None
  try:
    amount = float(payment_data["amountcent_int"]/100)
    invoice_request_dict = {
      "customer_name": payment_data["customer_name"],
      "merchant_reference_no":payment_data["uid"],
      "invoice_description": payment_data["description"],
      "customer_email_id": "", #Blank incase bill_delivery_type is NONE
      "customer_email_subject": "", #Blank incase bill_delivery_type is NONE
      "valid_for": 2,
      "valid_type": "days",
      "customer_mobile_no":"", #Blank incase bill_delivery_type is NONE
      "currency": payment_data["currency_str"],
      "amount": amount,
      "bill_delivery_type": "none"
    }
    invoice_response = request_response("generateQuickInvoice", invoice_request_dict, payment_data)
    payment_id = invoice_response["invoice_id"]
    payment_link = invoice_response["tiny_url"]
    ok = True
  except:
    log("error2", str(traceback.format_exc())) # ошибка получения данных
  else:
    log("error", [payment_data, invoice_response])
  return ok, payment_link, ref


def ccavenue_check_payment(uid_str, ref, payment_data):
  check = False
  try:
    response = request_response("orderStatusTracker", {"order_no":uid_str}, payment_data)
    order_status = response["order_status"]
    if order_status in ["Shipped", "Successful"]:
      check = True
  except:
    log("error3", str(traceback.format_exc())) # ошибка получения данных
  return check, None

def ccavenue_create_payment_form(payment_data):
  ok, payment_form, ref = get_payment_form(payment_data)
  if not ok:
    raise Exception('Error: can not get_payment_link')
  return payment_form, ref


def ccavenue_create_payment_url(payment_data):
  ok, payment_link, ref = get_payment_link2(payment_data)
  if not ok:
    raise Exception('Error: can not get_payment_link')
  return payment_link, ref

