<?php

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

require_once CREGIS_PAYMENT_PLUGIN_DIR . 'includes/class-cregis-logger.php';

class Cregis_Payment {
    private $api;
    private $settings;
    private $logger;
    
    public function __construct() {
        $this->settings = get_option('cregis_payment_settings', array());
        $this->logger = new Cregis_Logger(isset($this->settings['debug']) ? $this->settings['debug'] : false);
        
        if (!empty($this->settings['project_id']) && !empty($this->settings['secret_key'])) {
            $this->api = new Cregis_API(
                $this->settings['project_id'],
                $this->settings['secret_key'],
                isset($this->settings['api_mode']) ? $this->settings['api_mode'] : 'test',
                isset($this->settings['api_url']) ? $this->settings['api_url'] : null,
                isset($this->settings['debug']) ? $this->settings['debug'] : true // Always enable debug for API requests
            );
        }
        
        add_action('init', array($this, 'init'));
    }
    
    public function init() {
        add_action('rest_api_init', array($this, 'register_webhook'));
        add_shortcode('cregis_payment_form', array($this, 'payment_form_shortcode'));
    }
    
    public function register_webhook() {
        register_rest_route('cregis/v1', '/webhook', array(
            'methods' => 'POST',
            'callback' => array($this, 'handle_webhook'),
            'permission_callback' => '__return_true'
        ));
    }
    
    public function handle_webhook($request) {
        try {
            // Check if request object is valid
            if (!$request || !is_object($request)) {
                error_log('Cregis: Invalid request object in webhook');
                return new WP_Error('invalid_request', 'Invalid request object', array('status' => 400));
            }
            
            // Get raw request body for signature verification
            $body = $request->get_body();
            
            // Log raw request body
            error_log('Cregis: Webhook raw request body: ' . $body);
            if (isset($this->logger)) {
                $this->logger->info('Webhook raw request body', array('body' => $body));
            }
            
            // Parse JSON data for processing
            $data = json_decode($body, true);
            
            // Check if data is valid
            if (!$data || !is_array($data)) {
                error_log('Cregis: No valid JSON data in webhook. Raw body: ' . $body);
                if (isset($this->logger)) {
                    $this->logger->error('No valid JSON data in webhook', array('body' => $body));
                }
                return new WP_Error('no_data', 'No valid JSON data received', array('status' => 400));
            }
            
            // Log webhook data
            if (isset($this->logger)) {
                $this->logger->info('Webhook received', $data);
            }
            
            $signature = isset($data['sign']) ? $data['sign'] : '';
            
            if (!$this->api) {
                error_log('Cregis: API not initialized for webhook verification');
                return new WP_Error('api_not_initialized', 'API not initialized', array('status' => 500));
            }
            
            // Verify webhook signature using raw data (including data as JSON string)
            if (!$this->api->verify_webhook_signature($data, $signature)) {
                if (isset($this->logger)) {
                    $this->logger->error('Invalid webhook signature');
                }
                return new WP_Error('invalid_signature', 'Invalid signature', array('status' => 401));
            }
            
            $event_name = isset($data['event_name']) ? $data['event_name'] : '';
            $event_type = isset($data['event_type']) ? $data['event_type'] : '';
            $order_data_raw = isset($data['data']) ? $data['data'] : '';
            
            // Check if order_data is a JSON string and parse it
            $order_data = array();
            if (is_string($order_data_raw)) {
                $order_data = json_decode($order_data_raw, true);
            } elseif (is_array($order_data_raw)) {
                $order_data = $order_data_raw;
            }
            
            if (isset($this->logger)) {
                $this->logger->info(sprintf('Webhook event: %s (%s)', $event_name, $event_type));
            }
            
            if (empty($order_data)) {
                if (isset($this->logger)) {
                    $this->logger->error('Webhook data is empty');
                }
                return new WP_Error('invalid_data', 'Order data is missing', array('status' => 400));
            }
            
            $order_id = isset($order_data['order_id']) ? $order_data['order_id'] : '';
            $cregis_order_id = isset($order_data['cregis_id']) ? $order_data['cregis_id'] : '';
            $status = isset($order_data['status']) ? $order_data['status'] : '';
            
            if (isset($this->logger)) {
                $this->logger->info(sprintf('Processing order: %s (Cregis ID: %s, Status: %s)', $order_id, $cregis_order_id, $status));
            }
            
            try {
                $this->update_order_status($order_id, $cregis_order_id, $status, $order_data);
            } catch (Exception $e) {
                if (isset($this->logger)) {
                    $this->logger->error(sprintf('Error updating order status: %s', $e->getMessage()));
                }
                return new WP_Error('order_update_error', 'Error updating order status', array('status' => 500));
            }
            
            if (isset($this->logger)) {
                $this->logger->info('Webhook processed successfully');
            }
            
            // Return "success" string as required by Cregis documentation
            // Use die() to return raw string without JSON wrapping
            die('success');
        } catch (Exception $e) {
            error_log(sprintf('Cregis Webhook error: %s', $e->getMessage()));
            if (isset($this->logger)) {
                $this->logger->error(sprintf('Webhook error: %s', $e->getMessage()));
            }
            return new WP_Error('webhook_error', $e->getMessage(), array('status' => 500));
        }
    }
    
    private function update_order_status($order_id, $cregis_order_id, $status, $order_data = array()) {
        $woo_order = null;
        
        // Log the received status
        error_log(sprintf('Cregis: Updating order status - order_id=%s, cregis_order_id=%s, status=%s', $order_id, $cregis_order_id, $status));
        if (isset($this->logger)) {
            $this->logger->info(sprintf('Updating order status - order_id=%s, cregis_order_id=%s, status=%s', $order_id, $cregis_order_id, $status));
        }
        
        if ($cregis_order_id) {
            $woo_order = $this->find_order_by_cregis_id($cregis_order_id);
        }
        
        if (!$woo_order && $order_id) {
            $woo_order = $this->find_order_by_woo_order_id($order_id);
        }
        
        if (!$woo_order) {
            error_log(sprintf('Cregis: Order not found - order_id=%s, cregis_order_id=%s', $order_id, $cregis_order_id));
            if (isset($this->logger)) {
                $this->logger->error(sprintf('Order not found: order_id=%s, cregis_order_id=%s', $order_id, $cregis_order_id));
            }
            return;
        }
        
        error_log(sprintf('Cregis: Found WooCommerce order: %d', $woo_order->get_id()));
        if (isset($this->logger)) {
            $this->logger->info(sprintf('Found WooCommerce order: %d', $woo_order->get_id()));
        }
        
        // Map Cregis status to WooCommerce status
        // Cregis status values: new, paid, expired, paid_over, paid_partial, paid_remain, refunded, failed
        switch ($status) {
            case 'paid':
                if ($woo_order->get_status() === 'completed') {
                    if (isset($this->logger)) {
                        $this->logger->info('Order already completed, skipping');
                    }
                    break;
                }
                $woo_order->update_status('completed', __('Payment completed via Cregis', 'cregis-payment-for-woocommerce'));
                $this->add_order_notes($woo_order, $order_data);
                if (isset($this->logger)) {
                    $this->logger->log_order_status_update($order_id, 'completed');
                }
                break;

            case 'paid_partial':
                // Check if accept_all_underpaid is enabled
                $settings = get_option('cregis_payment_settings', array());
                $accept_all_underpaid = isset($settings['accept_all_underpaid']) && $settings['accept_all_underpaid'] === 'yes';
                
                if ($accept_all_underpaid) {
                    // If accept_all_underpaid is enabled, mark as completed
                    $woo_order->update_status('completed', __('Partial payment received via Cregis (accepted)', 'cregis-payment-for-woocommerce'));
                    if (isset($this->logger)) {
                        $this->logger->info('Accept all underpaid enabled, marking paid_partial as completed');
                    }
                } else {
                    // Otherwise, put on hold
                    $woo_order->update_status('on-hold', __('Partial payment received via Cregis', 'cregis-payment-for-woocommerce'));
                }
                $this->add_order_notes($woo_order, $order_data);
                if (isset($this->logger)) {
                    $this->logger->log_order_status_update($order_id, 'paid_partial');
                }
                break;

            case 'paid_over':
                // Check if accept_all_overpaid is enabled
                $settings = get_option('cregis_payment_settings', array());
                $accept_all_overpaid = isset($settings['accept_all_overpaid']) && $settings['accept_all_overpaid'] === 'yes';
                
                if ($accept_all_overpaid) {
                    // If accept_all_overpaid is enabled, mark as completed
                    $woo_order->update_status('completed', __('Overpayment received via Cregis (accepted)', 'cregis-payment-for-woocommerce'));
                    if (isset($this->logger)) {
                        $this->logger->info('Accept all overpaid enabled, marking paid_over as completed');
                    }
                } else {
                    // Otherwise, put on hold
                    $woo_order->update_status('on-hold', __('Overpayment received via Cregis', 'cregis-payment-for-woocommerce'));
                }
                $this->add_order_notes($woo_order, $order_data);
                if (isset($this->logger)) {
                    $this->logger->log_order_status_update($order_id, 'paid_over');
                }
                break;

            case 'cancelled':
            case 'expired':
                // Restore stock for cancelled/expired orders
                wc_increase_stock_levels($woo_order->get_id());
                $woo_order->update_status('cancelled', __('Payment cancelled or expired', 'cregis-payment-for-woocommerce'));
                if (isset($this->logger)) {
                    $this->logger->log_order_status_update($order_id, $status);
                }
                break;

            default:
                if (isset($this->logger)) {
                    $this->logger->info(sprintf('Received unknown order status: %s for order %s', $status, $order_id));
                }
                break;
        }

        // Save Cregis payment status as order meta
        $woo_order->update_meta_data('_cregis_payment_status', $status);

        // Save the order
        $woo_order->save();
        error_log(sprintf('Cregis: Order status updated to %s for order %d', $status, $woo_order->get_id()));
    }
    
    private function find_order_by_cregis_id($cregis_order_id) {
        $orders = wc_get_orders(array(
            'meta_key' => '_cregis_order_id',
            'meta_value' => $cregis_order_id,
            'limit' => 1
        ));
        
        return !empty($orders) ? $orders[0] : null;
    }
    
    private function find_order_by_woo_order_id($order_id) {
        $order_id = str_replace('wc_', '', $order_id);
        // Extract only the numeric part before the first underscore
        $order_id = explode('_', $order_id)[0];
        
        if (is_numeric($order_id)) {
            return wc_get_order(intval($order_id));
        }
        
        return null;
    }
    
    private function add_order_notes($order, $order_data) {
        if (empty($order_data)) {
            return;
        }
        
        // Check if this is a refund
        if (isset($order_data['refund_transact_time'])) {
            $this->add_refund_notes($order, $order_data);
            return;
        }
        
        // Check if this is an additional payment
        if (isset($order_data['additional_payment_transact_time'])) {
            $this->add_additional_payment_notes($order, $order_data);
            return;
        }
        
        // Default to first payment notes
        $this->add_first_payment_notes($order, $order_data);
    }
    
    private function add_first_payment_notes($order, $order_data) {
        $notes = array();
        $notes[] = __('First Payment', 'cregis-payment-for-woocommerce');
        $notes[] = '';
        
        // Payment Time
        if (isset($order_data['transact_time'])) {
            $payment_time = $this->timestamp_to_datetime($order_data['transact_time']);
            $notes[] = sprintf(__('Payment Time: %s', 'cregis-payment-for-woocommerce'), $payment_time);
        }
        
        // Order Amount
        if (isset($order_data['order_amount']) && isset($order_data['order_currency'])) {
            $order_amount = $order_data['order_amount'];
            $order_currency = $order_data['order_currency'];
            $receive_amount = isset($order_data['receive_amount']) ? $order_data['receive_amount'] : '';
            $receive_currency = isset($order_data['receive_currency']) ? $order_data['receive_currency'] : '';
            
            if ($receive_amount && $receive_currency) {
                $notes[] = sprintf(__('Order Amount: %s %s (%s %s)', 'cregis-payment-for-woocommerce'), 
                    $order_amount, $order_currency, $receive_amount, $receive_currency);
            } else {
                $notes[] = sprintf(__('Order Amount: %s %s', 'cregis-payment-for-woocommerce'), $order_amount, $order_currency);
            }
        }
        
        // Received Amount
        if (isset($order_data['pay_amount']) && isset($order_data['pay_currency'])) {
            $notes[] = sprintf(__('Received Amount: %s %s', 'cregis-payment-for-woocommerce'), 
                $order_data['pay_amount'], $order_data['pay_currency']);
        }
        
        // Received Address
        if (isset($order_data['payment_address'])) {
            $notes[] = sprintf(__('Received Address: %s', 'cregis-payment-for-woocommerce'), $order_data['payment_address']);
        }
        
        // Transaction Hash
        if (isset($order_data['tx_id'])) {
            $notes[] = sprintf(__('Transaction Hash: %s', 'cregis-payment-for-woocommerce'), $order_data['tx_id']);
        }
        
        // Accumulated Amount
        $accumulated_amount = $this->calculate_accumulated_amount($order_data);
        $order_currency = isset($order_data['order_currency']) ? $order_data['order_currency'] : '';
        if ($accumulated_amount !== null && $order_currency) {
            $notes[] = sprintf(__('Notes: Accumulated Amount: %s %s', 'cregis-payment-for-woocommerce'), 
                $accumulated_amount, $order_currency);
        }
        
        if (!empty($notes)) {
            $order->add_order_note(implode("\n", $notes));
        }
    }
    
    private function add_additional_payment_notes($order, $order_data) {
        $notes = array();
        $notes[] = __('Second Payment', 'cregis-payment-for-woocommerce');
        $notes[] = '';
        
        // Payment Time
        if (isset($order_data['additional_payment_transact_time'])) {
            $payment_time = $this->timestamp_to_datetime($order_data['additional_payment_transact_time']);
            $notes[] = sprintf(__('Payment Time: %s', 'cregis-payment-for-woocommerce'), $payment_time);
        }
        
        // Order Amount
        if (isset($order_data['order_amount']) && isset($order_data['order_currency'])) {
            $order_amount = $order_data['order_amount'];
            $order_currency = $order_data['order_currency'];
            $receive_amount = isset($order_data['receive_amount']) ? $order_data['receive_amount'] : '';
            $receive_currency = isset($order_data['receive_currency']) ? $order_data['receive_currency'] : '';
            
            if ($receive_amount && $receive_currency) {
                $notes[] = sprintf(__('Order Amount: %s %s (%s %s)', 'cregis-payment-for-woocommerce'), 
                    $order_amount, $order_currency, $receive_amount, $receive_currency);
            } else {
                $notes[] = sprintf(__('Order Amount: %s %s', 'cregis-payment-for-woocommerce'), $order_amount, $order_currency);
            }
        }
        
        // Received Amount
        if (isset($order_data['additional_pay_amount']) && isset($order_data['additional_pay_currency'])) {
            $notes[] = sprintf(__('Received Amount: %s %s', 'cregis-payment-for-woocommerce'), 
                $order_data['additional_pay_amount'], $order_data['additional_pay_currency']);
        }
        
        // Received Address
        if (isset($order_data['additional_payment_address'])) {
            $notes[] = sprintf(__('Received Address: %s', 'cregis-payment-for-woocommerce'), $order_data['additional_payment_address']);
        }
        
        // Transaction Hash
        if (isset($order_data['additional_payment_tx_id'])) {
            $notes[] = sprintf(__('Transaction Hash: %s', 'cregis-payment-for-woocommerce'), $order_data['additional_payment_tx_id']);
        }
        
        // Accumulated Amount
        $accumulated_amount = $this->calculate_accumulated_amount($order_data);
        $order_currency = isset($order_data['order_currency']) ? $order_data['order_currency'] : '';
        if ($accumulated_amount !== null && $order_currency) {
            $notes[] = sprintf(__('Notes: Accumulated Amount: %s %s', 'cregis-payment-for-woocommerce'), 
                $accumulated_amount, $order_currency);
        }
        
        if (!empty($notes)) {
            $order->add_order_note(implode("\n", $notes));
        }
    }
    
    private function add_refund_notes($order, $order_data) {
        $notes = array();
        $notes[] = __('Full/Partial Refund', 'cregis-payment-for-woocommerce');
        $notes[] = '';
        
        // Refund Time
        if (isset($order_data['refund_transact_time'])) {
            $refund_time = $this->timestamp_to_datetime($order_data['refund_transact_time']);
            $notes[] = sprintf(__('Refund Time: %s', 'cregis-payment-for-woocommerce'), $refund_time);
        }
        
        // Order Amount
        if (isset($order_data['order_amount']) && isset($order_data['order_currency'])) {
            $order_amount = $order_data['order_amount'];
            $order_currency = $order_data['order_currency'];
            $receive_amount = isset($order_data['receive_amount']) ? $order_data['receive_amount'] : '';
            $receive_currency = isset($order_data['receive_currency']) ? $order_data['receive_currency'] : '';
            
            if ($receive_amount && $receive_currency) {
                $notes[] = sprintf(__('Order Amount: %s %s (%s %s)', 'cregis-payment-for-woocommerce'), 
                    $order_amount, $order_currency, $receive_amount, $receive_currency);
            } else {
                $notes[] = sprintf(__('Order Amount: %s %s', 'cregis-payment-for-woocommerce'), $order_amount, $order_currency);
            }
        }
        
        // Refund Amount
        if (isset($order_data['actual_refund_amount']) && isset($order_data['refund_currency'])) {
            $notes[] = sprintf(__('Refund Amount: %s %s', 'cregis-payment-for-woocommerce'), 
                $order_data['actual_refund_amount'], $order_data['refund_currency']);
        }
        
        // Refund Handling Fee
        if (isset($order_data['refund_fee']) && isset($order_data['refund_currency'])) {
            $notes[] = sprintf(__('Refund Handling Fee: %s %s', 'cregis-payment-for-woocommerce'), 
                $order_data['refund_fee'], $order_data['refund_currency']);
        }
        
        // Refund Address
        if (isset($order_data['refund_address'])) {
            $notes[] = sprintf(__('Refund Address: %s', 'cregis-payment-for-woocommerce'), $order_data['refund_address']);
        }
        
        // Refund Transaction Hash
        if (isset($order_data['refund_tx_id'])) {
            $notes[] = sprintf(__('Refund Transaction Hash: %s', 'cregis-payment-for-woocommerce'), $order_data['refund_tx_id']);
        }
        
        // Accumulated Amount
        $accumulated_amount = $this->calculate_accumulated_amount($order_data);
        $order_currency = isset($order_data['order_currency']) ? $order_data['order_currency'] : '';
        if ($accumulated_amount !== null && $order_currency) {
            $notes[] = sprintf(__('Notes: Accumulated Amount: %s %s', 'cregis-payment-for-woocommerce'), 
                $accumulated_amount, $order_currency);
        }
        
        if (!empty($notes)) {
            $order->add_order_note(implode("\n", $notes));
        }
    }
    
    private function timestamp_to_datetime($timestamp) {
        // Convert timestamp to datetime (assuming timestamp is in milliseconds)
        if (strlen((string)$timestamp) > 10) {
            $timestamp = (int)$timestamp / 1000;
        }
        return date('Y-m-d H:i:s', (int)$timestamp);
    }
    
    private function calculate_accumulated_amount($order_data) {
        $order_amount = isset($order_data['order_amount']) ? (float)$order_data['order_amount'] : 0;
        $additional_pay_amount = isset($order_data['additional_pay_amount']) ? (float)$order_data['additional_pay_amount'] : 0;
        $refund_amount = isset($order_data['refund_amount']) ? (float)$order_data['refund_amount'] : 0;
        
        return $order_amount + $additional_pay_amount - $refund_amount;
    }
    
    public function payment_form_shortcode($atts) {
        return '<p>Payment form shortcode coming soon</p>';
    }
    
    public function create_order($order_data) {
        if (!$this->api) {
            throw new Exception('API not initialized');
        }
        return $this->api->create_checkout($order_data);
    }
    
    public function get_order($order_id) {
        if (!$this->api) {
            throw new Exception('API not initialized');
        }
        return $this->api->get_order_info($order_id);
    }
    
    public function get_order_currencies() {
        if (!$this->api) {
            throw new Exception('API not initialized');
        }
        return $this->api->get_order_currencies();
    }
    
    public function get_pay_currencies() {
        if (!$this->api) {
            throw new Exception('API not initialized');
        }
        return $this->api->get_pay_currencies();
    }
}
