<?php
/**
 * Plugin Name: Teleport Pay Gateway
 * Plugin URI:  https://teleportpay.com
 * Description: WooCommerce payment gateway via Teleport Pay crypto acquiring
 * Version:     1.0.0
 * Author:      Teleport Pay
 * Text Domain: teleport-pay-gateway
 * Requires Plugins: woocommerce
 */

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

// ─── Register the gateway with WooCommerce ──────────────────────────────────
add_filter( 'woocommerce_payment_gateways', function( $gateways ) {
    $gateways[] = 'Teleport_Pay_Gateway';
    return $gateways;
} );

// ─── Load gateway class after WooCommerce is initialized ────────────────────
add_action( 'plugins_loaded', function() {
    if ( ! class_exists( 'WC_Payment_Gateway' ) ) {
        return;
    }

    class Teleport_Pay_Gateway extends WC_Payment_Gateway {

        /** Teleport Pay API base URL */
        const API_BASE    = 'https://gate.teleport.ltd/api/crypto-acquiring/v1';

        /** WooCommerce gateway identifier */
        const GATEWAY_ID  = 'teleport_pay';

        public function __construct() {
            $this->id                 = self::GATEWAY_ID;
            $this->icon               = '';
            $this->has_fields         = false;
            $this->method_title       = 'Teleport Pay';
            $this->method_description = 'Crypto acquiring via Teleport Pay. Redirects customer to hosted payment page.';

            // Supported WooCommerce Subscriptions features
            $this->supports = array(
                'products',
                'subscriptions',
                'subscription_cancellation',
                'subscription_suspension',
                'subscription_reactivation',
                'subscription_amount_changes',
                'subscription_date_changes',
                'subscription_payment_method_change',
                'subscription_payment_method_change_customer',
                'subscription_payment_method_change_admin',
                'multiple_subscriptions',
                'refunds',
            );

            $this->init_form_fields();
            $this->init_settings();

            $this->title          = $this->get_option( 'title' );
            $this->description    = $this->get_option( 'description' );
            $this->api_key        = $this->get_option( 'api_key' );
            $this->webhook_secret = $this->get_option( 'webhook_secret' );
            $this->debug          = $this->get_option( 'debug' ) === 'yes';

            // Save settings when the admin form is submitted
            add_action(
                'woocommerce_update_options_payment_gateways_' . $this->id,
                array( $this, 'process_admin_options' )
            );

            // Register webhook endpoint: https://yoursite.com/?wc-api=teleport_pay
            add_action( 'woocommerce_api_' . $this->id, array( $this, 'handle_webhook' ) );
        }

        // ─── Settings fields (WooCommerce → Settings → Payments → Manage) ────
        public function init_form_fields() {
            $this->form_fields = array(

                'enabled' => array(
                    'title'   => 'Enable/Disable',
                    'type'    => 'checkbox',
                    'label'   => 'Enable Teleport Pay Gateway',
                    'default' => 'no',
                ),

                'title' => array(
                    'title'       => 'Title',
                    'type'        => 'text',
                    'default'     => 'Pay with Crypto (Teleport Pay)',
                    'desc_tip'    => true,
                    'description' => 'Payment method name shown to the customer at checkout.',
                ),

                'description' => array(
                    'title'   => 'Description',
                    'type'    => 'textarea',
                    'default' => 'You will be redirected to a secure crypto payment page.',
                ),

                'api_key' => array(
                    'title'       => 'API Key',
                    'type'        => 'password',
                    'description' => 'Your Teleport Pay API key (starts with tk_...)',
                    'default'     => '',
                    'desc_tip'    => true,
                ),

                'webhook_secret' => array(
                    'title'       => 'Webhook Secret',
                    'type'        => 'password',
                    'description' => 'Your Teleport Pay webhook secret (starts with whsec_...). Found in your Teleport Pay dashboard.',
                    'default'     => '',
                    'desc_tip'    => true,
                ),

                'webhook_url_display' => array(
                    'title'             => 'Webhook URL',
                    'type'              => 'text',
                    'description'       => 'Copy this URL and set it in your Teleport Pay dashboard as the webhook endpoint.',
                    'default'           => WC()->api_request_url( self::GATEWAY_ID ),
                    'custom_attributes' => array( 'readonly' => 'readonly' ),
                ),

                'debug' => array(
                    'title'   => 'Debug Log',
                    'type'    => 'checkbox',
                    'label'   => 'Enable logging (viewable at WooCommerce → Status → Logs)',
                    'default' => 'no',
                ),
            );
        }

        // ─── Process payment: create invoice and redirect to hosted page ─────
        public function process_payment( $order_id ) {
            $order = wc_get_order( $order_id );

            // Build the request payload for the Teleport Pay API
            $payload = array(
                'order_id'       => (string) $order_id,
                'amount'         => round( (float) $order->get_total(), 2 ),
                'currency'       => get_woocommerce_currency(),
                'description'    => 'Order #' . $order_id . ' — ' . get_bloginfo( 'name' ),
                'customer_email' => $order->get_billing_email(),
                'customer_name'  => trim( $order->get_billing_first_name() . ' ' . $order->get_billing_last_name() ),
                'return_url'     => $this->get_return_url( $order ),
                'cancel_url'     => wc_get_cart_url(),
                'webhook_url'    => WC()->api_request_url( $this->id ),
            );

            $this->log( 'Creating invoice: ' . wp_json_encode( $payload ) );

            // Send POST request to Teleport Pay API
            $response = wp_remote_post(
                self::API_BASE . '/invoice/create/',
                array(
                    'method'  => 'POST',
                    'timeout' => 30,
                    'headers' => array(
                        'X-API-Key'    => $this->api_key,
                        'Content-Type' => 'application/json',
                    ),
                    'body' => wp_json_encode( $payload ),
                )
            );

            // Handle connection errors
            if ( is_wp_error( $response ) ) {
                $this->log( 'Connection error: ' . $response->get_error_message(), 'error' );
                wc_add_notice( 'Payment gateway connection error. Please try again.', 'error' );
                return array( 'result' => 'failure' );
            }

            $http_code = wp_remote_retrieve_response_code( $response );
            $body      = json_decode( wp_remote_retrieve_body( $response ), true );

            $this->log( 'API response (' . $http_code . '): ' . wp_json_encode( $body ) );

            // API returns 201 on success; also accept 200 for forward compatibility
            if ( in_array( $http_code, array( 200, 201 ), true ) && ! empty( $body['success'] ) && ! empty( $body['payment_url'] ) ) {

                // Store Teleport Pay metadata on the order
                $order->update_meta_data( '_teleport_payment_id', sanitize_text_field( $body['payment_id'] ?? '' ) );
                $order->update_meta_data( '_teleport_bill_uid',   sanitize_text_field( $body['bill_uid'] ?? '' ) );
                $order->update_meta_data( '_teleport_expires_at', sanitize_text_field( $body['expires_at'] ?? '' ) );
                $order->update_status( 'pending', 'Awaiting Teleport Pay crypto payment.' );
                $order->save();

                // Clear the cart since the order is now in progress
                WC()->cart->empty_cart();

                // Redirect the customer to the Teleport Pay hosted payment page
                return array(
                    'result'   => 'success',
                    'redirect' => esc_url( $body['payment_url'] ),
                );

            } else {
                $error = $body['error'] ?? $body['detail'] ?? $body['message'] ?? 'Unknown error from Teleport Pay';
                $this->log( 'Invoice creation failed: ' . $error, 'error' );
                wc_add_notice( 'Payment error: ' . esc_html( $error ), 'error' );
                return array( 'result' => 'failure' );
            }
        }

        // ─── Handle incoming webhook from Teleport Pay ───────────────────────
        // Endpoint URL: https://yoursite.com/?wc-api=teleport_pay
        public function handle_webhook() {
            $raw_body  = file_get_contents( 'php://input' );
            $signature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';

            $this->log( 'Webhook received. Body: ' . $raw_body );

            // Step 1: Verify HMAC-SHA256 signature
            if ( ! $this->verify_signature( $raw_body, $signature ) ) {
                $this->log( 'Invalid webhook signature', 'error' );
                wp_die( 'Invalid signature', 'Forbidden', array( 'response' => 403 ) );
            }

            $data = json_decode( $raw_body, true );

            if ( empty( $data['order_id'] ) || empty( $data['status'] ) ) {
                wp_die( 'Invalid payload', 'Bad Request', array( 'response' => 400 ) );
            }

            // Step 2: Only process invoice.status_changed events
            if ( ( $data['event'] ?? '' ) !== 'invoice.status_changed' ) {
                http_response_code( 200 );
                echo wp_json_encode( array( 'received' => true, 'action' => 'ignored' ) );
                exit;
            }

            $order_id = absint( $data['order_id'] );
            $order    = wc_get_order( $order_id );

            if ( ! $order ) {
                $this->log( 'Order not found: ' . $order_id, 'error' );
                wp_die( 'Order not found', 'Not Found', array( 'response' => 404 ) );
            }

            // Security check: ensure the order belongs to this gateway
            if ( $order->get_payment_method() !== $this->id ) {
                $this->log( 'Wrong payment method for order: ' . $order_id, 'error' );
                wp_die( 'Wrong gateway', 'Forbidden', array( 'response' => 403 ) );
            }

            $status     = $data['status'];
            $payment_id = sanitize_text_field( $data['payment_id'] ?? '' );
            $bill_uid   = sanitize_text_field( $data['bill_uid'] ?? '' );

            $this->log( 'Processing status "' . $status . '" for order #' . $order_id );

            // Step 3: Map Teleport Pay statuses to WooCommerce order statuses
            switch ( $status ) {

                case 'paid':
                    // Idempotency: skip if order is already completed
                    if ( $order->has_status( array( 'completed', 'processing' ) ) ) {
                        $this->log( 'Order #' . $order_id . ' already completed, skipping.' );
                        break;
                    }
                    if ( $payment_id ) {
                        $order->set_transaction_id( $payment_id );
                    }
                    $order->payment_complete();
                    $order->add_order_note(
                        'Payment confirmed by Teleport Pay.' .
                        ( $bill_uid ? ' Bill UID: ' . $bill_uid : '' )
                    );

                    // Activate subscriptions if WooCommerce Subscriptions is active
                    $this->maybe_activate_subscriptions( $order );

                    $this->log( 'Order #' . $order_id . ' marked as paid.' );
                    break;

                case 'expired':
                    if ( ! $order->has_status( array( 'completed', 'processing', 'cancelled' ) ) ) {
                        $order->update_status( 'cancelled', 'Teleport Pay invoice expired.' );
                        $this->log( 'Order #' . $order_id . ' cancelled (expired).' );
                    }
                    break;

                case 'cancelled':
                    if ( ! $order->has_status( array( 'completed', 'processing', 'cancelled' ) ) ) {
                        $order->update_status( 'cancelled', 'Payment cancelled by customer via Teleport Pay.' );
                        $this->log( 'Order #' . $order_id . ' cancelled.' );
                    }
                    break;

                case 'failed':
                    if ( ! $order->has_status( array( 'completed', 'processing' ) ) ) {
                        $order->update_status( 'failed', 'Teleport Pay payment failed.' );
                        $this->log( 'Order #' . $order_id . ' failed.' );
                    }
                    break;

                case 'manual_confirmation':
                    // Underpayment detected — put order on hold until manual review
                    if ( ! $order->has_status( array( 'completed', 'processing' ) ) ) {
                        $order->update_status(
                            'on-hold',
                            'Teleport Pay: underpayment detected, manual confirmation required.'
                        );
                        $this->log( 'Order #' . $order_id . ' on-hold (manual_confirmation).' );
                    }
                    break;

                default:
                    $this->log( 'Unknown status "' . $status . '" for order #' . $order_id, 'warning' );
                    break;
            }

            // Step 4: Return 200 so Teleport Pay does not retry delivery
            http_response_code( 200 );
            echo wp_json_encode( array( 'received' => true ) );
            exit;
        }

        // ─── Subscriptions: activate after first payment ─────────────────────
        private function maybe_activate_subscriptions( $order ) {
            if ( ! function_exists( 'wcs_get_subscriptions_for_order' ) ) {
                return;
            }
            $subscriptions = wcs_get_subscriptions_for_order(
                $order,
                array( 'order_type' => 'parent' )
            );
            foreach ( $subscriptions as $subscription ) {
                if ( $subscription->has_status( array( 'pending', 'on-hold' ) ) ) {
                    $subscription->update_status( 'active' );
                    $this->log( 'Subscription #' . $subscription->get_id() . ' activated.' );
                }
            }
        }

        // ─── Subscriptions: handle renewal payments ──────────────────────────
        // Teleport Pay is crypto-based — no automatic recurring charges.
        // WooCommerce Subscriptions puts the order on-hold and the customer
        // receives an email with a link to pay manually.
        public function scheduled_subscription_payment( $amount_to_charge, $renewal_order ) {
            $renewal_order->update_status(
                'on-hold',
                'Awaiting Teleport Pay crypto payment for renewal. Customer notified by email.'
            );

            // Send the customer an invoice email with a payment link
            $mailer = WC()->mailer();
            $mailer->emails['WC_Email_Customer_Invoice']->trigger( $renewal_order->get_id() );

            $this->log( 'Renewal order #' . $renewal_order->get_id() . ' set to on-hold, email sent.' );
        }

        // ─── Verify HMAC-SHA256 webhook signature ────────────────────────────
        private function verify_signature( string $body, string $signature ): bool {
            if ( empty( $this->webhook_secret ) || empty( $signature ) ) {
                $this->log( 'Webhook secret or signature missing — skipping verification', 'warning' );
                // WARNING: In production, return false here to enforce signature checks.
                return true;
            }
            // Strip "sha256=" prefix if present (sent by the Teleport webhook system)
            $sig_clean = str_starts_with( $signature, 'sha256=' )
                ? substr( $signature, 7 )
                : $signature;
            $expected = hash_hmac( 'sha256', $body, $this->webhook_secret );
            return hash_equals( $expected, $sig_clean );
        }

        // ─── Internal logging helper ─────────────────────────────────────────
        private function log( string $message, string $level = 'info' ): void {
            if ( $this->debug ) {
                wc_get_logger()->log(
                    $level,
                    $message,
                    array( 'source' => $this->id )
                );
            }
        }
    }
} );
