# © 2024 - 2025 criptomart
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

import logging
import json
import pprint
import requests

from odoo import models, api, exceptions, fields
from odoo.addons.payment.models.payment_provider import ValidationError
from odoo.tools.float_utils import float_compare
from odoo.tools.translate import _


_logger = logging.getLogger(__name__)


class TxRedsysPreAuth(models.Model):
    _inherit = 'payment.transaction'

    def _get_specific_rendering_values(self, processing_values):
        if self.provider_code != "redsys":
            return super()._get_specific_rendering_values(processing_values)
        redsys_values = dict(processing_values)
        merchant_parameters = self.provider_id._prepare_merchant_parameters(
            processing_values
        )
        redsys_values.update(
            {
                "api_url": self.provider_id._redsys_get_api_url(),
                "Ds_SignatureVersion": str(self.provider_id.redsys_signature_version),
                "Ds_MerchantParameters": merchant_parameters,
                "Ds_Signature": self.provider_id.sign_parameters(
                    self.provider_id.redsys_secret_key, merchant_parameters
                ),
            }
        )
        return redsys_values

    # chequea que el usuario cancele el pago 9915. cambia el stado de done a authorized
    @api.model
    def _get_redsys_state(self, status_code):
        if 0 <= status_code <= 100:
            return "authorized"
        elif status_code <= 203:
            return "pending"
        elif status_code == 400:
            return "cancel"
        elif status_code == 900:
            return "done"
        elif 912 <= status_code <= 9915:
            return "cancel"
        else:
            return "error"

    def _process_notification_data(self, data):
        if self.provider_code != "redsys":
            return super()._process_notification_data(data)
        params = self.merchant_params_json2dict(data)
        status_code = int(params.get('Ds_Response', '29999'))
        state = self._get_redsys_state(status_code)
        vals = {
            'state': state,
            'redsys_txnid': params.get('Ds_AuthorisationCode'),
        }
        state_message = ""
        feedback_error = False
        if state == 'done':
            vals['state_message'] = _('Ok: %s') % params.get('Ds_Response')
            self._set_done()
            self._finalize_post_processing()
        if state == 'authorized':
            vals['state_message'] = _('Auth Ok: %s') % params.get('Ds_Response')
            self._set_authorized()
            self._finalize_post_processing()
        elif state == 'pending':  # 'Payment error: code: %s.'
            state_message = _("Redsys: feedback error: %s" %(status_code))
            self._set_pending()
        elif state == 'cancel':  # 'Payment error: bank unavailable.'
            state_message = _("Redsys: feedback error: %s" %(status_code))
            self._set_canceled()
        else:
            state_message = _("Redsys: feedback error: %s" %(status_code))
            self._set_error(state_message)
            feedback_error = True
        if state_message:
            vals['state_message'] = state_message % {
                "status_code": params.get("Ds_Response"),
                "error_code": params.get("Ds_ErrorCode"),
            }
            if state == 'error':
                _logger.warning(vals['state_message'])
        self.write(vals)

    def _send_capture_request(self, amount_to_capture=None):
        self.ensure_one()
        self._ensure_provider_is_not_disabled()
        _logger.info('Redsys: Capturing transaction %s -- %s', self.reference, amount_to_capture)
        try:
            if amount_to_capture:
                values = {'amount': amount_to_capture}
            else:
                values = {'amount': sum(order.invoiced_amount for order in self.sale_order_ids)}
            values.update({'reference': self.reference})
            values.update({'transaction_type': '2'})
            response = self.provider_id.redsys_send_s2s_msg(values)
            if not response:
                raise exceptions.ValidationError('Error mandando mensaje rest');
            if response.get('errorCode', ''):
                raise exceptions.ValidationError('Ref %s: Error Code %s' %(self.reference, response.get('errorCode')))
            params = self.merchant_params_json2dict(response)
            _logger.info('Redsys: parameters received:\n%s', pprint.pformat(params))
            if params['Ds_Response'] == '0900' and params['Ds_Order'] == self.reference:
                self.provider_reference = params['Ds_AuthorisationCode']
                self._set_done()
                _logger.info('Confirmacion de preautorizacion realizada con exito para la transaccion %s', self.reference)
                message = ('Preautorizacion confirmada')
                self.sale_order_ids.message_post(body=message)
            else:
                raise exceptions.ValidationError('Error en confirmacion de preautorizacion tx: %s - %s', self.reference, params['Ds_Response'])
        except Exception as e:
            _logger.exception('Redsys: Error capturando preautorización transacción %s:\n%s', self.reference, str(e))
            raise exceptions.UserError(_('Error capturing preauthorization for transaction %s:\n%s') % (self.reference, str(e)))

    def _send_void_request(self, amount_to_void=None):
        self.ensure_one()
        self._ensure_provider_is_not_disabled()
        _logger.info('Redsys: Preauthorization cancel for transaction %s', self.reference)
        try:
            if amount_to_void:
                values = {'amount': amount_to_void}
            else:
                values = {'amount': self.amount}
            values.update({'reference': self.reference})
            values.update({'transaction_type': '9'})
            response = self.provider_id.redsys_send_s2s_msg(values)
            if not response:
                raise exceptions.ValidationError(_('error redsys_s2s_msg'))
            if response.get('errorCode', ''):
                raise exceptions.ValidationError('Ref %s: Error Code %s' % (self.reference, response.get('errorCode')))
            params = self.merchant_params_json2dict(response)
            _logger.info('Redsys: parameters received):\n%s', pprint.pformat(params))
            if params['Ds_Response'] == '0400' and params['Ds_Order'] == self.reference:
                self._set_canceled()
                _logger.info('Preautorización cancelada con éxito para la transacción %s', self.reference)
            else:
                raise exceptions.ValidationError('No se pudo cancelar la preautorización para la transacción %s - %s', self.reference, params['Ds_Response'])
        except Exception as e:
            _logger.exception('Redsys Error cancelando preautorización tx %s:\n%s', self.reference, str(e))
            raise exceptions.UserError(_('Error cancelling preauthorization for transaction %s:\n%s') % (self.reference, str(e)))
