<?php
/**
 * Authorize.net Gateway Tokenization eCheck Class
 *
 * Handles eCheck Tokenization API payments through Authorize.net gateway for WooCommerce.
 *
 * @package    Authorize_Net_Payments_For_Woocommerce
 * @subpackage Authorize_Net_Payments_For_Woocommerce/includes
 * @since      1.0.0
 */

if (! defined('ABSPATH')) {
    exit;
}

use net\authorize\api\contract\v1 as AnetAPI;
use net\authorize\api\controller as AnetController;

require_once plugin_dir_path(__FILE__) . '../../trait-anet-customer-profile.php';
/**
 * Handles Authorize.net eCheck tokenization functionality.
 *
 * This class manages the creation, storage, and usage of customer profiles
 * for eCheck payments through the Authorize.net payment gateway, including
 * tokenization for secure payment processing.
 *
 * @since 1.0.0
 */
class Anet_ECheck_Tokenization
{
    use Anet_Customer_Profile;
    /**
     * Meta key for storing Authorize.net customer profile ID for eCheck
     *
     * @var mixed
     */
    private $meta_key;
    /**
     * Helper for API request 
     *
     * @var mixed
     */
    private $helper;
    /**
     * Constructor for the Authorize.net eCheck tokenization class.
     *
     * Initializes the meta key used for storing customer profile information.
     * Sets up the helper for request.
     *
     * @since 1.0.0
     */
    public function __construct()
    {
        $this->meta_key = $this->get_customer_profile_meta_key(true);
        $this->helper = new Anet_Api_Helper(ANET_PAYMENT_TYPE_ECHECK);
    }
    /**
     * Create a customer profile for My Account Section.
     *
     * @param int   $user_id      The user ID.
     * @param array $payment_args Payment arguments.
     * @return array Result of the profile creation.
     *
     * @since 1.0.0
     */
    public function create_customer_profile($user_id, $payment_args)
    {
        try {
            $customer_profile_id = get_user_meta($user_id, $this->meta_key, true);
            if ($customer_profile_id) {
                // Customer profile exists, just create payment profile.
                return $this->create_customer_payment_profile($customer_profile_id, $user_id, $payment_args);
            }
            $merchant_auth = $this->helper->merchant_authentication_request();
            $customer_profile = $this->helper->create_customer_profile_request($user_id, $payment_args);
            $validation_mode = $this->helper->validation_mode();
            $request = new AnetAPI\CreateCustomerProfileRequest();
            $request->setMerchantAuthentication($merchant_auth);
            $request->setProfile($customer_profile);
            $request->setValidationMode($validation_mode);
            $sanitized_request = Anet_Api_Helper::mask_tokenization_request($request); // Call the mask_tokenization_request function.
            Anet_Setting_Helper::log("\ncreateCustomerProfileRequest:\n" . $sanitized_request, ANET_PAYMENT_TYPE_ECHECK, 'debug');
            $controller = new AnetController\CreateCustomerProfileController($request);
            $response = $controller->executeWithApiResponse($this->helper->controller_response());
            $customer_profile_id = $response->getCustomerProfileId();
            $payment_profile_id_list = $response->getCustomerPaymentProfileIdList();
            $validation_direct_response_list = $response->getValidationDirectResponseList();
            Anet_Setting_Helper::log(
                "\ncreateCustomerProfileResponse:\n" .
                    wp_json_encode([
                        'customerProfileId' => $customer_profile_id,
                        'customerPaymentProfileIdList' => $payment_profile_id_list,
                        'validationDirectResponseList' => $validation_direct_response_list,
                        'messages' => $response->getMessages(),
                    ], JSON_PRETTY_PRINT),
                ANET_PAYMENT_TYPE_ECHECK, 'debug'
            );
            if (ANET_SANDBOX_STATUS_AUTHORIZED === $response->getMessages()->getResultCode() && null !== $response) {
                $customer_profile_id = $response->getCustomerProfileId();
                $payment_profile_id = $response->getCustomerPaymentProfileIdList()[0];
                update_user_meta($user_id, $this->meta_key, $customer_profile_id);
                $payment_profile_result = $this->get_customer_payment_profile($user_id, $payment_profile_id, true);
                if ($payment_profile_result['result']) {
                    return [
                        'result' => true,
                        'customerProfileId' => $customer_profile_id,
                        'customerPaymentProfileId' => $payment_profile_id
                    ];
                }
            }
            return [
                'result' => false,
            ];
        } catch (Throwable $e) {
            Anet_Setting_Helper::log("\nException:\n" . $e->getMessage(), ANET_PAYMENT_TYPE_ECHECK, 'error');
            return [
                'result' => false,
            ];
        }
    }
    /**
     * Create a customer payment profile for My Account Section.
     *
     * @param string $customer_profile_id The customer profile ID.
     * @param int    $user_id             The user ID.
     * @param array  $payment_args        Payment arguments.
     * @return array Result of the payment profile creation.
     *
     * @since 1.0.0
     */
    public function create_customer_payment_profile($customer_profile_id, $user_id, $payment_args)
    {
        try {
            $merchant_auth = $this->helper->merchant_authentication_request();
            $payment_profile = $this->helper->create_customer_payment_profile_request($payment_args);
            $validation_mode = $this->helper->validation_mode();
            $request = new AnetAPI\CreateCustomerPaymentProfileRequest();
            $request->setMerchantAuthentication($merchant_auth);
            $request->setCustomerProfileId($customer_profile_id);
            $request->setPaymentProfile($payment_profile);
            $request->setValidationMode($validation_mode);
            $sanitized_request = Anet_Api_Helper::mask_tokenization_request($request); // Call the mask_tokenization_request function.
            Anet_Setting_Helper::log("\ncreateCustomerPaymentProfileRequest:\n" . $sanitized_request, ANET_PAYMENT_TYPE_ECHECK, 'debug');
            $controller = new AnetController\CreateCustomerPaymentProfileController($request);
            $response = $controller->executeWithApiResponse($this->helper->controller_response());
            $customer_profile_id = $response->getCustomerProfileId();
            $customer_payment_profile_id = $response->getCustomerPaymentProfileId();
            $validation_direct_response = $response->getValidationDirectResponse();
            Anet_Setting_Helper::log(
                "\ncreateCustomerPaymentProfileResponse:\n" .
                    wp_json_encode([
                        'customerProfileId' => $customer_profile_id,
                        'customerPaymentProfileId' => $customer_payment_profile_id,
                        'validationDirectResponse' => $validation_direct_response,
                        'messages' => $response->getMessages(),
                    ], JSON_PRETTY_PRINT),
                ANET_PAYMENT_TYPE_ECHECK, 'debug'
            );
            if (ANET_SANDBOX_STATUS_AUTHORIZED === $response->getMessages()->getResultCode() && null !== $response) {
                $payment_profile_id = $response->getCustomerPaymentProfileId();
                $payment_profile_result = $this->get_customer_payment_profile($user_id, $payment_profile_id, true);
                if ($payment_profile_result['result']) {
                    return [
                        'result' => true,
                        'customerProfileId' => $customer_profile_id,
                        'customerPaymentProfileId' => $payment_profile_id
                    ];
                }
            }
            return [
                'result' => false,
            ];
        } catch (Throwable $e) {
            Anet_Setting_Helper::log("\nException:\n" . $e->getMessage(), ANET_PAYMENT_TYPE_ECHECK, 'error');
            return [
                'result' => false,
            ];
        }
    }
    /**
     * Get customer payment profile details.
     *
     * Retrieves payment profile information from Authorize.net API
     * and optionally stores the details as a payment token.
     *
     * @param int    $user_id                    The WordPress user ID.
     * @param string $customer_payment_profile_id The payment profile ID from Authorize.net.
     * @param bool   $store_card_details         Whether to store card details as token.
     *
     * @return array Payment profile details or empty array on failure.
     *
     * @since 1.0.0
     */
    public function get_customer_payment_profile($user_id, $customer_payment_profile_id, $store_card_details = false)
    {
        try {
            $customer_profile_id = get_user_meta($user_id, $this->meta_key, true);
            if (!$customer_profile_id) {
                return [];
            }
            $merchant_auth = $this->helper->merchant_authentication_request();
            $request = new AnetAPI\GetCustomerPaymentProfileRequest();
            $request->setMerchantAuthentication($merchant_auth);
            $request->setCustomerProfileId($customer_profile_id);
            $request->setCustomerPaymentProfileId($customer_payment_profile_id);
            // Only set if your SDK version supports it.
            if (method_exists($request, 'setIncludeIssuerInfo')) {
                $request->setIncludeIssuerInfo(true);
            }
            $controller = new AnetController\GetCustomerPaymentProfileController($request);
            $response = $controller->executeWithApiResponse($this->helper->controller_response());
            if (ANET_SANDBOX_STATUS_AUTHORIZED === $response->getMessages()->getResultCode() && null !== $response) {
                $payment_profile = $response->getPaymentProfile();
                $bank_account = $payment_profile->getPayment()->getBankAccount();
                if ($store_card_details) {
                    $this->store_echeck_details($user_id, $customer_payment_profile_id, $response->getPaymentProfile());
                }
                $issuer_info = method_exists($response, 'getIssuerInfo') ? $response->getIssuerInfo() : null;
                return [
                    'result' => true,
                    'account_type' => $bank_account->getAccountType(),
                    'account_number' => $bank_account->getAccountNumber(),
                    'routing_number' => $bank_account->getRoutingNumber(),
                    'name_on_account' => $bank_account->getNameOnAccount()
                ];
            } else {
                return [
                    'result' => false,
                ];
            }
        } catch (Throwable $e) {
            Anet_Setting_Helper::log("\nException:\n" . $e->getMessage(), ANET_PAYMENT_TYPE_ECHECK, 'error');
            return [
                'result' => false,
            ];
        }
    }
    /**
     * Storing a card through checkout page.
     *
     * @param string   $customer_profile_id The customer profile ID.
     * @param string   $transaction_id      The transaction ID.
     * @param int|null $user_id             The user ID (optional).
     * @return array Result of the profile creation from transaction.
     *
     * @since 1.0.0
     */
    public function create_customer_payment_profile_from_transaction($customer_profile_id, $transaction_id, $user_id = null)
    {
        try {
            $merchant_auth = $this->helper->merchant_authentication_request();
            $request = new AnetAPI\CreateCustomerProfileFromTransactionRequest();
            $request->setMerchantAuthentication($merchant_auth);
            if ($customer_profile_id) {
                $request->setCustomerProfileId($customer_profile_id);
            }
            $request->setTransId($transaction_id);
            $sanitized_request = Anet_Api_Helper::mask_tokenization_request($request); // Call the mask_tokenization_request function.
            Anet_Setting_Helper::log("\ncreateCustomerProfileFromTransactionRequest:\n" . $sanitized_request, ANET_PAYMENT_TYPE_ECHECK, 'debug');
            $controller = new AnetController\CreateCustomerProfileFromTransactionController($request);
            $response = $controller->executeWithApiResponse($this->helper->controller_response());
            // Log the response.
            Anet_Setting_Helper::log(
                "\ncreateCustomerProfileFromTransactionResponse:\n" .
                    wp_json_encode([
                        'customerProfileId' => $response->getCustomerProfileId(),
                        'customerPaymentProfileIdList' => $response->getCustomerPaymentProfileIdList(),
                        'customerShippingAddressIdList' => $response->getCustomerShippingAddressIdList(),
                        'validationDirectResponseList' => $response->getValidationDirectResponseList(),
                        'messages' => $response->getMessages(),
                    ], JSON_PRETTY_PRINT),
                ANET_PAYMENT_TYPE_ECHECK, 'debug'
            );
            if (ANET_SANDBOX_STATUS_AUTHORIZED === $response->getMessages()->getResultCode() && null !== $response) {
                $customer_profile_id = $response->getCustomerProfileId();
                $payment_profile_id_list = $response->getCustomerPaymentProfileIdList();
                update_user_meta($user_id, $this->meta_key, $customer_profile_id);
                $payment_profile_result = $this->get_customer_payment_profile($user_id, end($payment_profile_id_list), true);
                if ($payment_profile_result['result']) {
                    return [
                        'result' => true,
                        'customerProfileId' => $customer_profile_id,
                        'customerPaymentProfileId' => end($payment_profile_id_list)
                    ];
                }
            }
            return [
                'result' => false,
                'error' => $response ? $response->getMessages() : 'No response'
            ];
        } catch (Throwable $e) {
            Anet_Setting_Helper::log("\nException:\n" . $e->getMessage(), ANET_PAYMENT_TYPE_ECHECK, 'error');
            return [
                'result' => false,
            ];
        }
    }
    /**
     * Process stored card/eCheck payment.
     *
     * Processes a payment transaction using previously stored eCheck
     * payment information from a customer payment profile.
     *
     * @param WC_Order $order        The WooCommerce order object.
     * @param array    $payment_args Array of payment arguments and settings.
     *
     * @return array Result of the payment processing operation.
     *
     * @since 1.0.0
     */
    public function stored_card($order, $payment_args = array())
    {
        try {
            // Set up merchant authentication.
            $merchant_auth = $this->helper->merchant_authentication_request();
            $transaction_request = $this->helper->stored_card_request($payment_args);
            // Create the transaction request.
            $request = new AnetAPI\CreateTransactionRequest();
            $request->setMerchantAuthentication($merchant_auth);
            $request->setTransactionRequest($transaction_request);
            // Set the refId.
            if (isset($payment_args['refId'])) {
                $request->setRefId($payment_args['refId']);
            }
            // Log the request with masked data.
            $sanitized_request = Anet_Api_Helper::mask_sensitive_data($request); // Call the mask_sensitive_data function.
            Anet_Setting_Helper::log("\ncreateTransactionRequest:\n" . $sanitized_request, ANET_PAYMENT_TYPE_ECHECK, 'debug');
            // Execute the request.
            $controller = new AnetController\CreateTransactionController($request);
            $response = $controller->executeWithApiResponse($this->helper->controller_response());
            return Anet_ECheck_Api::process_response($response);
        } catch (Throwable $e) {
            Anet_Setting_Helper::log("\nException:\n" . $e->getMessage(), ANET_PAYMENT_TYPE_ECHECK, 'error');
            return array("success" => false);
        }
    }
    /**
     * Update customer payment profile with new eCheck details.
     *
     * Updates an existing customer payment profile in Authorize.net
     * with new bank account information for eCheck payments.
     *
     * @param int    $user_id                     The WordPress user ID.
     * @param string $customer_profile_id         The customer profile ID from Authorize.net.
     * @param string $customer_payment_profile_id The payment profile ID to update.
     * @param string $new_account_number          The new bank account number.
     * @param string $new_routing_number          The new bank routing number.
     * @param string $new_account_type            The new account type (checking/savings).
     * @param string $new_name_on_account         The new name on the bank account.
     *
     * @return array Result of the update operation with success status and message.
     *
     * @since 1.0.0
     */
    public function update_customer_payment_profile($user_id, $customer_profile_id, $customer_payment_profile_id, $new_account_number, $new_routing_number, $new_account_type, $new_name_on_account)
    {
        try {
            // 1. Fetch the current payment profile.
            $merchant_auth = $this->helper->merchant_authentication_request();
            $get_request = new AnetAPI\GetCustomerPaymentProfileRequest();
            $get_request->setMerchantAuthentication($merchant_auth);
            $get_request->setCustomerProfileId($customer_profile_id);
            $get_request->setCustomerPaymentProfileId($customer_payment_profile_id);
            $get_controller = new AnetController\GetCustomerPaymentProfileController($get_request);
            $get_response = $get_controller->executeWithApiResponse($this->helper->controller_response());
            if (ANET_SANDBOX_STATUS_AUTHORIZED !== $get_response->getMessages()->getResultCode() || !$get_response) {
                return [
                    'result' => false,
                    'message' => __('Could not fetch current payment profile.', 'authorize-net-payments-for-woocommerce')
                ];
            }
            $current_profile = $get_response->getPaymentProfile();
            // 2. Update the bank account info.
            $bank_account = new AnetAPI\BankAccountType();
            $bank_account->setAccountNumber($new_account_number);
            $bank_account->setRoutingNumber($new_routing_number);
            $bank_account->setAccountType($new_account_type);
            $bank_account->setNameOnAccount($new_name_on_account);
            $payment = new AnetAPI\PaymentType();
            $payment->setBankAccount($bank_account);
            // 3. Build the updated payment profile object.
            $updated_profile = new AnetAPI\CustomerPaymentProfileExType();
            $updated_profile->setCustomerPaymentProfileId($customer_payment_profile_id);
            $updated_profile->setPayment($payment);
            // Copy billing address if present.
            if ($current_profile->getBillTo()) {
                $updated_profile->setBillTo($current_profile->getBillTo());
            }
            $validation_mode = $this->helper->validation_mode();
            // 4. Send the update request.
            $request = new AnetAPI\UpdateCustomerPaymentProfileRequest();
            $request->setMerchantAuthentication($merchant_auth);
            $request->setCustomerProfileId($customer_profile_id);
            $request->setPaymentProfile($updated_profile);
            $request->setValidationMode($validation_mode);
            $sanitized_request = Anet_Api_Helper::mask_sensitive_data($request); // Call the mask_sensitive_data function.
            Anet_Setting_Helper::log("\nupdateCustomerPaymentProfileRequest:\n" . $sanitized_request, ANET_PAYMENT_TYPE_ECHECK, 'debug');
            $controller = new AnetController\UpdateCustomerPaymentProfileController($request);
            $response = $controller->executeWithApiResponse($this->helper->controller_response());
            // Log the response.
            Anet_Setting_Helper::log(
                "\nupdateCustomerPaymentProfileResponse:\n" .
                    wp_json_encode([
                        'validationDirectResponse' => $response->getValidationDirectResponse(),
                        'messages' => $response->getMessages(),
                    ], JSON_PRETTY_PRINT),
                ANET_PAYMENT_TYPE_ECHECK, 'debug'
            );
            $validation_mode = $this->helper->validation_mode();
            if (ANET_SANDBOX_STATUS_AUTHORIZED === $response->getMessages()->getResultCode() && $response) {
                // Optionally validate the updated profile.
                $validate_request = new AnetAPI\ValidateCustomerPaymentProfileRequest();
                $validate_request->setMerchantAuthentication($merchant_auth);
                $validate_request->setCustomerProfileId($customer_profile_id);
                $validate_request->setCustomerPaymentProfileId($customer_payment_profile_id);
                $validate_request->setValidationMode($validation_mode);
                $validate_controller = new AnetController\ValidateCustomerPaymentProfileController($validate_request);
                $validate_response = $validate_controller->executeWithApiResponse($this->helper->controller_response());
                if (ANET_SANDBOX_STATUS_AUTHORIZED === $validate_response->getMessages()->getResultCode() && $validate_response) {
                    return [
                        'result' => true,
                        'message' => __('Payment method successfully updated.', 'authorize-net-payments-for-woocommerce')
                    ];
                }
            }
            return [
                'result' => false,
                'message' => __('Payment method update failed. Please try again.', 'authorize-net-payments-for-woocommerce') .
                    (isset($validate_response) && $validate_response->getMessages()->getMessage()
                        ? ' ' . $validate_response->getMessages()->getMessage()[0]->getText()
                        : '')
            ];
        } catch (Throwable $e) {
            Anet_Setting_Helper::log("\nException:\n" . $e->getMessage(), ANET_PAYMENT_TYPE_ECHECK, 'error');
            return [
                'result' => false,
                'message' => __('Payment method update failed. Please try again.', 'authorize-net-payments-for-woocommerce') . $response->getMessages()->getMessage()[0]->getText()
            ];
        }
    }
    /**
     * Set default payment profile for customer.
     *
     * Sets a specific customer payment profile as the default payment method
     * and optionally updates the eCheck bank account information.
     *
     * @param int         $user_id                     The WordPress user ID.
     * @param string      $customer_profile_id         The customer profile ID from Authorize.net.
     * @param string      $customer_payment_profile_id The payment profile ID to set as default.
     * @param string|null $account_number              Optional new account number.
     * @param string|null $routing_number              Optional new routing number.
     * @param string|null $account_type                Optional new account type.
     * @param string|null $name_on_account             Optional new name on account.
     *
     * @return array Result of the operation with success status.
     *
     * @since 1.0.0
     */
    public function set_default_payment_profile($user_id, $customer_profile_id, $customer_payment_profile_id, $account_number = null, $routing_number = null, $account_type = null, $name_on_account = null)
    {
        try {
            $merchant_auth = $this->helper->merchant_authentication_request();
            $payment_profile = new AnetAPI\CustomerPaymentProfileExType();
            $payment_profile->setCustomerPaymentProfileId($customer_payment_profile_id);
            $payment_profile->setDefaultPaymentProfile(true);
            // For eCheck, optionally update the bank account info if provided.
            if ($account_number && $routing_number && $account_type && $name_on_account) {
                $bank_account = new AnetAPI\BankAccountType();
                $bank_account->setAccountNumber($account_number);
                $bank_account->setRoutingNumber($routing_number);
                $bank_account->setAccountType($account_type);
                $bank_account->setNameOnAccount($name_on_account);
                $payment = new AnetAPI\PaymentType();
                $payment->setBankAccount($bank_account);
                $payment_profile->setPayment($payment);
            }
            $validation_mode = $this->helper->validation_mode();
            $request = new AnetAPI\UpdateCustomerPaymentProfileRequest();
            $request->setMerchantAuthentication($merchant_auth);
            $request->setCustomerProfileId($customer_profile_id);
            $request->setPaymentProfile($payment_profile);
            $request->setValidationMode($validation_mode);
            $sanitized_request = Anet_Api_Helper::mask_sensitive_data($request);
            Anet_Setting_Helper::log("\nsetDefaultPaymentProfileRequest:\n" . $sanitized_request, ANET_PAYMENT_TYPE_ECHECK, 'debug');
            $controller = new AnetController\UpdateCustomerPaymentProfileController($request);
            $response = $controller->executeWithApiResponse($this->helper->controller_response());
            // Log the response.
            Anet_Setting_Helper::log(
                "\nsetDefaultPaymentProfileResponse:\n" .
                    wp_json_encode([
                        'validationDirectResponse' => $response->getValidationDirectResponse(),
                        'messages' => $response->getMessages(),
                    ], JSON_PRETTY_PRINT),
                ANET_PAYMENT_TYPE_ECHECK, 'debug'
            );
            if (ANET_SANDBOX_STATUS_AUTHORIZED === $response->getMessages()->getResultCode() && $response) {
                return [
                    'result' => true,
                ];
            }
            return [
                'result' => false,
            ];
        } catch (Throwable $e) {
            Anet_Setting_Helper::log("\nException:\n" . $e->getMessage(), ANET_PAYMENT_TYPE_ECHECK, 'error');
            return [
                'result' => false,
            ];
        }
    }
    /**
     * Delete entire customer profile from Authorize.net.
     *
     * Removes a customer profile and all associated payment profiles
     * from Authorize.net and cleans up local WordPress user meta.
     *
     * @param int    $user_id             The WordPress user ID.
     * @param string $customer_profile_id The customer profile ID to delete.
     *
     * @return bool True on successful deletion, false on failure.
     *
     * @since 1.0.0
     */
    public function delete_customer_profile($user_id, $customer_profile_id)
    {
        if (!$customer_profile_id) {
            return false;
        }
        try {
            $merchant_auth = $this->helper->merchant_authentication_request();
            $request = new AnetAPI\DeleteCustomerProfileRequest();
            $request->setMerchantAuthentication($merchant_auth);
            $request->setCustomerProfileId($customer_profile_id);
            $sanitized_request = Anet_Api_Helper::mask_tokenization_request($request); // Call the mask_tokenization_request function.
            Anet_Setting_Helper::log("\ndeleteCustomerProfileRequest:\n" . $sanitized_request, ANET_PAYMENT_TYPE_ECHECK, 'debug');
            $controller = new AnetController\DeleteCustomerProfileController($request);
            $response = $controller->executeWithApiResponse($this->helper->controller_response());
            Anet_Setting_Helper::log("\ndeleteCustomerProfileResponse:\n" . wp_json_encode($response, JSON_PRETTY_PRINT), ANET_PAYMENT_TYPE_ECHECK, 'debug');
            if (ANET_SANDBOX_STATUS_AUTHORIZED === $response->getMessages()->getResultCode() && null !== $response) {
                delete_user_meta($user_id, $this->meta_key);
                return true;
            }
            return false;
        } catch (Throwable $e) {
            Anet_Setting_Helper::log("\nException:\n" . $e->getMessage(), ANET_PAYMENT_TYPE_ECHECK, 'error');
            return false;
        }
    }
    /**
     * Delete specific customer payment profile.
     *
     * Removes a specific payment profile from a customer profile
     * in Authorize.net while keeping the customer profile intact.
     *
     * @param int    $user_id                     The WordPress user ID.
     * @param string $customer_profile_id         The customer profile ID.
     * @param string $customer_payment_profile_id The payment profile ID to delete.
     *
     * @return bool True on successful deletion, false on failure.
     *
     * @since 1.0.0
     */
    public function delete_customer_payment_profile($user_id, $customer_profile_id, $customer_payment_profile_id)
    {
        if (!$customer_profile_id || !$customer_payment_profile_id) {
            return false;
        }
        try {
            $merchant_auth = $this->helper->merchant_authentication_request();
            $request = new AnetAPI\DeleteCustomerPaymentProfileRequest();
            $request->setMerchantAuthentication($merchant_auth);
            $request->setCustomerProfileId($customer_profile_id);
            $request->setCustomerPaymentProfileId($customer_payment_profile_id);
            $sanitized_request = Anet_Api_Helper::mask_tokenization_request($request); // Call the mask_tokenization_request function.
            Anet_Setting_Helper::log("\ndeleteCustomerPaymentProfileRequest:\n" . $sanitized_request, ANET_PAYMENT_TYPE_ECHECK, 'debug');
            $controller = new AnetController\DeleteCustomerPaymentProfileController($request);
            $response = $controller->executeWithApiResponse($this->helper->controller_response());
            Anet_Setting_Helper::log("\ndeleteCustomerPaymentProfileResponse:\n" . wp_json_encode($response, JSON_PRETTY_PRINT), ANET_PAYMENT_TYPE_ECHECK, 'debug');
            if (ANET_SANDBOX_STATUS_AUTHORIZED === $response->getMessages()->getResultCode() && null !== $response) {
                // Optionally, delete the WooCommerce payment token for this card.
                $tokens = WC_Payment_Tokens::get_customer_tokens($user_id, ANET_ECHECK_GATEWAY_ID);
                foreach ($tokens as $token) {
                    $token_data = $token->get_meta('token_information');
                    if (!empty($token_data['payment_profile_id']) && $customer_payment_profile_id === $token_data['payment_profile_id']) {
                        return true;
                    }
                }
            }
            return false;
        } catch (Throwable $e) {
            Anet_Setting_Helper::log("\nException:\n" . $e->getMessage(), ANET_PAYMENT_TYPE_ECHECK, 'error');
            return false;
        }
    }
    /**
     * Delete payment profile with intelligent selection.
     *
     * Determines whether to delete the entire customer profile or just
     * a specific payment profile based on the number of existing tokens
     * and payment profiles associated with the customer.
     *
     * @param int         $user_id                     The WordPress user ID.
     * @param string      $customer_profile_id         The customer profile ID.
     * @param string|null $customer_payment_profile_id Optional payment profile ID.
     *
     * @return bool True on successful deletion, false on failure.
     *
     * @since 1.0.0
     */
    public function delete_profile($user_id, $customer_profile_id, $customer_payment_profile_id = null)
    {
        $customer_tokens = "_anet_customer_profile_id_echeck" === $this->meta_key ? WC_Payment_Tokens::get_tokens(['user_id' => $user_id, 'gateway_id' => "anet_echeck"]) : array_merge(WC_Payment_Tokens::get_tokens(['user_id' => $user_id, 'gateway_id' => "anet"]), WC_Payment_Tokens::get_tokens(['user_id' => $user_id, 'gateway_id' => "anet_echeck"]));
        if (1 >= count($customer_tokens) || null === $customer_payment_profile_id) {
            return $this->delete_customer_profile($user_id, $customer_profile_id);
        } else {
            // Delete only the specified payment profile.
            return $this->delete_customer_payment_profile($user_id, $customer_profile_id, $customer_payment_profile_id);
        }
    }
    /**
     * Store eCheck details as payment token.
     *
     * Creates or updates a WooCommerce payment token with eCheck details
     * from the Authorize.net payment profile data.
     *
     * @param int   $user_id           The WordPress user ID.
     * @param string $payment_profile_id The payment profile ID from Authorize.net.
     * @param mixed $echeck_data       The eCheck data from Authorize.net API.
     */
    public function store_echeck_details($user_id, $payment_profile_id, $echeck_data)
    {
        // Try to find an existing token for this user and payment profile.
        $existing_tokens = WC_Payment_Tokens::get_customer_tokens($user_id, ANET_ECHECK_GATEWAY_ID);
        $token_obj = null;
        foreach ($existing_tokens as $token) {
            $token_info = $token->get_meta('token_information');
            if (
                !empty($token_info['payment_profile_id']) &&
                $payment_profile_id === $token_info['payment_profile_id']
            ) {
                $token_obj = $token;
                break;
            }
        }
        // If not found, create a new token.
        if (!$token_obj) {
            $token_obj = new \WC_Payment_Token_ECheck();
            $token_obj->set_token($payment_profile_id);
            $token_obj->set_user_id($user_id);
            $token_obj->set_gateway_id(ANET_ECHECK_GATEWAY_ID);
            $token_obj->set_type('echeck'); // Custom type for eCheck.
        }
        $data          = $this->get_echeck_data_to_save($echeck_data, $user_id);
        $props         = $this->get_echeck_props();
        $return_result = $this->save_echeck_token_to_database($token_obj, $data, $props);
    }
    /**
     * Prepare eCheck data for saving to database.
     *
     * Processes and formats eCheck payment data from Authorize.net response
     * into a structure suitable for storage in WooCommerce payment tokens.
     *
     * @param mixed $echeck_data Raw eCheck data from Authorize.net API response.
     * @param int   $user_id     The WordPress user ID.
     *
     * @return array Formatted eCheck data array for database storage.
     */
    public function get_echeck_data_to_save($echeck_data, $user_id)
    {
        $setting = Anet_Setting_Helper::get_echeck_settings();
        $echeck_data = json_decode(wp_json_encode($echeck_data), true);
        $data = array();
        $token_identifier['customer_profile_id'] = $echeck_data['customerProfileId'];
        $token_identifier['payment_profile_id'] = $echeck_data['customerPaymentProfileId'];
        $token_identifier['account_type'] = $echeck_data['payment']['bankAccount']['accountType'];
        $token_identifier['routing_number'] = $echeck_data['payment']['bankAccount']['routingNumber'];
        $token_identifier['name_on_account'] = $echeck_data['payment']['bankAccount']['nameOnAccount'];
        $token_identifier['state'] = 'ACTIVE';
        $token_identifier['new'] = true;
        $data['last_four']         = $echeck_data['payment']['bankAccount']['accountNumber'];
        $data['token_information'] = $token_identifier;
        $data['gateway_id']        = ANET_ECHECK_GATEWAY_ID;
        $data['user_id']           = $user_id;
        $data['environment']       = $setting['testmode'] ? ANET_ENVIRONMENT_TEST : ANET_ENVIRONMENT_PRODUCTION;
        return $data;
    }
    /**
     * Get eCheck properties mapping array.
     *
     * Returns a mapping array that defines how eCheck data fields
     * should be mapped to WooCommerce payment token properties.
     *
     * @return array Array mapping data keys to property names.
     */
    public function get_echeck_props()
    {
        return array(
            'gateway_id'      => 'gateway_id',
            'user_id'         => 'user_id',
            'is_default'      => 'default',
            'last4'           => 'last_four',
            'account_type'    => 'account_type',
            'routing_number'  => 'routing_number',
            'bank_name'       => 'bank_name',
            'name_on_account' => 'name_on_account',
        );
    }
    /**
     * Save eCheck token to database.
     *
     * Saves the formatted eCheck data to the WooCommerce payment token
     * by mapping data fields to token properties and storing metadata.
     *
     * @param WC_Payment_Token_ECheck $token_obj The payment token object to save.
     * @param array                   $data      The formatted eCheck data array.
     * @param array                   $props     The property mapping array.
     *
     * @return array Result array with status, message, and token information.
     */
    public function save_echeck_token_to_database($token_obj, $data, $props)
    {
        foreach ($data as $key => $value) {
            // prefix the expiration year if needed (WC_Payment_Token requires it to be 4 digits long);.
            $core_key = array_search($key, $props, true);
            /** \WC_Payment_Token does not define a set_is_default method */
            if ('is_default' === $core_key) {
                $token_obj->set_default($value);
            } elseif ($core_key) {
                $token_obj->set_props(array($core_key => $value));
            } else {
                $token_obj->update_meta_data($key, $value, true);
            }
        }
        try {
            $saved_token = $token_obj->save();
            if ($saved_token) {
                $return_result['message'] = __('Card Saved Succesfully.', 'authorize-net-payments-for-woocommerce');
                $return_result['status']  = true;
                $return_result['token']  = $token_obj->get_token();
                // Redirect to payment methods page after saving.
            }
        } catch (Throwable $e) {
            Anet_Setting_Helper::log("\nException:\n" . $e->getMessage(), ANET_PAYMENT_TYPE_ECHECK, 'error');
            $return_result['message'] = __('Unable to store card information. Please try again later.', 'authorize-net-payments-for-woocommerce');
            $return_result['status']  = false;
        }
        return $return_result;
    }
    /**
     * Add the payment method title to the account page.
     *
     * @param array $columns Existing columns array.
     * @return array Modified columns array with title column added.
     *
     * @since 1.0.0
     */
    public function account_payment_methods_echeck_columns($columns = array())
    {
        $title_column = array('title' => __('Title', 'authorize-net-payments-for-woocommerce'));
        $columns      = $this->array_insert_after($columns, 'method', $title_column);
        $details_column = array('details' => __('Details', 'authorize-net-payments-for-woocommerce'));
        $columns        = $this->array_insert_after($columns, 'title', $details_column);
        return $columns;
    }
    /**
     * Insert array elements after a specific key.
     *
     * Inserts all elements from the given element array after
     * the specified key in the main array.
     *
     * @param array  $main_array The main array to insert into.
     * @param string $insert_key The key after which to insert elements.
     * @param array  $element    The array of elements to insert.
     *
     * @return array The modified array with inserted elements.
     */
    public static function array_insert_after(array $main_array, $insert_key, array $element)
    {
        $new_array = array();
        foreach ($main_array as $key => $value) {
            $new_array[$key] = $value;
            if ($key === $insert_key) {
                foreach ($element as $k => $v) {
                    $new_array[$k] = $v;
                }
            }
        }
        return $new_array;
    }
    /**
     * Add the payment method title value to the account page.
     *
     * @param array $method The payment method data.
     * @return void
     *
     * @since 1.0.0
     */
    public function add_payment_method_echeck_title($method)
    {
        $gateway_title = null;
        $settings = get_option('woocommerce_anet_echeck_settings', []);
        if (ANET_ECHECK_GATEWAY_ID === $method['method']['gateway']) {
            $gateway_title = isset($settings['title']) ? $settings['title'] : null;
        }
        if ($gateway_title) {
            echo '<div class="method title"> ' . esc_html($gateway_title) . ' </div>';
        }
    }
    /**
     * This method provides the Card used for Payment.
     *
     * @param mixed $method Payment Method.
     */
    public function add_payment_method_echeck_details($method)
    {
        $last_four = null;
        if (ANET_ECHECK_GATEWAY_ID === $method['method']['gateway']) {
            $last_four = $method['method']['last4'];
        }
        if ($last_four) {
            echo '<span class="anet-echeck-account-number-display">' . esc_html($last_four) . '</span>';
        }
    }
    /**
     * Display eCheck routing number for payment method.
     *
     * Outputs the routing number for an eCheck payment method
     * on the customer account payment methods page.
     *
     * @param mixed $method Payment method array containing eCheck details.
     */
    public function add_payment_method_echeck_routing_number($method)
    {
        $routing_number = null;
        if (ANET_ECHECK_GATEWAY_ID === $method['method']['gateway']) {
            $routing_number = $method['method']['routing_number'];
        }
        if ($routing_number) {
            echo '<span class="anet-echeck-routing-number-display">' . esc_html($routing_number) . '</span>';
        }
    }
    /**
     * Display eCheck account type for payment method.
     *
     * Outputs the account type (checking/savings) for an eCheck payment method
     * on the customer account payment methods page.
     *
     * @param mixed $method Payment method array containing eCheck details.
     */
    public function add_payment_method_echeck_account_type($method)
    {
        $account_type = null;
        if (ANET_ECHECK_GATEWAY_ID === $method['method']['gateway']) {
            $account_type = $method['method']['account_type'];
        }
        if ($account_type) {
            echo '<span class="anet-echeck-account-type-display">' . esc_html($account_type) . '</span>';
        }
    }
    /**
     * Add view/edit functionality for eCheck payment methods.
     *
     * Modifies the payment method item to include eCheck-specific
     * details and view/edit functionality for customer account page.
     *
     * @param array            $item          The payment method item array.
     * @param WC_Payment_Token $payment_token The payment token object.
     *
     * @return array Modified payment method item.
     */
    public function add_payment_methods_list_item_echeck_edit($item, $payment_token)
    {
        $gateway_id = $payment_token->get_gateway_id();
        if (ANET_ECHECK_GATEWAY_ID === $gateway_id) {
            if ($payment_token->get_is_default()) {
                WC()->session->set('anet_default_card_id', wc_clean($payment_token->get_id()));
            }
            $token_info = $payment_token->get_meta('token_information');
            $item['method']['token_id'] = $payment_token->get_id();
            if (!empty($token_info['payment_profile_id'])) {
                $item['method']['payment_profile_id'] = $token_info['payment_profile_id'];
            }
            if (!empty($token_info['customer_profile_id'])) {
                $item['method']['customer_profile_id'] = $token_info['customer_profile_id'];
            }
            if (!empty($token_info['routing_number'])) {
                $item['method']['routing_number'] = $token_info['routing_number'];
            }
            if (!empty($token_info['account_type'])) {
                $item['method']['account_type'] = $token_info['account_type'];
            }
            $item['row_class'] = (isset($item['row_class']) ? $item['row_class'] . ' ' : '') . 'anet-method-row';
            $token_id = $payment_token->get_id();
            // Add Edit action.
            $item['actions']['edit'] = array(
                'url'  => wc_get_account_endpoint_url('edit-echeck') . $token_id . ANET_SLASH,
                'name' => __('Edit', 'authorize-net-payments-for-woocommerce'),
            );
        }
        return $item;
    }
    /**
     * Enqueue scripts and styles for eCheck payment method management.
     *
     * Loads JavaScript and CSS files needed for eCheck payment method
     * editing functionality on customer account pages.
     *
     * @since 1.0.0
     */
    public function enqueue_myaccount_echeck()
    {
        if (is_account_page() && !is_add_payment_method_page()) {
            wp_enqueue_script(
                'anet-echeck-inline-edit',
                plugins_url('../../../assets/js/frontend/anet-echeck-update-payment-method.js', __FILE__),
                ['jquery'],
                ANET_PLUGIN_VERSION,
                true
            );
            wp_localize_script('anet-echeck-inline-edit', 'anetEdit', [
                'ajax_url' => admin_url('admin-ajax.php'),
                'nonce'    => wp_create_nonce('anet_echeck_edit_nonce'),
                'account_types' => [
                    ANET_ECHECK_ACCOUNT_TYPE_CHECKING,
                    ANET_ECHECK_ACCOUNT_TYPE_SAVINGS,
                ],
            ]);
        }
    }
    /**
     * Add custom query variables for eCheck payment method editing.
     *
     * Registers the 'edit-echeck' query variable to handle eCheck
     * payment method editing URLs in customer account pages.
     *
     * @param array $vars Existing query variables array.
     * @return array Modified query variables array with eCheck edit variable.
     *
     * @since 1.0.0
     */
    public function add_custom_query_vars_echeck($vars)
    {
        $vars[] = 'edit-echeck';
        return $vars;
    }
    /**
     * Render eCheck payment method editing form.
     *
     * Displays the eCheck payment method editing interface on customer
     * account pages, handles form submission, and processes updates
     * to existing eCheck payment methods.
     *
     * @since 1.0.0
     */
    public function render_edit_echeck()
    {
        try {
            $redirect_url = isset($_SERVER['REQUEST_URI']) ? esc_url_raw(wp_unslash($_SERVER['REQUEST_URI'])) : '';
            $notice_type = 'error';
            $user_id = get_current_user_id();
            $token_id = get_query_var('edit-echeck');
            $result = array('result' => false);
            if (!$token_id) {
                echo '<p>' . esc_html__('Invalid eCheck.', 'authorize-net-payments-for-woocommerce') . '</p>';
                return;
            }
            $payment_token = WC_Payment_Tokens::get($token_id);
            if (!$payment_token || $user_id !== $payment_token->get_user_id()) {
                echo '<p>' . esc_html__('Invalid eCheck.', 'authorize-net-payments-for-woocommerce') . '</p>';
                return;
            }
            $token_info = $payment_token->get_meta('token_information');
            $payment_profile_id = !empty($token_info['payment_profile_id']) ? $token_info['payment_profile_id'] : '';
            $customer_profile_id = !empty($token_info['customer_profile_id']) ? $token_info['customer_profile_id'] : '';
            // Fetch card details.
            $tokenization = new Anet_ECheck_Tokenization();
            $profile = $tokenization->get_customer_payment_profile($user_id, $payment_profile_id);
            if (empty($profile['account_number'])) {
                echo '<p>' . esc_html__('Unable to fetch eCheck details.', 'authorize-net-payments-for-woocommerce') . '</p>';
                return;
            }
            // Handle form submission.
            if (isset($_SERVER['REQUEST_METHOD']) && 'POST' === $_SERVER['REQUEST_METHOD'] && isset($_POST['anet_echeck_edit_nonce']) && wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['anet_echeck_edit_nonce'])), 'anet_echeck_edit_nonce')) {
                $new_account_number = isset($_POST['account_number']) ? sanitize_text_field(wp_unslash($_POST['account_number'])) : '';
                $new_routing_number = isset($_POST['routing_number']) ? sanitize_text_field(wp_unslash($_POST['routing_number'])) : '';
                $new_account_type   = isset($_POST['account_type']) ? sanitize_text_field(wp_unslash($_POST['account_type'])) : '';
                $new_name_on_account  = isset($_POST['name_on_account']) ? sanitize_text_field(wp_unslash($_POST['name_on_account'])) : '';
                $result = $tokenization->update_customer_payment_profile(
                    $user_id,
                    $customer_profile_id,
                    $payment_profile_id,
                    $new_account_number,
                    $new_routing_number,
                    $new_account_type,
                    $new_name_on_account
                );
                if ($result['result']) {
                    $profile = $tokenization->get_customer_payment_profile($user_id, $payment_profile_id, true);
                    if ($profile['result']) {
                        $notice_type = 'success';
                        $redirect_url = wc_get_endpoint_url(ANET_PAYMENT_METHODS);
                    }
                }
                wc_add_notice($result['message'], $notice_type);
            }
            // Load the template.
            $template_path = plugin_dir_path(__FILE__) . '../../../templates/myaccount/anet-echeck-edit.php';
            if (file_exists($template_path)) {
                include $template_path;
            } else {
                echo '<p>' . esc_html__('Edit template not found.', 'authorize-net-payments-for-woocommerce') . '</p>';
            }
        } catch (Throwable $e) {
            Anet_Setting_Helper::log("\nException:\n" . $e->getMessage(), ANET_PAYMENT_TYPE_ECHECK, 'error');
            wc_add_notice($result['message'], 'error');
            $redirect_url = isset($_SERVER['REQUEST_URI']) ? esc_url_raw(wp_unslash($_SERVER['REQUEST_URI'])) : '';
            wp_safe_redirect($redirect_url);
            exit();
        }
    }
}
// Register the custom endpoint for /my-account/edit-echeck/.
add_action('init', function () {
    add_rewrite_endpoint('edit-echeck', EP_ROOT | EP_PAGES);
});
