import logging
from rest_framework.decorators import authentication_classes, api_view, permission_classes
from rest_framework.permissions import IsAuthenticated

from app.encryption.hashid import CFHashIds
from backend.authentication import JWTAuthentication
from app.user.user import User
from app.payment.mandate import Payment
from django.shortcuts import render

from django.conf import settings
from django.http import HttpResponseRedirect

from paytmchecksum import PaytmChecksum

from app.api import api
from app.api.response_builder import ResponseBuilder
from app.loan_application.loan_application import LoanApplication
from app.loan_offer.loan_offer import LoanOffer
from app.util import util
from app.loan_application.views import validate_update_customer_consent
from app.user.views import validate_bank_details_inputs
from app.payment.views import validate_generate_payment_link_inputs, validate_setup_mandate_inputs
from app.loan_offer.views import validate_update_loan_offer_inputs

log = logging.getLogger(__name__)


@api_view(['POST'])
@authentication_classes((JWTAuthentication,))
@permission_classes((IsAuthenticated,))
def update_customer_consent(request):
    data = request.data
    response_builder = ResponseBuilder()

    application_id = data.get('application_id')
    application_id = CFHashIds().encode(application_id) if CFHashIds().encode(application_id) != '' else application_id
    latitude = data.get('latitude')
    longitude = data.get('longitude')
    status = data.get('status')
    user_ip = api.get_client_ip(request)

    status, loan_application = validate_update_customer_consent(application_id, status, user_ip)
    if util.is_status_failed(status):
        return response_builder.get_bad_request_response_solar()

    status = LoanApplication(loan_application).update_consent(latitude, longitude, status, user_ip, request)
    if util.is_status_failed(status):
        return response_builder.get_ok200_fail_response(status)

    return response_builder.solar_success().ok_200().message('Consent updated').get_solar_response()


@api_view(['POST'])
@authentication_classes((JWTAuthentication,))
@permission_classes((IsAuthenticated,))
def update_bank_details(request):
    data = request.data
    response_builder = ResponseBuilder()

    loan_application_id = data.get('application_id')

    account_number = data.get('account_number')
    ifsc_code = data.get('ifsc_code').upper()
    bank_name = data.get('bank_name')
    branch_name = data.get('branch_name')
    source = data.get('source')
    status, loan_application = validate_bank_details_inputs(
        loan_application_id, account_number, ifsc_code, bank_name, branch_name, source)
    if util.is_status_failed(status):
        if source == "no_touch":
            return (response_builder.solar_fail().ok_200().message('Please pass all the required parameter')
                    .get_solar_response())
        else:
            return response_builder.get_bad_request_response(status)

    status = LoanApplication(loan_application).update_bank_details(
        account_number, bank_name, ifsc_code, branch_name)
    if util.is_status_failed(status):
        return (response_builder.solar_fail().ok_200().message("Unable to verify Bank Account details")
                .get_solar_response())
    return (response_builder.solar_success().ok_200().message('Bank updated')
            .get_solar_response())


@api_view(['POST'])
@authentication_classes((JWTAuthentication,))
@permission_classes((IsAuthenticated,))
def generate_payment_link(request):
    response_builder = ResponseBuilder()
    data = request.data

    application_id = data.get('application_id')
    if str(application_id).isnumeric():
        application_id = int(application_id)
    application_id = CFHashIds().encode(application_id) if CFHashIds().encode(application_id) != '' else application_id
    redirect_url = data.get('redirect_url')

    status, loan_application = validate_generate_payment_link_inputs(application_id)
    if util.is_status_failed(status):
        return response_builder.get_bad_request_response(status)

    is_payment_required = LoanApplication(loan_application).is_payment_required2()

    payment_link = None
    if is_payment_required:
        payment_link = LoanApplication(loan_application).get_payment_link2(redirect_url)

    result = {
        'payment_link': payment_link,
        'is_payment_required': is_payment_required
    }

    return (response_builder.solar_success().ok_200().message('Payment link generated').result_object(result)
            .get_solar_response())


@api_view(['POST'])
@authentication_classes((JWTAuthentication,))
@permission_classes((IsAuthenticated,))
def setup_mandate(request):
    response_builder = ResponseBuilder()
    data = request.data

    loan_application_id = data.get("application_id")
    if loan_application_id.isnumeric():
        loan_application_id = int(loan_application_id)
    loan_application_id = CFHashIds().encode(loan_application_id) if CFHashIds().encode(
        loan_application_id) != '' else loan_application_id
    redirect_url = data.get("redirect_url", "")
    status, loan_application = validate_setup_mandate_inputs(loan_application_id)
    if util.is_status_failed(status):
        return response_builder.get_bad_request_response(status)

    loan_application = LoanApplication(loan_application)
    application_id = loan_application.get_loan_application_id()

    emi_calculation = LoanOffer.get_emi_calculation(application_id)
    if not emi_calculation:
        log.error('Emi calculations not found')
        return response_builder.get_bad_request_response(api.MANDATE_SETUP_REQUEST_FAILED)

    status, mandate_setup_link = loan_application.get_mandate_setup_link(
        application_id, emi_calculation, redirect_url)
    if util.is_status_failed(status):
        return response_builder.get_ok200_fail_response(status)

    result = {
        'mandate_registration_url': mandate_setup_link
    }

    return response_builder.solar_success().ok_200().message('Mandate link generated').result_object(
        result).get_solar_response()


@api_view(['POST'])
@authentication_classes((JWTAuthentication,))
@permission_classes((IsAuthenticated,))
def update_offer_details(request):
    data = request.data
    response_builder = ResponseBuilder()

    loan_offer_id = data.get('offer_id')
    loan_application_id = data.get('application_id')
    loan_application_id = CFHashIds().encode(int(loan_application_id)) if str(
        loan_application_id).isnumeric() else loan_application_id

    status, loan_application, loan_offer = validate_update_loan_offer_inputs(loan_offer_id, loan_application_id)
    if util.is_status_failed(status):
        return (response_builder.solar_fail().ok_200().message('Please pass all the required parameter')
                .get_solar_response())

    status = LoanOffer(loan_offer).update_loan_offer(loan_application, None)
    if util.is_status_failed(status):
        return (response_builder.solar_fail().ok_200().message('Please pass all the required parameter')
                .get_solar_response())

    return response_builder.solar_success().ok_200().message('Loan offer updated').get_solar_response()


@api_view(['POST'])
@authentication_classes((JWTAuthentication,))
@permission_classes((IsAuthenticated,))
def update_user_references(request):
    data = request.data
    response_builder = ResponseBuilder()

    references = data.get('references')
    loan_application_id = data.get('application_id')
    if str(loan_application_id).isnumeric():
        loan_application_id = int(loan_application_id)
    loan_application_id = CFHashIds().encode(loan_application_id) if CFHashIds().encode(loan_application_id) != '' else loan_application_id
    status, loan_application = validate_references_inputs(references, loan_application_id)
    if util.is_status_failed(status):
        return (response_builder.solar_fail().ok_200().message('Fail to save reference')
                .get_solar_response())

    status = LoanApplication(loan_application).update_references(references)
    if util.is_status_failed(status):
        return (response_builder.solar_fail().ok_200().message('Fail to save reference')
                .get_solar_response())
    return (response_builder.solar_success().ok_200().message('success')
            .get_solar_response())


def validate_references_inputs(references, loan_application_id):
    if not (references and len(references) == 2):
        return api.INVALID_INPUT, None

    loan_application = LoanApplication.get_loan_application(hashed_loan_application_id=loan_application_id)
    if not loan_application:
        return api.LOAN_APPLICATION_NOT_FOUND, None

    user = LoanApplication(loan_application).get_user()
    user_phone_number = User(user).get_plaintext_phone()
    for reference in references:
        if not ('name' in reference and 'phone_number' in reference and 'relationship' in reference and
                user_phone_number != reference['phone_number']):
            return api.INVALID_INPUT, None

    return api.SUCCESS, loan_application

def order_payment(request):
    # http://127.0.0.1:8000/v1/order/payment/?application_id=4ewpdErX6A1yDY1qvmy2
    # TODO check cookie for auth
    hashed_application_id = request.GET.get("application_id")
    redirect_url = request.GET.get("redirect_url")

    settings.REDIRECT_FRONTEND_HOME_URL = settings.CREDITFAIR_FRONTEND_HOME_URL

    if redirect_url:
        settings.REDIRECT_FRONTEND_HOME_URL = redirect_url

    application_id = LoanApplication.get_application_id_from_hash(hashed_application_id)
    if not application_id:
        return HttpResponseRedirect(
            f"{settings.FRONTEND_HOME_URL}/customer/loan/application/error/?message=Invalid Loan Application")

    loan_application = LoanApplication.get_loan_application(application_id)
    if not loan_application:
        return HttpResponseRedirect(
            f"{settings.FRONTEND_HOME_URL}/customer/loan/application/error/?message=Invalid Loan Application")

    redirect_url = f"{settings.BACKEND_HOME_URL}/v1/payment_call_back/"

    status, recorded_transactions_details = LoanApplication(loan_application).record_payment_transactions2()
    if util.is_status_failed(status):
        return HttpResponseRedirect(
            f"{settings.FRONTEND_HOME_URL}/v1/customer/loan/application/error/?message=Invalid Loan Application")

    status, payment_context, response = LoanApplication(loan_application).get_paytm_payment_context2(
        redirect_url,
        recorded_transactions_details.get('online_processing_id'),
        recorded_transactions_details.get('online_advanced_id'),
        recorded_transactions_details.get('online_insurance_id'))
    if util.is_status_failed(status):
        return HttpResponseRedirect(
            f"{settings.FRONTEND_HOME_URL}/v1/customer/loan/application/error/?message=Invalid Loan Application")

    Payment.update_order_id_in_transactions(payment_context['order_id'], recorded_transactions_details)

    if not payment_context:
        return HttpResponseRedirect(
            f"{settings.FRONTEND_HOME_URL}/v1/customer/loan/application/error/?message=Invalid Loan Application")

    return render(request, "paytm_place_order.html", payment_context)


@api_view(['POST'])
@authentication_classes((JWTAuthentication,))
@permission_classes((IsAuthenticated,))
def create_consent_document(request):
    data = request.data
    response_builder = ResponseBuilder()

    application_id = data.get('application_id')
    loan_application = LoanApplication.get_loan_application(hashed_loan_application_id=CFHashIds().encode(application_id))
    status = LoanApplication(loan_application).generate_consent_document(application_id)

    if util.is_status_failed(status):
        return response_builder.get_ok200_fail_response(status)

    return response_builder.solar_success().ok_200().message('Consent Document Generated').get_solar_response()


def validate_get_loan_offer_details_inputs(loan_application_id):
    if not loan_application_id:
        return api.INVALID_INPUT, None

    loan_application = LoanApplication.get_loan_application(hashed_loan_application_id=loan_application_id)
    if not loan_application:
        return api.INVALID_INPUT, None

    return api.SUCCESS, loan_application


@api_view(['POST'])
@authentication_classes((JWTAuthentication,))
@permission_classes((IsAuthenticated,))
def get_loan_summary(request):
    data = request.data
    response_builder = ResponseBuilder()

    loan_application_id = CFHashIds().encode(int(data.get('application_id')))

    status, loan_application = validate_get_loan_offer_details_inputs(loan_application_id)
    if util.is_status_failed(status):
        return response_builder.get_bad_request_response(status)

    status, offer_details = LoanOffer.get_loan_offer_details(loan_application)
    if util.is_status_failed(status):
        return response_builder.get_ok200_fail_response(status)

    result = {
        "offer": offer_details
    }
    return response_builder.solar_success().ok_200().message('Loan summary').result_object(result).get_solar_response()

@api_view(['POST', 'GET'])
def call_back(request):
    # {'BANKNAME': ['OTHERS'], 'BANKTXNID': ['777001310151559'], 'CHECKSUMHASH': ['kpK0c0FKFo2QT7rJK/qIQrokzYbPJZNVB9C
    # r4HJzKvK4JEqaiSA5wgyI6lRPukiGt0Pbc9DwQpkCINSsQUHn03/iZzgnmKzz+JEwk/xkzAM='],
    #  'CURRENCY': ['INR'], 'GATEWAYNAME': ['HDFC'], 'MID': ['KMglob21546666561510'], 'ORDERID': ['8fb8fb37c3'],
    #  'PAYMENTMODE': ['DC'], RESPCODE': ['810'], 'RESPMSG': ['Payment failed due to a technical error. Please try
    #  after some time.'], 'STATUS': ['TXN_FAILURE'], 'TXNAMOUNT': ['33399.00'], 'TXNDATE': ['2023-09-08 09:23:32.0'],
    #  'TXNID': ['20230908011650000906836261153896702']}

    if request.method == 'GET':
        return HttpResponseRedirect(
            f"{settings.REDIRECT_FRONTEND_HOME_URL}&paymentStatus=TXN_FAILURE")

    data = request.data

    checksum = data.get('CHECKSUMHASH')
    order_id = data.get('ORDERID')
    payment_status = data.get('STATUS')

    dict_data = dict(data)
    dict_data.pop('CHECKSUMHASH')
    normalized_data = {key: value[0] for key, value in dict_data.items()}

    status = PaytmChecksum.verifySignature(normalized_data, settings.PAYTM_MERCHANT_KEY, checksum)

    if util.is_status_failed(status):
        Payment.update_online_payment_transaction_status(order_id, "TXN_FAILURE")
        return HttpResponseRedirect(
            f"{settings.REDIRECT_FRONTEND_HOME_URL}&paymentStatus=TXN_FAILURE")

    Payment.update_online_payment_transaction_status(order_id, payment_status)

    if settings.REDIRECT_FRONTEND_HOME_URL.split('/')[-1] == 'customer':
        return HttpResponseRedirect(
            f"{settings.REDIRECT_FRONTEND_HOME_URL}&paymentStatus={payment_status}")
    else:
        if '?' in settings.REDIRECT_FRONTEND_HOME_URL:
            return HttpResponseRedirect(
                f"{settings.REDIRECT_FRONTEND_HOME_URL}&paymentStatus={payment_status}")
        else:
            return HttpResponseRedirect(
                f"{settings.REDIRECT_FRONTEND_HOME_URL}?paymentStatus={payment_status}")
