from appservices.common.util import *

from base64 import b64encode
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from Crypto.Random import get_random_bytes
from Crypto.Protocol.KDF import scrypt
from base64 import b64encode, b64decode
import hmac
import hashlib

indian_bank_base_url = "https://uatindpay.indianbank.co.in/mobilityMiddleware/"
indian_bank_base_url_2 = "http://inbuat.kiya.ai:8866/mobilityMiddleware/"

INIT_VECTOR = b"9568463295684632"
key = "01428169FE856B02EA3998A4E0C92D84"
checksum_secret_key = "73127505498180881483015890950210"


def indian_bank_encrypt(data, key):
    if isinstance(data, dict):
        data = json.dumps(data)
    encrypted_data = ""
    try:
        # Same 16-byte IV used in Java
        # init_vector = b"9568463295684632"
        cipher = AES.new(key.encode("utf-8"), AES.MODE_GCM, nonce=INIT_VECTOR)

        # Encrypt and get tag
        ciphertext, tag = cipher.encrypt_and_digest(data.encode("utf-8"))

        # Java expects: base64(ciphertext + tag)
        encrypted_data = base64.b64encode(ciphertext + tag).decode("utf-8")

    except Exception as e:
        print(f"Error: {e}")

    return encrypted_data


def indian_bank_decrypt(data, key):
    decrypted_data = ""
    try:
        # Parameters
        # init_vector = b"9568463295684632"  # 16 bytes IV from Java
        GCM_TAG_LENGTH = 16  # in bytes

        # Decode the base64 encoded data
        decoded_data = base64.b64decode(data)

        # Java appends the GCM tag at the end
        ciphertext = decoded_data[:-GCM_TAG_LENGTH]
        tag = decoded_data[-GCM_TAG_LENGTH:]

        # Create AES-GCM cipher with the same IV and key
        cipher = AES.new(key.encode("utf-8"), AES.MODE_GCM, nonce=INIT_VECTOR)
        decrypted = cipher.decrypt_and_verify(ciphertext, tag)

        decrypted_data = decrypted.decode("utf-8")
        return json.loads(decoded_data)
    except Exception as e:
        print(f"Error: {e}")

    return decrypted_data


def input_data_for_checksum(data_dict, keys_list):
    return "|".join([f"{key}-{str(data_dict.get(key, '') or '').strip()}" for key in keys_list])

# Function to calculate the HMAC hash based on the check type (SHA-512 or SHA-256)


def get_indian_bank_checksum(check_sum_data, keys_list, secret_key, check_type=False):
    try:
        check_sum_data = input_data_for_checksum(check_sum_data, keys_list)
        print("checksum input:", check_sum_data)
        byte_key = secret_key.encode('utf-8')

        # Choose the hash algorithm based on the check type
        if check_type:
            print("sha256")
            hmac_algorithm = hashlib.sha256
        else:
            print("sha512")
            hmac_algorithm = hashlib.sha512
        # Create a new HMAC object with the selected hash algorithm and secret key
        hmac_obj = hmac.new(
            byte_key, check_sum_data.encode('utf-8'), hmac_algorithm)

        # Get the resulting hash in hexadecimal format
        result = hmac_obj.hexdigest().upper()
        print("checksum:", result)
        return result
    except Exception as e:
        print(f"Error: {e}")
        return None


def indian_bank_on_boarding(entityId, mobileNo, paymentAddress, merchantAccountNo, accountType, IFSC, merchantLegalName, channelId, aggregatorCode,  merchantId,  MCC, terminalId, userId, passwd, authToken, pan, fathername, dob, gstind, consumer_id, service_provider, dlNo, consent, storeId="", merchantType="", merchantGenre="", onboardingType="", OwnershipType="", latitude="", longitude="", creditCardTxn="", mdrConsent=""):
    merchantCreationResponseDict = {"responseStatus": 0, "result": ""}
    try:
        keys_list = ["entityId", "merchantId", "mobileNo", "paymentAddress", "merchantAccountNo",
                     "accountType", "IFSC", "merchantLegalName", "channelId", "aggregatorCode", "MCC", "terminalId"]

        indian_bank_request_body = {
            "entityId": "INB",
            "merchantId": "172536",
            "mobileNo": "9885200900",
            "paymentAddress": "test.viyona@indianbk",
            "merchantAccountNo": "7866330830",
            "accountType": "SAVINGS",
            "IFSC": "IDIB000M180",
            "merchantLegalName": "QAMAR",
            "channelId": "UPI",
            "aggregatorCode": "VIYONA",
            "MCC": "6012",
            "merchantType": "LARGE",
            "creditCardTxn": "N",
            "terminalId": "C1689250648888",
            "pan": "AGYPW4350P",
            "panFatherName": "QAMAR",
            "pandob": "05/06/1988",
            "panName": "QAMAR ABDULLAH",
            "gst": "37AAICD4800A1Z6",
            "ebConsent": "Y",
            "ebConsumerId": "1012395000",
            "ebServiceProvider": "BESCOM",
            "ebCaseid": "123456",
            "dlAdditionaldetails": "true",
            "dlConsent": "Y",
            "dlCaseId": "123456"}

        # indian_bank_request_body["authToken"] = "Test"

        indian_bank_request_body["Checksum"] = get_indian_bank_checksum(
            indian_bank_request_body, keys_list, checksum_secret_key)
        print("Before encrypt request body:", indian_bank_request_body)

        encryptedRequestBody = indian_bank_encrypt(
            indian_bank_request_body, key)
        try:
            url = indian_bank_base_url + "Merchants/onBoard"
            headers = {
                "Content-type": "application/json",
            }
            indian_bank_payload = {
                "data": encryptedRequestBody
            }
            print("After encrypt Request body:", indian_bank_payload)
            print(f"bank url - {url}")
            responseData = requests.post(
                url, json=indian_bank_payload, headers=headers)
            print(responseData.status_code, "Response status code")
            indian_response_json = responseData.json()
            print("Response of On Boarding:", indian_response_json)
            # return indian_response_json

            if responseData.status_code == 200:
                decreptResponse = indian_response_json
                onboardingResponse = {
                    "code": decreptResponse.get("code", ""),
                    "result": decreptResponse.get("result", ""),
                    "responseParameter": decreptResponse.get("responseParameter", {}),
                    "data": decreptResponse.get("data", {})
                }
                if onboardingResponse.get("code") in ["00", "03"]:
                    merchantCreationResponseDict.update({
                        "responseStatus": 1,
                        "result": onboardingResponse.get("result"),
                        "merchantId": onboardingResponse.get("responseParameter").get("merchantId", ""),
                        "merchantCode": onboardingResponse.get("responseParameter").get("merchantCode", ""),
                        "terminalId": onboardingResponse.get("data").get("terminalId", ""),
                        "orgTxnId": onboardingResponse.get("data").get("orgTxnId", "")
                    })
                elif onboardingResponse.get("code") == "01":
                    merchantCreationResponseDict.update({
                        "responseStatus": 0,
                        "result": onboardingResponse.get("result"),
                        "orgTxnId": onboardingResponse.get("data").get("orgTxnId", ""),
                        # "merchantId": onboardingResponse.get("data").get("merchantId",""),
                        "terminalId": onboardingResponse.get("data").get("terminalId", "")
                    })
                else:
                    merchantCreationResponseDict.update({
                        "responseStatus": 0,
                        "result": onboardingResponse.get("result", ""),

                    })
            else:
                merchantCreationResponseDict.update({
                    "responseStatus": 0,
                    "result": onboardingResponse.get("result"),

                })

            return merchantCreationResponseDict

        except Exception as e:
            app.logger.error(
                "Error during POST request or response processing: " + traceback.format_exc())
            merchantCreationResponseDict["result"] = "Failed to connect to the banking partner. Please try again later."
            return merchantCreationResponseDict

    except Exception as e:
        app.logger.error(
            "Error during request preparation: " + traceback.format_exc())
        merchantCreationResponseDict["result"] = "Our banking partner server is down, please try again later."
        return merchantCreationResponseDict


def indian_bank_onboard_status_check(entityId, mobileNo, paymentAddress, merchantAccountNo, accountType, IFSC, merchantLegalName, channelId, aggregatorCode, merchantId, MCC, terminalId):
    onBoardCheckStatusResponseDict = {"responseStatus": 0, "result": ""}
    try:
        keys_list = ["entityId", "merchantId", "mobileNo", "paymentAddress", "merchantAccountNo",
                     "accountType", "IFSC", "merchantLegalName", "channelId", "aggregatorCode", "MCC", "terminalId"]
        indian_bank_request_body = {
            "entityId": entityId,
            "mobileNo": mobileNo,
            "paymentAddress": paymentAddress,
            "merchantAccountNo": merchantAccountNo,
            "accountType": accountType,
            "IFSC": IFSC,
            "merchantLegalName": merchantLegalName,
            "channelId": channelId,
            "aggregatorCode": aggregatorCode,
            "merchantId": merchantId,
            "MCC": MCC,
            "terminalId": terminalId,
        }
        indian_bank_request_body["Checksum"] = get_indian_bank_checksum(
            indian_bank_request_body, keys_list, checksum_secret_key)
        encryptedRequestBody = indian_bank_encrypt(
            indian_bank_request_body, key)
        print("Before encrypt request body:", indian_bank_request_body)
        try:
            url = indian_bank_base_url_2 + "Merchants/checkOnBoardStatus"
            headers = {
                "Content-type": "application/json",
            }
            indian_bank_payload = {
                "data": encryptedRequestBody
            }
            print("After encrypt Request body:", indian_bank_payload)
            print(f"bank url - {url}")
            responseData = requests.post(
                url, json=indian_bank_payload, headers=headers)
            print(responseData.status_code, "Response status code")
            indian_response_json = responseData.json()
            print("Response of check on Board status:", responseData.text)
            # return indian_response_json
            if responseData.status_code == 200:
                decreptResponse = indian_response_json
                onboardStatusCheckResponse = {
                    "responseCode": decreptResponse.get("responseCode"),
                    "responseStatus": decreptResponse.get("responseStatus", ""),
                    "data": decreptResponse.get("data", {})
                }

                if onboardStatusCheckResponse.get("responseCode") == "00":
                    onBoardCheckStatusResponseDict.update(
                        {
                            "responseStatus": 1,
                            "result": "Success",
                            "txnID": onboardStatusCheckResponse.get("data").get("txnID", ""),
                            "merchantId": onboardStatusCheckResponse.get("data").get("merchantId", ""),
                            "terminalId": onboardStatusCheckResponse.get("data").get("terminalId", ""),
                            "message": onboardStatusCheckResponse.get("responseStatus", "")
                        }
                    )
                elif onboardStatusCheckResponse.get("responseCode") == "01":
                    onBoardCheckStatusResponseDict.update(
                        {
                            "responseStatus": 0,
                            "result": "Failure",
                            "txnID": onboardStatusCheckResponse.get("data").get("txnID", ""),
                            "merchantId": onboardStatusCheckResponse.get("data").get("merchantId", ""),
                            "terminalId": onboardStatusCheckResponse.get("data").get("terminalId", ""),
                            "message": onboardStatusCheckResponse.get("data").get("failureResaon", "")
                        }
                    )
                else:
                    onBoardCheckStatusResponseDict.update({
                        "responseStatus": 0,
                        "result": "Failure",
                    })

            else:
                onBoardCheckStatusResponseDict.update({
                    "responseStatus": 0,
                    "result": "Failure",
                })
            return onBoardCheckStatusResponseDict

        except Exception as e:
            app.logger.error(
                "Error during POST request or response processing: " + traceback.format_exc())
            onBoardCheckStatusResponseDict["result"] = "Failed to connect to the banking partner. Please try again later."
            return onBoardCheckStatusResponseDict

    except Exception as e:
        app.logger.error(
            "Error during request preparation: " + traceback.format_exc())
        onBoardCheckStatusResponseDict["result"] = "Our banking partner server is down, please try again later."
        return onBoardCheckStatusResponseDict


def indian_bank_query_transaction(entityId, txnId, txnRefNumber=""):
    queryTransationResponseDict = {"responseStatus": 0, "result": ""}
    try:
        keys_list = ["entityId", "txnId"]
        indian_bank_request_body = {
            "entityId": entityId,
            "txnId": txnId,
            "txnRefNumber": txnRefNumber
        }
        indian_bank_request_body["checkSum"] = get_indian_bank_checksum(
            indian_bank_request_body, keys_list, checksum_secret_key)
        print("Before encrypt request body:", indian_bank_request_body)
        encryptedRequestBody = indian_bank_encrypt(
            indian_bank_request_body, key)
        try:
            url = indian_bank_base_url_2 + "Merchants/QueryTransaction/V1/VIYONA"
            headers = {
                "Content-type": "application/json",
            }
            indian_bank_payload = {
                "data": encryptedRequestBody
            }
            print("After encrypt Request body:", indian_bank_payload)
            print(f"bank url - {url}")
            responseData = requests.post(
                url, json=indian_bank_payload, headers=headers)
            print(responseData.status_code, "Response status code")
            indian_response_json = responseData.json()
            print("Response of Query Transaction:", indian_response_json)
            # return indian_response_json
            if responseData:
                decreptResponse = indian_response_json
                queryTransationResponse = {
                    "code": decreptResponse.get("code"),
                    "result":  decreptResponse.get("result", ""),
                    "responseParameter":  decreptResponse.get("responseParameter", {}),
                    "data":  decreptResponse.get("data", {})
                }
                if queryTransationResponse.get("code") == "00":
                    queryTransationResponseDict.update({
                        "responseStatus": 1,
                        "result": "Success",
                        "entityID": queryTransationResponse.get("data").get("entityID"),
                        "mobileNo":  queryTransationResponse.get("data").get("mobileNo"),
                        "txnID":  queryTransationResponse.get("data").get("txnID"),
                        "txnType":  queryTransationResponse.get("data").get("txnType"),
                        "payerAddr":  queryTransationResponse.get("data").get("payerAddr"),
                        "payeeAddr":  queryTransationResponse.get("data").get("payeeAddr"),
                        "requestTime":  str(queryTransationResponse.get("data").get("requestTime")),
                        "responseStatus":  queryTransationResponse.get("data").get("responseStatus"),
                        "txnAmount":  queryTransationResponse.get("data").get("txnAmount"),
                        "payeeName":  queryTransationResponse.get("data").get("payeeName"),
                        "rrn":  queryTransationResponse.get("data").get("rrn")
                    })
                else:
                    queryTransationResponseDict["result"] = queryTransationResponse.get(
                        "result", "")
            else:
                queryTransationResponseDict["result"] = "Failure"

            return queryTransationResponseDict

        except Exception as e:
            app.logger.error(
                "Error during POST request or response processing: " + traceback.format_exc())
            queryTransationResponseDict["result"] = "Failed to connect to the banking partner. Please try again later."
            return queryTransationResponseDict

    except Exception as e:
        app.logger.error(
            "Error during request preparation: " + traceback.format_exc())
        queryTransationResponseDict["result"] = "Our banking partner server is down, please try again later."
        return queryTransationResponseDict


def indian_bank_refund(entityId, txnId, txnAmount, txnRefID="", OrgTxnRefNo=""):
    refundResponseDict = {"responseStatus": 0, "result": ""}
    try:
        keys_list = ["entityId", "txnId", "txnAmount"]
        indian_bank_request_body = {
            "entityId": entityId,
            "txnId": txnId,
            "txnRefID": txnRefID,
            "txnAmount": txnAmount,
            "OrgTxnRefNo": OrgTxnRefNo
        }
        indian_bank_request_body["checksum"] = get_indian_bank_checksum(
            indian_bank_request_body, keys_list, checksum_secret_key)
        print("Before encrypt request body:", indian_bank_request_body)
        encryptedRequestBody = indian_bank_encrypt(
            indian_bank_request_body, key)
        try:
            url = indian_bank_base_url_2 + "Refund/ProcessRefund/VIYONA"
            headers = {
                "Content-type": "application/json",
            }
            indian_bank_payload = {
                "data": encryptedRequestBody
            }
            print("After encrypt Request body:", indian_bank_payload)
            print(f"bank url - {url}")
            responseData = requests.post(
                url, json=indian_bank_payload, headers=headers)
            print(responseData.status_code, "Response status code")
            indian_response_json = responseData.json()
            print("Response of Refund:", indian_response_json)
            # return indian_response_json
            if responseData:
                decreptResponse = indian_response_json
                refundResponse = {
                    "status": decreptResponse.get("status"),
                    "msg": decreptResponse.get("msg"),
                    "response": decreptResponse.get("response"),
                    "responseCode": decreptResponse.get("responseCode"),
                    "cbsResponseCode": decreptResponse.get("cbsResponseCode"),
                    "mobileNo": decreptResponse.get("mobileNo"),
                    "responseParameter": decreptResponse.get("responseParameter", {}),
                    "bankRefNo": decreptResponse.get("bankRefNo"),
                    "opstatus": decreptResponse.get("opstatus"),
                    "transactionTime": decreptResponse.get("transactionTime"),
                    "rrn": decreptResponse.get("rrn"),
                    "Result": decreptResponse.get("Result"),
                    "paymentMode": decreptResponse.get("paymentMode"),
                    "orgTxnId": decreptResponse.get("orgTxnId")
                }
                if refundResponse.get("responseCode") == "00":
                    refundResponseDict.update({
                        "responseStatus": 1,
                        "result": "Success",
                        "status": refundResponse.get("status"),
                        "message": refundResponse.get("msg"),
                        "response": refundResponse.get("response"),
                        "cbsResponseCode": refundResponse.get("cbsResponseCode"),
                        "mobileNo": refundResponse.get("mobileNo"),
                        "bankRefNo": refundResponse.get("responseParameter").get("bankRefNo"),
                        "opstatus": refundResponse.get("responseParameter").get("opstatus"),
                        "transactionTime": refundResponse.get("responseParameter").get("transactionTime"),
                        "rrn": refundResponse.get("responseParameter").get("rrn"),
                        "Result": refundResponse.get("responseParameter").get("Result"),
                        "paymentMode": refundResponse.get("responseParameter").get("paymentMode"),
                        "orgTxnId": refundResponse.get("orgTxnId")
                    })
                else:
                    refundResponseDict.update({
                        "responseStatus": 0,
                        "result": "Failure",
                        "status": refundResponse.get("status"),
                        "message": refundResponse.get("response"),
                        "cbsResponseCode": refundResponse.get("cbsResponseCode"),
                        "orgTxnId": refundResponse.get("orgTxnId")
                    })
            else:
                refundResponseDict["result"] = "Failure"

            return refundResponseDict

        except Exception as e:
            app.logger.error(
                "Error during POST request or response processing: " + traceback.format_exc())
            refundResponseDict["result"] = "Failed to connect to the banking partner. Please try again later."
            return refundResponseDict

    except Exception as e:
        app.logger.error(
            "Error during request preparation: " + traceback.format_exc())
        refundResponseDict["result"] = "Our banking partner server is down, please try again later."
        return refundResponseDict


def indian_bank_vpa_deactivation(entityId, mobileNo, paymentAddress, merchantID=""):
    vpnDeactivationResponseDict = {"responseStatus": 0, "result": ""}
    try:
        keys_list = ["entityId", "mobileNo", "paymentAddress"]
        indian_bank_request_body = {
            "entityId": entityId,
            "mobileNo": mobileNo,
            "paymentAddress": paymentAddress,
            "merchantID": merchantID
        }
        indian_bank_request_body["checkSum"] = get_indian_bank_checksum(
            indian_bank_request_body, keys_list, checksum_secret_key)
        print("Before encrypt request body:", indian_bank_request_body)
        encryptedRequestBody = indian_bank_encrypt(
            indian_bank_request_body, key)
        try:
            url = indian_bank_base_url_2 + "vpadeactivation"
            headers = {
                "Content-type": "application/json",
            }
            indian_bank_payload = {
                "data": encryptedRequestBody
            }
            print("After encrypt Request body:", indian_bank_payload)
            responseData = requests.post(
                url, json=indian_bank_payload, headers=headers)
            print(responseData.status_code, "Response status code")
            indian_response_json = responseData.json()
            print("Response of VPA Deactivation:", indian_response_json)
            if responseData.status_code == 200:
                decreptResponse = indian_response_json
                vpnDeactivationResponse = {
                    "responseCode": decreptResponse.get("responseCode"),
                    "result": decreptResponse.get("result"),
                    "txnTimedate": decreptResponse.get("txnTimedate", ""),
                    "txnRefId": decreptResponse.get("txnRefId", "")
                }

                if vpnDeactivationResponse.get("responseCode") == "00":
                    vpnDeactivationResponseDict.update({
                        "responseStatus": 1,
                        "result": decreptResponse.get("result"),
                        "txnTimedate": str(decreptResponse.get("txnTimedate")),
                        "txnRefId": decreptResponse.get("txnRefId")
                    })
                else:
                    vpnDeactivationResponseDict["result"] = "Failure"
                    vpnDeactivationResponseDict["message"] = decreptResponse.get(
                        "result", "")
            else:
                vpnDeactivationResponseDict["result"] = "Failure"
            return vpnDeactivationResponseDict

        except Exception as e:
            app.logger.error(
                "Error during POST request or response processing: " + traceback.format_exc())
            vpnDeactivationResponseDict["result"] = "Failed to connect to the banking partner. Please try again later."
            return vpnDeactivationResponseDict

    except Exception as e:
        app.logger.error(
            "Error during request preparation: " + traceback.format_exc())
        vpnDeactivationResponseDict["result"] = "Our banking partner server is down, please try again later."
        return vpnDeactivationResponseDict


def indian_bank_callback(TransID, CustRefNo, Amount, TxnAuthDate, responseCode, approvalNumber, Status, AddInfo, Payer_VPA, Payee_VPA, OrderNo, TransactionNote, PSPRefNO="", CurrentStatusDesc="", TransactionType="", RefURL=""):
    callbackResponseDict = {"responseStatus": 0, "result": ""}
    try:
        keys_list = ["entityId", "mobileNo", "paymentAddress"]
        indian_bank_request_body = {
            "TransID": TransID,
            "CustRefNo": CustRefNo,
            "Amount": Amount,
            "TxnAuthDate": TxnAuthDate,
            "responseCode": responseCode,
            "approvalNumber": approvalNumber,
            "Status": Status,
            "AddInfo": AddInfo,
            "Payer_VPA": Payer_VPA,
            "Payee_VPA": Payee_VPA,
            "OrderNo": OrderNo,
            "TransactionNote": TransactionNote,
            "PSPRefNO": PSPRefNO,
            "CurrentStatusDesc": CurrentStatusDesc,
            "TransactionType": TransactionType,
            "RefURL": RefURL

        }
        indian_bank_request_body["Checksum"] = get_indian_bank_checksum(
            indian_bank_request_body, keys_list, checksum_secret_key)
        print("Before encrypt request body:", indian_bank_request_body)
        encryptedRequestBody = indian_bank_encrypt(
            indian_bank_request_body, key)
        try:
            url = indian_bank_base_url + ""
            headers = {
                "Content-type": "application/json",
            }
            indian_bank_payload = {
                "data": encryptedRequestBody
            }
            print("After encrypt Request body:", indian_bank_payload)
            responseData = requests.post(
                url, json=indian_bank_payload, headers=headers)
            print(responseData.status_code, "Response status code")
            indian_response_json = responseData.json()
            print("Response of VPA Deactivation:", indian_response_json)
            return indian_response_json
        except Exception as e:
            app.logger.error(
                "Error during POST request or response processing: " + traceback.format_exc())
            callbackResponseDict["result"] = "Failed to connect to the banking partner. Please try again later."
            return callbackResponseDict
    except Exception as e:
        app.logger.error(
            "Error during request preparation: " + traceback.format_exc())
        callbackResponseDict["result"] = "Our banking partner server is down, please try again later."
        return callbackResponseDict
