<?php
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

class PC_Membership_Stripe {

    private static function get_options() {
        return get_option( 'pc_membership_options', array() );
    }

    private static function get_secret_key() {
        $options = self::get_options();
        $mode = isset( $options['mode'] ) ? $options['mode'] : 'test';
        return isset( $options[ $mode . '_secret_key' ] ) ? $options[ $mode . '_secret_key' ] : '';
    }

    private static function get_publishable_key() {
        $options = self::get_options();
        $mode = isset( $options['mode'] ) ? $options['mode'] : 'test';
        return isset( $options[ $mode . '_publishable_key' ] ) ? $options[ $mode . '_publishable_key' ] : '';
    }

    private static function get_currency() {
        $options = self::get_options();
        return isset( $options['currency'] ) ? $options['currency'] : 'usd';
    }

    public static function init() {
        $secret_key = self::get_secret_key();

        if ( empty( $secret_key ) ) {
            return false;
        }

        if ( ! class_exists( '\Stripe\Stripe' ) ) {
            if ( file_exists( PC_MEMBERSHIP_PLUGIN_DIR . 'vendor/autoload.php' ) ) {
                require_once PC_MEMBERSHIP_PLUGIN_DIR . 'vendor/autoload.php';
            }
        }

        if ( class_exists( '\Stripe\Stripe' ) ) {
            \Stripe\Stripe::setApiKey( $secret_key );
            \Stripe\Stripe::setApiVersion( '2023-10-16' );
            return true;
        }

        return false;
    }

    public static function create_checkout_session( $plan_id, $user_id = null, $customer_email = null ) {
        if ( ! self::init() ) {
            return new WP_Error( 'stripe_not_configured', __( 'Stripe is not configured properly.', 'pc-membership-abc123' ) );
        }

        global $wpdb;
        $plan = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}pc_membership_plans WHERE id = %d", $plan_id ) );

        if ( ! $plan ) {
            return new WP_Error( 'plan_not_found', __( 'Plan not found.', 'pc-membership-abc123' ) );
        }

        $user = null;
        $wp_user_id = null;

        if ( $user_id ) {
            $wp_user_id = $user_id;
        } elseif ( is_user_logged_in() ) {
            $wp_user_id = get_current_user_id();
        }

        $customer_id = null;
        $session_data = array(
            'payment_method_types' => array( 'card' ),
            'line_items' => array(),
            'success_url' => add_query_arg( array(
                'session_id' => '{CHECKOUT_SESSION_ID}',
                'plan_id' => $plan_id,
            ), self::get_success_url() ),
            'cancel_url' => self::get_cancel_url(),
            'metadata' => array(
                'plan_id' => $plan_id,
                'wp_user_id' => $wp_user_id ?: 0,
            ),
        );

        try {
            if ( $wp_user_id ) {
                $user = get_userdata( $wp_user_id );
                if ( $user ) {
                    $customer_id = self::get_or_create_customer( $user, $wp_user_id );
                    if ( ! is_wp_error( $customer_id ) ) {
                        $session_data['customer'] = $customer_id;
                    } else {
                        $session_data['customer_email'] = $user->user_email;
                    }
                }
            } elseif ( $customer_email ) {
                $session_data['customer_email'] = $customer_email;
            }

            if ( $plan->is_subscription ) {
                $price_data = array(
                    'currency' => self::get_currency(),
                    'product_data' => array(
                        'name' => $plan->name,
                        'description' => $plan->description ? substr( $plan->description, 0, 500 ) : '',
                    ),
                    'recurring' => array(
                        'interval' => $plan->billing_interval,
                    ),
                    'unit_amount' => intval( $plan->price * 100 ),
                );

                $session_data['mode'] = 'subscription';
                $session_data['line_items'] = array(
                    array(
                        'price_data' => $price_data,
                        'quantity' => 1,
                    ),
                );

                if ( $plan->trial_days > 0 ) {
                    $session_data['subscription_data'] = array(
                        'trial_period_days' => $plan->trial_days,
                    );
                }
            } else {
                $session_data['mode'] = 'payment';
                $session_data['line_items'] = array(
                    array(
                        'price_data' => array(
                            'currency' => self::get_currency(),
                            'product_data' => array(
                                'name' => $plan->name,
                                'description' => $plan->description ? substr( $plan->description, 0, 500 ) : '',
                            ),
                            'unit_amount' => intval( $plan->price * 100 ),
                        ),
                        'quantity' => 1,
                    ),
                );
            }

            $session = \Stripe\Checkout\Session::create( $session_data );

            return $session;

        } catch ( \Exception $e ) {
            return new WP_Error( 'stripe_error', $e->getMessage() );
        }
    }

    public static function get_or_create_customer( $user, $wp_user_id ) {
        global $wpdb;

        $subscription = $wpdb->get_row( $wpdb->prepare(
            "SELECT stripe_customer_id FROM {$wpdb->prefix}pc_membership_subscriptions WHERE user_id = %d ORDER BY id DESC LIMIT 1",
            $wp_user_id
        ) );

        if ( $subscription && ! empty( $subscription->stripe_customer_id ) ) {
            return $subscription->stripe_customer_id;
        }

        try {
            $customer = \Stripe\Customer::create( array(
                'email' => $user->user_email,
                'name' => $user->display_name,
                'metadata' => array(
                    'wp_user_id' => $wp_user_id,
                ),
            ) );

            return $customer->id;

        } catch ( \Exception $e ) {
            return new WP_Error( 'stripe_customer_error', $e->getMessage() );
        }
    }

    public static function cancel_subscription( $stripe_subscription_id ) {
        if ( ! self::init() ) {
            return new WP_Error( 'stripe_not_configured', __( 'Stripe is not configured properly.', 'pc-membership-abc123' ) );
        }

        try {
            $subscription = \Stripe\Subscription::retrieve( $stripe_subscription_id );
            $subscription->cancel();

            return true;

        } catch ( \Exception $e ) {
            return new WP_Error( 'stripe_error', $e->getMessage() );
        }
    }

    public static function create_portal_session() {
        if ( ! self::init() ) {
            return new WP_Error( 'stripe_not_configured', __( 'Stripe is not configured properly.', 'pc-membership-abc123' ) );
        }

        if ( ! is_user_logged_in() ) {
            return new WP_Error( 'not_logged_in', __( 'User must be logged in.', 'pc-membership-abc123' ) );
        }

        global $wpdb;
        $subscription = $wpdb->get_row( $wpdb->prepare(
            "SELECT stripe_customer_id FROM {$wpdb->prefix}pc_membership_subscriptions WHERE user_id = %d AND status = 'active' ORDER BY id DESC LIMIT 1",
            get_current_user_id()
        ) );

        if ( ! $subscription || empty( $subscription->stripe_customer_id ) ) {
            return new WP_Error( 'no_customer', __( 'No Stripe customer found.', 'pc-membership-abc123' ) );
        }

        try {
            $session = \Stripe\BillingPortal\Session::create( array(
                'customer' => $subscription->stripe_customer_id,
                'return_url' => self::get_page_url( 'account' ),
            ) );

            return $session;

        } catch ( \Exception $e ) {
            return new WP_Error( 'stripe_error', $e->getMessage() );
        }
    }

    public static function retrieve_session( $session_id ) {
        if ( ! self::init() ) {
            return new WP_Error( 'stripe_not_configured', __( 'Stripe is not configured properly.', 'pc-membership-abc123' ) );
        }

        try {
            $session = \Stripe\Checkout\Session::retrieve( $session_id );
            return $session;

        } catch ( \Exception $e ) {
            return new WP_Error( 'stripe_error', $e->getMessage() );
        }
    }

    public static function handle_webhook() {
        if ( ! self::init() ) {
            return;
        }

        $options = get_option( 'pc_membership_options' );
        $webhook_secret = isset( $options['webhook_secret'] ) ? $options['webhook_secret'] : '';

        $payload = file_get_contents( 'php://input' );
        $sig_header = isset( $_SERVER['HTTP_STRIPE_SIGNATURE'] ) ? $_SERVER['HTTP_STRIPE_SIGNATURE'] : '';

        if ( empty( $webhook_secret ) || empty( $sig_header ) ) {
            return;
        }

        try {
            $event = \Stripe\Webhook::constructEvent( $payload, $sig_header, $webhook_secret );
        } catch ( \Exception $e ) {
            return;
        }

        self::process_webhook_event( $event );
    }

    private static function process_webhook_event( $event ) {
        global $wpdb;

        switch ( $event->type ) {
            case 'checkout.session.completed':
                self::handle_checkout_completed( $event->data->object );
                break;

            case 'customer.subscription.created':
            case 'customer.subscription.updated':
                self::handle_subscription_updated( $event->data->object );
                break;

            case 'customer.subscription.deleted':
                self::handle_subscription_deleted( $event->data->object );
                break;

            case 'invoice.payment_succeeded':
                self::handle_payment_succeeded( $event->data->object );
                break;

            case 'invoice.payment_failed':
                self::handle_payment_failed( $event->data->object );
                break;
        }
    }

    private static function handle_checkout_completed( $session ) {
        global $wpdb;

        $plan_id = isset( $session->metadata->plan_id ) ? absint( $session->metadata->plan_id ) : 0;
        $wp_user_id = isset( $session->metadata->wp_user_id ) ? absint( $session->metadata->wp_user_id ) : 0;
        $customer_id = $session->customer;
        $subscription_id = null;

        if ( empty( $plan_id ) ) {
            return;
        }

        $plan = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}pc_membership_plans WHERE id = %d", $plan_id ) );

        if ( ! $plan ) {
            return;
        }

        if ( $plan->is_subscription && ! empty( $session->subscription ) ) {
            $subscription_id = $session->subscription;

            try {
                $stripe_subscription = \Stripe\Subscription::retrieve( $subscription_id );
                $period_end = date( 'Y-m-d H:i:s', $stripe_subscription->current_period_end );
            } catch ( \Exception $e ) {
                $period_end = null;
            }
        } else {
            $period_end = null;
        }

        if ( $wp_user_id && $customer_id ) {
            $existing = $wpdb->get_var( $wpdb->prepare(
                "SELECT id FROM {$wpdb->prefix}pc_membership_subscriptions WHERE user_id = %d AND plan_id = %d",
                $wp_user_id,
                $plan_id
            ) );

            if ( $existing ) {
                $wpdb->update( $wpdb->prefix . 'pc_membership_subscriptions', array(
                    'stripe_customer_id' => $customer_id,
                    'stripe_subscription_id' => $subscription_id ?: '',
                    'status' => 'active',
                    'expires_at' => $period_end,
                ), array( 'id' => $existing ) );
            } else {
                $wpdb->insert( $wpdb->prefix . 'pc_membership_subscriptions', array(
                    'user_id' => $wp_user_id,
                    'plan_id' => $plan_id,
                    'stripe_customer_id' => $customer_id,
                    'stripe_subscription_id' => $subscription_id ?: '',
                    'status' => 'active',
                    'started_at' => current_time( 'mysql' ),
                    'expires_at' => $period_end,
                ) );

                if ( $plan->role ) {
                    $user = get_userdata( $wp_user_id );
                    if ( $user ) {
                        $user->set_role( $plan->role );
                    }
                }
            }

            if ( $session->mode === 'payment' && isset( $session->amount_total ) ) {
                $wpdb->insert( $wpdb->prefix . 'pc_membership_payments', array(
                    'user_id' => $wp_user_id,
                    'plan_id' => $plan_id,
                    'stripe_payment_intent' => $session->payment_intent ?: '',
                    'amount' => $session->amount_total / 100,
                    'currency' => self::get_currency(),
                    'status' => 'succeeded',
                ) );
            }
        }
    }

    private static function handle_subscription_updated( $subscription ) {
        global $wpdb;

        $stripe_sub_id = $subscription->id;
        $customer_id = $subscription->customer;
        $status = self::map_stripe_status( $subscription->status );
        $period_end = date( 'Y-m-d H:i:s', $subscription->current_period_end );

        $existing = $wpdb->get_row( $wpdb->prepare(
            "SELECT * FROM {$wpdb->prefix}pc_membership_subscriptions WHERE stripe_subscription_id = %s",
            $stripe_sub_id
        ) );

        if ( $existing ) {
            $wpdb->update( $wpdb->prefix . 'pc_membership_subscriptions', array(
                'status' => $status,
                'expires_at' => $period_end,
            ), array( 'id' => $existing->id ) );

            if ( $status === 'active' ) {
                $plan = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}pc_membership_plans WHERE id = %d", $existing->plan_id ) );
                if ( $plan && $plan->role ) {
                    $user = get_userdata( $existing->user_id );
                    if ( $user ) {
                        $user->set_role( $plan->role );
                    }
                }
            }
        }
    }

    private static function handle_subscription_deleted( $subscription ) {
        global $wpdb;

        $stripe_sub_id = $subscription->id;

        $existing = $wpdb->get_row( $wpdb->prepare(
            "SELECT * FROM {$wpdb->prefix}pc_membership_subscriptions WHERE stripe_subscription_id = %s",
            $stripe_sub_id
        ) );

        if ( $existing ) {
            $wpdb->update( $wpdb->prefix . 'pc_membership_subscriptions', array(
                'status' => 'cancelled',
            ), array( 'id' => $existing->id ) );

            $user = get_userdata( $existing->user_id );
            if ( $user ) {
                $user->set_role( 'subscriber' );
            }
        }
    }

    private static function handle_payment_succeeded( $invoice ) {
        global $wpdb;

        if ( empty( $invoice->subscription ) ) {
            return;
        }

        $stripe_sub_id = $invoice->subscription;

        $subscription = $wpdb->get_row( $wpdb->prepare(
            "SELECT * FROM {$wpdb->prefix}pc_membership_subscriptions WHERE stripe_subscription_id = %s",
            $stripe_sub_id
        ) );

        if ( ! $subscription ) {
            return;
        }

        $wpdb->insert( $wpdb->prefix . 'pc_membership_payments', array(
            'user_id' => $subscription->user_id,
            'plan_id' => $subscription->plan_id,
            'stripe_payment_intent' => $invoice->payment_intent ?: '',
            'amount' => $invoice->amount_paid / 100,
            'currency' => strtolower( $invoice->currency ),
            'status' => 'succeeded',
        ) );

        if ( isset( $invoice->billing_reason ) && $invoice->billing_reason === 'subscription_cycle' ) {
            $stripe_sub = \Stripe\Subscription::retrieve( $stripe_sub_id );
            $period_end = date( 'Y-m-d H:i:s', $stripe_sub->current_period_end );

            $wpdb->update( $wpdb->prefix . 'pc_membership_subscriptions', array(
                'expires_at' => $period_end,
            ), array( 'id' => $subscription->id ) );
        }
    }

    private static function handle_payment_failed( $invoice ) {
        global $wpdb;

        if ( empty( $invoice->subscription ) ) {
            return;
        }

        $stripe_sub_id = $invoice->subscription;

        $subscription = $wpdb->get_row( $wpdb->prepare(
            "SELECT * FROM {$wpdb->prefix}pc_membership_subscriptions WHERE stripe_subscription_id = %s",
            $stripe_sub_id
        ) );

        if ( $subscription ) {
            $user = get_user_by( 'id', $subscription->user_id );
            if ( $user ) {
                wp_mail(
                    $user->user_email,
                    __( 'Payment Failed', 'pc-membership-abc123' ),
                    __( 'Your membership payment has failed. Please update your payment method to continue your subscription.', 'pc-membership-abc123' )
                );
            }
        }
    }

    private static function map_stripe_status( $stripe_status ) {
        $map = array(
            'active' => 'active',
            'past_due' => 'past_due',
            'unpaid' => 'unpaid',
            'canceled' => 'cancelled',
            'incomplete' => 'pending',
            'incomplete_expired' => 'expired',
            'trialing' => 'active',
            'paused' => 'paused',
        );

        return isset( $map[ $stripe_status ] ) ? $map[ $stripe_status ] : 'pending';
    }

    private static function get_success_url() {
        $options = get_option( 'pc_membership_options' );
        $page_id = isset( $options['success_page_id'] ) ? absint( $options['success_page_id'] ) : 0;
        return $page_id ? get_permalink( $page_id ) : home_url();
    }

    private static function get_cancel_url() {
        $options = get_option( 'pc_membership_options' );
        $page_id = isset( $options['cancel_page_id'] ) ? absint( $options['cancel_page_id'] ) : 0;
        return $page_id ? get_permalink( $page_id ) : home_url();
    }

    private static function get_page_url( $page_type ) {
        $options = get_option( 'pc_membership_options' );
        $page_id = isset( $options[ $page_type . '_page_id' ] ) ? absint( $options[ $page_type . '_page_id' ] ) : 0;
        return $page_id ? get_permalink( $page_id ) : home_url();
    }
}
