<?php
/**
 * Stripe integration for Subscription System
 *
 * @package    Subscription_System
 * @subpackage Subscription_System/includes
 */

// If this file is called directly, abort.
if (!defined('WPINC')) {
    die;
}

/**
 * Stripe integration class
 */
class Subs_Sys_Stripe {

    /**
     * Stripe API key
     *
     * @var string
     */
    private $api_key;

    /**
     * Stripe publishable key
     *
     * @var string
     */
    private $publishable_key;

    /**
     * Initialize the class
     */
    public function __construct() {
        $this->api_key = get_option('subscription_stripe_secret_key');
        $this->publishable_key = get_option('subscription_stripe_publishable_key');
        
        // Debug: Log API key status
        // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Debug logging for API key status
        error_log('Stripe API Key exists: ' . (!empty($this->api_key) ? 'Yes' : 'No'));
        
        // Load Stripe PHP SDK if not already loaded
        if (!class_exists('\Stripe\Stripe')) {
            $autoload_path = plugin_dir_path(dirname(__FILE__)) . 'vendor/autoload.php';
            
            // Debug: Check if autoload file exists
            if (!file_exists($autoload_path)) {
                // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Debug logging for missing autoload
                error_log('Stripe autoload file not found at: ' . $autoload_path);
                throw new \Exception('Stripe library not found. Please make sure it is installed correctly.');
            }
            
            // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Debug logging for SDK loading
            error_log('Loading Stripe SDK from: ' . $autoload_path);
            require_once $autoload_path;
        }
        
        // Initialize Stripe with the secret key
        if (empty($this->api_key)) {
            // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Debug logging for empty API key
            error_log('Stripe API key is empty. Please configure it in the plugin settings.');
            throw new \Exception('Stripe API key is not configured. Please set it in the plugin settings.');
        }
        
        try {
            \Stripe\Stripe::setApiKey($this->api_key);
            // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Debug logging for successful API key setup
            error_log('Stripe API key set successfully');
        } catch (\Exception $e) {
            error_log('Error setting Stripe API key: ' . $e->getMessage());
            throw $e;
        }
    }

    /**
     * Get Stripe publishable key
     *
     * @return string
     */
    public function get_publishable_key() {
        return $this->publishable_key;
    }

    /**
     * Create a payment intent
     *
     * @param float $amount Amount to charge
     * @param string $currency Currency code
     * @param array $metadata Additional metadata
     * @param string $customer_id Customer ID (optional)
     * @return \Stripe\PaymentIntent
     */
    public function create_payment_intent($amount, $currency = 'usd', $metadata = [], $customer_id = null) {
        try {
            $data = [
                'amount' => intval($amount * 100), // Convert to cents
                'currency' => $currency,
                'metadata' => $metadata,
                'payment_method_types' => ['card'],
                'description' => 'Subscription payment',
            ];
            
            // Add customer if provided
            if (!empty($customer_id)) {
                $data['customer'] = $customer_id;
            }
            
            return \Stripe\PaymentIntent::create($data);
        } catch (\Stripe\Exception\ApiErrorException $e) {
            // Log the error
            error_log('Stripe API Error: ' . $e->getMessage());
            throw $e;
        }
    }

    /**
     * Create a subscription
     *
     * @param string $customer_id Stripe customer ID
     * @param string $price_id Stripe price ID
     * @param array $metadata Additional metadata
     * @return \Stripe\Subscription
     */
    public function create_subscription($customer_id, $price_id, $metadata = []) {
        try {
            return \Stripe\Subscription::create([
                'customer' => $customer_id,
                'items' => [
                    ['price' => $price_id],
                ],
                'metadata' => $metadata,
            ]);
        } catch (\Stripe\Exception\ApiErrorException $e) {
            // Log the error
            error_log('Stripe API Error: ' . $e->getMessage());
            throw $e;
        }
    }

    /**
     * Create or get a customer
     *
     * @param string $email Customer email
     * @param string $name Customer name
     * @param string $payment_method Payment method ID
     * @return \Stripe\Customer
     */
    public function create_customer($email, $name, $payment_method = null) {
        try {
            // Check if customer already exists
            $customers = \Stripe\Customer::all(['email' => $email, 'limit' => 1]);
            
            if (!empty($customers->data)) {
                $customer = $customers->data[0];
                
                // Update customer if needed
                if ($payment_method) {
                    try {
                        \Stripe\PaymentMethod::retrieve($payment_method)->attach([
                            'customer' => $customer->id,
                        ]);
                        
                        // Set as default payment method
                        $customer->invoice_settings = ['default_payment_method' => $payment_method];
                        $customer->save();
                    } catch (\Exception $e) {
                        // If it's already attached, that's fine
                        if (strpos($e->getMessage(), 'already been attached') === false) {
                            throw $e;
                        }
                    }
                }
                
                return $customer;
            }
            
            // Create new customer
            $customer_data = [
                'email' => $email,
                'name' => $name,
            ];
            
            if ($payment_method) {
                $customer_data['payment_method'] = $payment_method;
                $customer_data['invoice_settings'] = ['default_payment_method' => $payment_method];
            }
            
            return \Stripe\Customer::create($customer_data);
        } catch (\Exception $e) {
            error_log('Stripe API Error in create_customer: ' . $e->getMessage());
            throw $e;
        }
    }

    /**
     * Handle Stripe webhook events
     * This function should be called by your webhook endpoint
     */
    public function handle_webhook_event($event) {
        if (!$event) {
            return false;
        }

        switch ($event->type) {
            case 'checkout.session.completed':
                return $this->handle_checkout_completed($event->data->object);
            
            case 'invoice.payment_succeeded':
                return $this->handle_payment_succeeded($event->data->object);
            
            // Handle other events as needed
        }
        
        return true;
    }

    /**
     * Handle checkout.session.completed event
     */
    private function handle_checkout_completed($session) {
        error_log('Session data: ' . json_encode($session));
        
        // Get metadata
        $metadata = isset($session->metadata) ? $session->metadata : new stdClass();
        error_log('Session metadata: ' . json_encode($metadata));
        
        // Try to get plan_id from different sources
        $plan_id = null;
        if (isset($metadata->plan_id)) {
            $plan_id = $metadata->plan_id;
            error_log('Plan ID from metadata: ' . $plan_id);
        } elseif (isset($session->client_reference_id)) {
            $plan_id = $session->client_reference_id;
            error_log('Plan ID from client_reference_id: ' . $plan_id);
        }
        
        // Try to get user_id from different sources
        $user_id = null;
        if (isset($metadata->user_id)) {
            $user_id = $metadata->user_id;
            error_log('User ID from metadata: ' . $user_id);
        }
        
        // If we don't have a user ID but have an email, try to find the user
        if (!$user_id && isset($session->customer_details) && isset($session->customer_details->email)) {
            $user = get_user_by('email', $session->customer_details->email);
            if ($user) {
                $user_id = $user->ID;
                error_log('User ID found by email: ' . $user_id);
            }
        }
        
        if (!$plan_id) {
            // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Debug logging for missing plan ID
            error_log('Missing plan_id in session data');
            return;
        }
        
        if (!$user_id) {
            // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Debug logging for missing user ID
            error_log('Missing user_id in session data');
            return;
        }
        
        // Get customer details
        $customer_email = isset($session->customer_details->email) ? $session->customer_details->email : '';
        $customer_name = isset($session->customer_details->name) ? $session->customer_details->name : '';
        
        // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Debug logging for subscription creation
        error_log("Creating subscription for user $user_id, plan $plan_id, email $customer_email");
        
        // Create subscription regardless of whether it's a one-time payment or recurring subscription
        $manager = new Subs_Sys_Manager();
        
        // For one-time payments, we need to calculate the end date based on the plan duration
        $plan = $manager->get_plan($plan_id);
        if (!$plan) {
            // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Debug logging for missing plan
            error_log('Plan not found with ID: ' . $plan_id);
            return;
        }
        
        $subscription_id = $manager->create_subscription($user_id, $plan_id, [
            'payment_id' => $session->id,
            'customer_email' => $customer_email,
            'customer_name' => $customer_name,
            'status' => 'active'
        ]);
        
        if (is_wp_error($subscription_id)) {
            // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Debug logging for subscription creation error
            error_log('Error creating subscription: ' . $subscription_id->get_error_message());
        } else {
            // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Debug logging for successful subscription creation
            error_log('Subscription created successfully: ' . $subscription_id);
        }
    }

    /**
     * Handle invoice.payment_succeeded event
     */
    private function handle_payment_succeeded($invoice) {
        // This is for recurring payments
        if (!$invoice->subscription) {
            return true; // Not a subscription invoice
        }
        
        $subscription_id = $invoice->subscription;
        
        // Get subscription from database
        $subscription_db = new Subs_Sys_DB();
        $subscription = $subscription_db->get_subscription_by_stripe_id($subscription_id);
        
        if (!$subscription) {
            error_log('Subscription not found for Stripe ID: ' . $subscription_id);
            return false;
        }
        
        // Update subscription end date
        $stripe_subscription = $this->stripe->subscriptions->retrieve($subscription_id);
        
        return $subscription_db->update_subscription(
            $subscription->id,
            array(
                'status' => 'active',
                'end_date' => date('Y-m-d H:i:s', $stripe_subscription->current_period_end),
                'updated_at' => current_time('mysql')
            )
        );
    }

    /**
     * Get WordPress user ID from session metadata
     */
    private function get_user_id_from_session($session) {
        // Check if user ID is in metadata
        if (isset($session->metadata->user_id)) {
            return $session->metadata->user_id;
        }
        
        // If not in metadata, try to find by customer ID
        $subscription_db = new Subs_Sys_DB();
        return $subscription_db->get_user_id_by_customer_id($session->customer);
    }

    /**
     * Get plan ID from session metadata
     */
    private function get_plan_id_from_session($session) {
        // Check if plan ID is in metadata
        if (isset($session->metadata->plan_id)) {
            return $session->metadata->plan_id;
        }
        
        // If not in metadata, try to get from line items
        $checkout_session = $this->stripe->checkout->sessions->retrieve(
            $session->id,
            ['expand' => ['line_items']]
        );
        
        if (isset($checkout_session->line_items->data[0]->price->metadata->plan_id)) {
            return $checkout_session->line_items->data[0]->price->metadata->plan_id;
        }
        
        return null;
    }

    /**
     * Update user role based on subscription plan
     */
    private function update_user_role($user_id, $plan_id) {
        $user = get_user_by('id', $user_id);
        if (!$user) {
            return false;
        }
        
        // Get the role associated with this plan
        $subscription_db = new Subs_Sys_DB();
        $plan = $subscription_db->get_plan($plan_id);
        
        if (!$plan || empty($plan->role)) {
            return false;
        }
        
        // Remove existing roles and add the new one
        $user->set_role($plan->role);
        
        return true;
    }

    /**
     * Get or create a Stripe customer for a WordPress user
     *
     * @param WP_User $user WordPress user object
     * @return \Stripe\Customer Stripe customer object
     */
    public function get_or_create_customer($user) {
        try {
            // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Debug logging for customer creation start
            error_log('Starting get_or_create_customer for user ID: ' . $user->ID);
            
            // Check if user already has a Stripe customer ID
            global $wpdb;
            $table_name = $wpdb->prefix . 'subscriptions';
            
            $query = $wpdb->prepare(
                "SELECT stripe_customer_id FROM $table_name WHERE user_id = %d AND stripe_customer_id IS NOT NULL LIMIT 1",
                $user->ID
            );
            // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Debug logging for SQL query
            error_log('SQL Query: ' . $query);
            
            $customer_id = $wpdb->get_var($query);
            // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Debug logging for customer ID retrieval
            error_log('Retrieved customer_id from DB: ' . ($customer_id ? $customer_id : 'null'));
            
            if ($customer_id) {
                // Customer exists, retrieve it
                // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Debug logging for existing customer
                error_log('Retrieving existing Stripe customer: ' . $customer_id);
                return \Stripe\Customer::retrieve($customer_id);
            }
            
            // Create new customer
            // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Debug logging for new customer creation
            error_log('Creating new Stripe customer for user: ' . $user->user_email);
            $customer = \Stripe\Customer::create([
                'email' => $user->user_email,
                'name' => $user->display_name,
                'metadata' => [
                    'wordpress_user_id' => $user->ID
                ]
            ]);
            
            // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Debug logging for successful customer creation
            error_log('New Stripe customer created: ' . $customer->id);
            return $customer;
        } catch (\Exception $e) {
            // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Debug logging for customer creation error
            error_log('Stripe error in get_or_create_customer: ' . $e->getMessage());
            // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Debug logging for exception trace
            error_log('Exception trace: ' . $e->getTraceAsString());
            throw $e;
        }
    }

    /**
     * Create a Stripe Checkout session
     */
    public function create_checkout_session($customer_id, $plan, $metadata = array()) {
        try {
            error_log('Creating checkout session for customer: ' . $customer_id);
            error_log('Plan details: ' . print_r($plan, true));
            error_log('Metadata: ' . print_r($metadata, true));
            
            // Check if plan object has required properties
            if (!isset($plan->plan_name) || !isset($plan->price)) {
                error_log('ERROR: Plan object missing required properties');
                error_log('Plan object: ' . print_r($plan, true));
                throw new \Exception('Invalid plan data: missing required properties');
            }
            
            $session_data = [
                'customer' => $customer_id,
                'payment_method_types' => ['card'],
                'line_items' => [[
                    'price_data' => [
                        'currency' => 'usd',
                        'product_data' => [
                            'name' => $plan->plan_name,
                        ],
                        'unit_amount' => intval($plan->price * 100), // Convert to cents
                        'recurring' => [
                            'interval' => 'month',
                        ],
                    ],
                    'quantity' => 1,
                ]],
                'mode' => 'subscription',
                'success_url' => get_permalink(get_option('thank_you_page', 0)) ? 
                    add_query_arg('session_id', '{CHECKOUT_SESSION_ID}', get_permalink(get_option('thank_you_page', 0))) : 
                    home_url('/subscription-success?session_id={CHECKOUT_SESSION_ID}'),
                'cancel_url' => get_permalink(get_option('subscription_cancel_page', 0)) ?: 
                    home_url('/subscription-cancel'),
                'metadata' => $metadata
            ];
            
            error_log('Session data: ' . json_encode($session_data));
            
            $session = \Stripe\Checkout\Session::create($session_data);
            
            error_log('Checkout session created: ' . $session->id);
            return $session;
        } catch (Exception $e) {
            error_log('Stripe error in create_checkout_session: ' . $e->getMessage());
            error_log('Exception trace: ' . $e->getTraceAsString());
            return false;
        }
    }

    /**
     * Verify the webhook signature
     */
    public function verify_webhook($payload, $signature, $webhook_secret) {
        try {
            return \Stripe\Webhook::constructEvent(
                $payload, $signature, $webhook_secret
            );
        } catch (\UnexpectedValueException $e) {
            error_log('Invalid payload: ' . $e->getMessage());
            return false;
        } catch (\Stripe\Exception\SignatureVerificationException $e) {
            error_log('Invalid signature: ' . $e->getMessage());
            return false;
        }
    }

    // Add this debugging to your payment webhook or callback function
    // This would be in your Stripe processing code
    public function process_payment_success($payment_data) {
        error_log('Payment success webhook received: ' . json_encode($payment_data));
        
        // Extract user_id and plan_id from payment data
        $user_id = isset($payment_data['user_id']) ? $payment_data['user_id'] : 0;
        $plan_id = isset($payment_data['plan_id']) ? $payment_data['plan_id'] : 0;
        
        error_log('Extracted user_id: ' . $user_id . ', plan_id: ' . $plan_id);
        
        if (!$user_id || !$plan_id) {
            error_log('Missing user_id or plan_id in payment data');
            return false;
        }
        
        // Create subscription
        $subscription_manager = new Subs_Sys_Manager();
        $subscription_id = $subscription_manager->create_subscription($user_id, $plan_id, [
            'payment_id' => $payment_data['payment_id'],
            'status' => 'active',
            'payment_method' => 'stripe'
        ]);
        
        if (is_wp_error($subscription_id)) {
            error_log('Error creating subscription: ' . $subscription_id->get_error_message());
            return false;
        }
        
        error_log('Subscription created successfully with ID: ' . $subscription_id);
        return $subscription_id;
    }

    /**
     * Get a Stripe Checkout Session
     *
     * @param string $session_id The session ID
     * @return \Stripe\Checkout\Session|false The session object or false on failure
     */
    public function get_session($session_id) {
        try {
            error_log('Retrieving session: ' . $session_id);
            return \Stripe\Checkout\Session::retrieve([
                'id' => $session_id,
                'expand' => ['customer', 'payment_intent', 'line_items']
            ]);
        } catch (\Exception $e) {
            error_log('Error retrieving session: ' . $e->getMessage());
            return false;
        }
    }
} 