<?php
/**
 * Settings class for Stripe Subscription Manager
 * Manages plugin settings and Stripe API keys
 */

// Exit if accessed directly
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

class STRP_SUB_Settings {

    /**
     * Single instance
     */
    private static $instance = null;

    /**
     * Settings option name
     */
    const OPTION_NAME = 'strp_sub_settings';

    /**
     * Get instance
     */
    public static function get_instance() {
        if ( null === self::$instance ) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    private function __clone() {}

    public function __wakeup() {
        throw new \RuntimeException( 'Cannot unserialize singleton.' );
    }

    /**
     * Constructor
     */
    private function __construct() {
        add_action( 'admin_init', array( $this, 'register_settings' ) );
        add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_upgrade_banner_assets' ) );
        add_action( 'wp_ajax_strp_sub_dismiss_upgrade_banner', array( $this, 'ajax_dismiss_upgrade_banner' ) );
    }

    /**
     * Register settings
     */
    public function register_settings() {
        register_setting( 'strp_sub_settings_group', self::OPTION_NAME, array( $this, 'sanitize_settings' ) );

        // -- OAuth Client ID --
        register_setting( 'strp_sub_settings_group', 'strp_sub_oauth_client_id', array(
            'sanitize_callback' => 'sanitize_text_field',
            'default'           => '',
        ) );

        register_setting( 'strp_sub_settings_group', 'strp_sub_oauth_client_secret', array(
            'sanitize_callback' => array( $this, 'sanitize_oauth_client_secret' ),
            'default'           => '',
        ) );

        // -- White-label settings (Agency plan) --
        register_setting( 'strp_sub_settings_group', 'strp_sub_white_label', array(
            'sanitize_callback' => function ( $input ) {
                if ( function_exists( 'strp_sub_fs' ) && strp_sub_fs() && strp_sub_fs()->is__premium_only() ) {
                    if ( ! class_exists( 'STRP_SUB_Freemius' ) || ! STRP_SUB_Freemius::has_feature( 'agency' ) ) {
                        return '';
                    }
                }
                return $input === 'yes' ? 'yes' : '';
            },
            'default' => '',
        ) );
        register_setting( 'strp_sub_settings_group', 'strp_sub_white_label_name', array(
            'sanitize_callback' => function ( $input ) {
                if ( function_exists( 'strp_sub_fs' ) && strp_sub_fs() && strp_sub_fs()->is__premium_only() ) {
                    if ( ! class_exists( 'STRP_SUB_Freemius' ) || ! STRP_SUB_Freemius::has_feature( 'agency' ) ) {
                        return '';
                    }
                }
                return sanitize_text_field( $input );
            },
            'default' => '',
        ) );

        // -- General settings section --
        add_settings_section(
            'strp_sub_general_section',
            __( 'General Settings', 'subscription-manager-for-stripe' ),
            array( $this, 'general_section_callback' ),
            'strp-sub-settings'
        );

        // Test mode field
        add_settings_field(
            'test_mode',
            __( 'Test Mode', 'subscription-manager-for-stripe' ),
            array( $this, 'test_mode_callback' ),
            'strp-sub-settings',
            'strp_sub_general_section'
        );

        // OAuth Client ID
        add_settings_field(
            'oauth_client_id',
            __( 'Stripe OAuth Client ID', 'subscription-manager-for-stripe' ),
            array( $this, 'oauth_client_id_callback' ),
            'strp-sub-settings',
            'strp_sub_general_section'
        );

        add_settings_field(
            'oauth_client_secret',
            __( 'Stripe OAuth Client Secret', 'subscription-manager-for-stripe' ),
            array( $this, 'oauth_client_secret_callback' ),
            'strp-sub-settings',
            'strp_sub_general_section'
        );

        // Test publishable key (fallback when OAuth is not connected)
        add_settings_field(
            'test_publishable_key',
            __( 'Test Publishable Key', 'subscription-manager-for-stripe' ),
            array( $this, 'test_publishable_key_callback' ),
            'strp-sub-settings',
            'strp_sub_general_section'
        );


        // Live publishable key (fallback when OAuth is not connected)
        add_settings_field(
            'live_publishable_key',
            __( 'Live Publishable Key', 'subscription-manager-for-stripe' ),
            array( $this, 'live_publishable_key_callback' ),
            'strp-sub-settings',
            'strp_sub_general_section'
        );

        // Test webhook secret
        add_settings_field(
            'test_webhook_secret',
            __( 'Test Webhook Signing Secret', 'subscription-manager-for-stripe' ),
            array( $this, 'test_webhook_secret_callback' ),
            'strp-sub-settings',
            'strp_sub_general_section'
        );

        // Live webhook secret
        add_settings_field(
            'live_webhook_secret',
            __( 'Live Webhook Signing Secret', 'subscription-manager-for-stripe' ),
            array( $this, 'live_webhook_secret_callback' ),
            'strp-sub-settings',
            'strp_sub_general_section'
        );

        // Log level
        add_settings_field(
            'log_level',
            __( 'Log Level', 'subscription-manager-for-stripe' ),
            array( $this, 'log_level_callback' ),
            'strp-sub-settings',
            'strp_sub_general_section'
        );

        add_settings_field(
            'strp_sub_wipe_data',
            __( 'Wipe Data on Uninstall', 'subscription-manager-for-stripe' ),
            array( $this, 'wipe_data_callback' ),
            'strp-sub-settings',
            'strp_sub_general_section'
        );

        // White-label branding (Agency plan).
        add_settings_field(
            'strp_sub_white_label',
            __( 'White-Label Branding', 'subscription-manager-for-stripe' ),
            array( $this, 'white_label_callback' ),
            'strp-sub-settings',
            'strp_sub_general_section'
        );

        // -- Product Mappings Section --
        add_settings_section(
            'strp_sub_products_section',
            __( 'Subscription Products', 'subscription-manager-for-stripe' ),
            array( $this, 'products_section_callback' ),
            'strp-sub-settings'
        );

        add_settings_field(
            'monthly_product_id',
            __( 'Monthly Product ID', 'subscription-manager-for-stripe' ),
            array( $this, 'monthly_product_id_callback' ),
            'strp-sub-settings',
            'strp_sub_products_section'
        );

        add_settings_field(
            'annual_product_id',
            __( 'Annual Product ID', 'subscription-manager-for-stripe' ),
            array( $this, 'annual_product_id_callback' ),
            'strp-sub-settings',
            'strp_sub_products_section'
        );

        add_settings_field(
            'lifetime_product_id',
            __( 'Lifetime Product ID', 'subscription-manager-for-stripe' ),
            array( $this, 'lifetime_product_id_callback' ),
            'strp-sub-settings',
            'strp_sub_products_section'
        );

        // -- Checkout & Trial Settings section --
        add_settings_section(
            'strp_sub_checkout_section',
            __( 'Checkout & Trial Settings', 'subscription-manager-for-stripe' ),
            array( $this, 'checkout_section_callback' ),
            'strp-sub-settings'
        );

        add_settings_field(
            'trial_period_days',
            __( 'Trial Period (Days)', 'subscription-manager-for-stripe' ),
            array( $this, 'trial_period_days_callback' ),
            'strp-sub-settings',
            'strp_sub_checkout_section'
        );

        add_settings_field(
            'checkout_msg_upgrade',
            __( 'Checkout Message -- Upgrade', 'subscription-manager-for-stripe' ),
            array( $this, 'checkout_msg_upgrade_callback' ),
            'strp-sub-settings',
            'strp_sub_checkout_section'
        );

        add_settings_field(
            'checkout_msg_trial',
            __( 'Checkout Message -- Trial', 'subscription-manager-for-stripe' ),
            array( $this, 'checkout_msg_trial_callback' ),
            'strp-sub-settings',
            'strp_sub_checkout_section'
        );

        add_settings_field(
            'checkout_msg_no_trial',
            __( 'Checkout Message -- No Trial', 'subscription-manager-for-stripe' ),
            array( $this, 'checkout_msg_no_trial_callback' ),
            'strp-sub-settings',
            'strp_sub_checkout_section'
        );

        add_settings_field(
            'checkout_msg_onetime_upgrade',
            __( 'Checkout Message -- One-Time Upgrade', 'subscription-manager-for-stripe' ),
            array( $this, 'checkout_msg_onetime_upgrade_callback' ),
            'strp-sub-settings',
            'strp_sub_checkout_section'
        );

        add_settings_field(
            'checkout_msg_onetime_new',
            __( 'Checkout Message -- One-Time New', 'subscription-manager-for-stripe' ),
            array( $this, 'checkout_msg_onetime_new_callback' ),
            'strp-sub-settings',
            'strp_sub_checkout_section'
        );

        // -- Stripe Tax section (Starter+) --
        if ( function_exists( 'strp_sub_fs' ) && strp_sub_fs() && strp_sub_fs()->is__premium_only() ) {
            add_settings_section(
                'strp_sub_tax_section',
                __( 'Stripe Tax', 'subscription-manager-for-stripe' ),
                array( $this, 'tax_section_callback' ),
                'strp-sub-settings'
            );

            add_settings_field(
                'enable_automatic_tax',
                __( 'Automatic Tax', 'subscription-manager-for-stripe' ),
                array( $this, 'enable_automatic_tax_callback' ),
                'strp-sub-settings',
                'strp_sub_tax_section'
            );
        }
    }

    /**
     * General section callback -- renders the OAuth connection banner first.
     */
    public function general_section_callback() {
        // -- OAuth connection status banner --
        if ( class_exists( 'STRP_SUB_OAuth' ) ) {
            STRP_SUB_OAuth::render_connection_section();
        }

        echo '<p>' . esc_html__( 'Configure Stripe OAuth credentials and webhook settings below.', 'subscription-manager-for-stripe' ) . '</p>';
        echo '<p><strong>' . esc_html__( 'Webhook URL:', 'subscription-manager-for-stripe' ) . '</strong> <code>' . esc_url( rest_url( 'stripe-sub/v1/webhook' ) ) . '</code></p>';
        echo '<p class="description">';
        echo esc_html__( 'OAuth is the required runtime authentication mode. Legacy manual secret keys are deprecated and not used for runtime Stripe API calls.', 'subscription-manager-for-stripe' );
        echo '</p>';
    }

    /**
     * Test mode callback
     */
    public function test_mode_callback() {
        $settings = get_option( self::OPTION_NAME, array() );
        $test_mode = isset( $settings['test_mode'] ) ? $settings['test_mode'] : 'yes';
        ?>
        <label>
            <input type="checkbox" name="<?php echo esc_attr( self::OPTION_NAME ); ?>[test_mode]" value="yes" <?php checked( $test_mode, 'yes' ); ?> />
            <?php esc_html_e( 'Enable test mode', 'subscription-manager-for-stripe' ); ?>
        </label>
        <p class="description"><?php esc_html_e( 'Use Stripe test keys for testing. Disable for live payments.', 'subscription-manager-for-stripe' ); ?></p>
        <?php
    }

    /**
     * Stripe OAuth Client ID field.
     * The Client ID identifies your platform app on Stripe's Connect network.
     */
    public function oauth_client_id_callback() {
        $is_disabled = defined( 'STRP_SUB_OAUTH_CLIENT_ID' );
        if ( $is_disabled ) {
            $value = 'xxxxxxxxxxxxxxxx (Defined in wp-config.php)';
        } else {
            $value = get_option( 'strp_sub_oauth_client_id', '' );
        }
        ?>
        <input type="text"
               name="strp_sub_oauth_client_id"
               id="strp_sub_oauth_client_id"
               value="<?php echo esc_attr( $value ); ?>"
               class="regular-text"
               placeholder="ca_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
               <?php disabled( $is_disabled ); ?> />
        <p class="description">
            <?php esc_html_e( 'Get your Client ID from Stripe Dashboard > Settings > Connect. Required for the 1-click "Connect with Stripe" OAuth flow.', 'subscription-manager-for-stripe' ); ?>
        </p>
        <?php
        if ( class_exists( 'STRP_SUB_OAuth' ) ) {
            $redirect_uri = STRP_SUB_OAuth::get_redirect_uri();
            echo '<p class="description"><strong>' . esc_html__( 'Redirect URI to whitelist in Stripe:', 'subscription-manager-for-stripe' ) . '</strong><br>';
            echo '<code>' . esc_url( $redirect_uri ) . '</code></p>';
        }
    }

    /**
     * Stripe OAuth Client Secret field (used for token exchange/deauthorise calls).
     */
    public function oauth_client_secret_callback() {
        $is_disabled = defined( 'STRP_SUB_OAUTH_CLIENT_SECRET' );
        if ( $is_disabled ) {
            $value = 'xxxxxxxxxxxxxxxx (Defined in wp-config.php)';
        } else {
            $value = get_option( 'strp_sub_oauth_client_secret', '' );
            $value = ! empty( $value ) ? '********' : '';
        }
        ?>
        <input type="password"
               name="strp_sub_oauth_client_secret"
               id="strp_sub_oauth_client_secret"
               value="<?php echo esc_attr( $value ); ?>"
               class="regular-text"
               autocomplete="off"
               <?php disabled( $is_disabled ); ?> />
        <p class="description">
            <?php esc_html_e( 'Store your Stripe Connect app client secret for secure OAuth token exchange. This is not your account API secret key.', 'subscription-manager-for-stripe' ); ?>
        </p>
        <?php
    }

    /**
     * Test publishable key callback
     */
    public function test_publishable_key_callback() {
        $is_disabled = defined( 'STRP_SUB_TEST_PUBLISHABLE_KEY' );
        if ( $is_disabled ) {
            $value = 'xxxxxxxxxxxxxxxx (Defined in wp-config.php)';
        } else {
            $settings = get_option( self::OPTION_NAME, array() );
            $value = isset( $settings['test_publishable_key'] ) ? $settings['test_publishable_key'] : '';
        }
        ?>
        <input type="text" name="<?php echo esc_attr( self::OPTION_NAME ); ?>[test_publishable_key]" value="<?php echo esc_attr( $value ); ?>" class="regular-text" <?php disabled( $is_disabled ); ?> />
        <p class="description"><?php esc_html_e( 'Get your API keys from your Stripe account.', 'subscription-manager-for-stripe' ); ?></p>
        <?php
    }

    /**
     * Live publishable key callback
     */
    public function live_publishable_key_callback() {
        $is_disabled = defined( 'STRP_SUB_LIVE_PUBLISHABLE_KEY' );
        if ( $is_disabled ) {
            $value = 'xxxxxxxxxxxxxxxx (Defined in wp-config.php)';
        } else {
            $settings = get_option( self::OPTION_NAME, array() );
            $value = isset( $settings['live_publishable_key'] ) ? $settings['live_publishable_key'] : '';
        }
        ?>
        <input type="text" name="<?php echo esc_attr( self::OPTION_NAME ); ?>[live_publishable_key]" value="<?php echo esc_attr( $value ); ?>" class="regular-text" <?php disabled( $is_disabled ); ?> />
        <?php
    }

    /**
     * Test webhook secret callback
     */
    public function test_webhook_secret_callback() {
        $is_disabled = defined( 'STRP_SUB_TEST_WEBHOOK_SECRET' );
        if ( $is_disabled ) {
            $value = 'xxxxxxxxxxxxxxxx (Defined in wp-config.php)';
        } else {
            $settings = get_option( self::OPTION_NAME, array() );
            $value = isset( $settings['test_webhook_secret'] ) ? $settings['test_webhook_secret'] : '';
            $value = ! empty( $value ) ? '********' : '';
        }
        ?>
        <input type="password" name="<?php echo esc_attr( self::OPTION_NAME ); ?>[test_webhook_secret]" value="<?php echo esc_attr( $value ); ?>" class="regular-text" <?php disabled( $is_disabled ); ?> />
        <p class="description"><?php esc_html_e( 'Get this from your Stripe test webhook settings.', 'subscription-manager-for-stripe' ); ?></p>
        <?php
    }

    /**
     * Live webhook secret callback
     */
    public function live_webhook_secret_callback() {
        $is_disabled = defined( 'STRP_SUB_LIVE_WEBHOOK_SECRET' );
        if ( $is_disabled ) {
            $value = 'xxxxxxxxxxxxxxxx (Defined in wp-config.php)';
        } else {
            $settings = get_option( self::OPTION_NAME, array() );
            $value = isset( $settings['live_webhook_secret'] ) ? $settings['live_webhook_secret'] : '';
            $value = ! empty( $value ) ? '********' : '';
        }
        ?>
        <input type="password" name="<?php echo esc_attr( self::OPTION_NAME ); ?>[live_webhook_secret]" value="<?php echo esc_attr( $value ); ?>" class="regular-text" <?php disabled( $is_disabled ); ?> />
        <p class="description"><?php esc_html_e( 'Get this from your Stripe live webhook settings.', 'subscription-manager-for-stripe' ); ?></p>
        <?php
    }

    /**
     * Log level callback
     */
    public function log_level_callback() {
        $settings = get_option( self::OPTION_NAME, array() );
        $value = isset( $settings['log_level'] ) ? $settings['log_level'] : 'info';
        ?>
        <select name="<?php echo esc_attr( self::OPTION_NAME ); ?>[log_level]">
            <option value="error" <?php selected( $value, 'error' ); ?>><?php esc_html_e( 'Errors only', 'subscription-manager-for-stripe' ); ?></option>
            <option value="warning" <?php selected( $value, 'warning' ); ?>><?php esc_html_e( 'Errors + Warnings', 'subscription-manager-for-stripe' ); ?></option>
            <option value="info" <?php selected( $value, 'info' ); ?>><?php esc_html_e( 'Normal (recommended)', 'subscription-manager-for-stripe' ); ?></option>
            <option value="debug" <?php selected( $value, 'debug' ); ?>><?php esc_html_e( 'Debug (verbose)', 'subscription-manager-for-stripe' ); ?></option>
        </select>
        <p class="description"><?php esc_html_e( 'Control how much is logged. Use "Errors only" in production to minimize log size.', 'subscription-manager-for-stripe' ); ?></p>
        <?php
    }

    public function wipe_data_callback() {
        $value = self::get( 'strp_sub_wipe_data', 'no' );
        ?>
        <label>
            <input type="checkbox" name="<?php echo esc_attr( self::OPTION_NAME ); ?>[strp_sub_wipe_data]" value="yes" <?php checked( $value, 'yes' ); ?>>
            <span style="color:#d63638;font-weight:600;"><?php esc_html_e( 'Erase all manager settings, custom tables, session logs, and trial fingerprints completely from the database when deleting this plugin via the dashboard.', 'subscription-manager-for-stripe' ); ?></span>
        </label>
        <?php
    }

    /**
     * White-label branding callback (Agency plan).
     */
    public function white_label_callback() {
        $has_agency = true;
        if ( function_exists( 'strp_sub_fs' ) && strp_sub_fs() && strp_sub_fs()->is__premium_only() ) {
            $has_agency = class_exists( 'STRP_SUB_Freemius' ) && STRP_SUB_Freemius::has_feature( 'agency' );
        }
        $enabled     = get_option( 'strp_sub_white_label', '' );
        $custom_name = get_option( 'strp_sub_white_label_name', '' );

        if ( ! $has_agency ) {
            ?>
            <label>
                <input type="checkbox" disabled />
                <?php esc_html_e( 'Remove plugin branding', 'subscription-manager-for-stripe' ); ?>
                <em>(<?php esc_html_e( 'Agency plan required', 'subscription-manager-for-stripe' ); ?>)</em>
            </label>
            <?php
            return;
        }
        ?>
        <label>
            <input type="checkbox"
                   name="strp_sub_white_label"
                   value="yes"
                   <?php checked( $enabled, 'yes' ); ?> />
            <?php esc_html_e( 'Remove plugin branding from admin menus and headings', 'subscription-manager-for-stripe' ); ?>
        </label>
        <br><br>
        <label>
            <?php esc_html_e( 'Custom plugin name:', 'subscription-manager-for-stripe' ); ?>
            <input type="text"
                   name="strp_sub_white_label_name"
                   value="<?php echo esc_attr( $custom_name ); ?>"
                   class="regular-text"
                   placeholder="<?php esc_attr_e( 'Subscription Manager', 'subscription-manager-for-stripe' ); ?>" />
        </label>
        <p class="description"><?php esc_html_e( 'Leave blank to use "Subscription Manager" as the default white-label name.', 'subscription-manager-for-stripe' ); ?></p>
        <?php
    }

    /**
     * Products section description.
     */
    public function products_section_callback() {
        echo '<p>' . esc_html__( 'Map your core WooCommerce products to their subscription roles so discounts apply correctly.', 'subscription-manager-for-stripe' ) . '</p>';
    }

    public function monthly_product_id_callback() {
        $value = self::get( 'monthly_product_id', '' );
        echo '<input type="number" name="' . esc_attr( self::OPTION_NAME ) . '[monthly_product_id]" value="' . esc_attr( $value ) . '" class="regular-text" />';
        echo '<p class="description">' . esc_html__( 'The WooCommerce product ID representing your monthly subscription.', 'subscription-manager-for-stripe' ) . '</p>';
    }

    public function annual_product_id_callback() {
        $value = self::get( 'annual_product_id', '' );
        echo '<input type="number" name="' . esc_attr( self::OPTION_NAME ) . '[annual_product_id]" value="' . esc_attr( $value ) . '" class="regular-text" />';
        echo '<p class="description">' . esc_html__( 'The WooCommerce product ID representing your annual subscription.', 'subscription-manager-for-stripe' ) . '</p>';
    }

    public function lifetime_product_id_callback() {
        $value = self::get( 'lifetime_product_id', '' );
        echo '<input type="number" name="' . esc_attr( self::OPTION_NAME ) . '[lifetime_product_id]" value="' . esc_attr( $value ) . '" class="regular-text" />';
        echo '<p class="description">' . esc_html__( 'The WooCommerce product ID representing your lifetime purchase.', 'subscription-manager-for-stripe' ) . '</p>';
    }

    /**
     * Checkout & Trial section description.
     */
    public function checkout_section_callback() {
        echo '<p>' . esc_html__( 'Configure the trial period and the text shown to customers on the Stripe Checkout page. Leave message fields blank to use the built-in English defaults.', 'subscription-manager-for-stripe' ) . '</p>';
    }

    /**
     * Stripe Tax section description.
     */
    public function tax_section_callback() {
        echo '<p>' . esc_html__( 'Control whether Stripe Tax is used during checkout. You must also enable Stripe Tax in your Stripe Dashboard for this to take effect.', 'subscription-manager-for-stripe' ) . '</p>';
    }

    /**
     * Enable automatic tax field.
     */
    public function enable_automatic_tax_callback() {
        $value = self::get( 'enable_automatic_tax', 'yes' );
        ?>
        <label>
            <input type="checkbox" name="<?php echo esc_attr( self::OPTION_NAME ); ?>[enable_automatic_tax]" value="yes" <?php checked( $value, 'yes' ); ?> />
            <?php esc_html_e( 'Enable Stripe Tax (automatic_tax) on checkout sessions', 'subscription-manager-for-stripe' ); ?>
        </label>
        <p class="description"><?php esc_html_e( 'When enabled, Stripe will automatically calculate and collect tax. You must also activate Stripe Tax in your Stripe Dashboard under Settings > Tax for this to work.', 'subscription-manager-for-stripe' ); ?></p>
        <?php
    }

    /**
     * Trial period days field.
     */
    public function trial_period_days_callback() {
        $value = self::get_trial_period_days();
        echo '<input type="number" min="1" max="365" name="' . esc_attr( self::OPTION_NAME ) . '[trial_period_days]" value="' . esc_attr( $value ) . '" class="small-text" />';
        echo '<p class="description">' . esc_html__( 'Number of free trial days for new subscriptions (1-365). Default: 21.', 'subscription-manager-for-stripe' ) . '</p>';
    }

    /**
     * Render a textarea for a checkout custom_text message field.
     */
    private function checkout_msg_field( $key, $placeholder ) {
        $value = self::get( $key, '' );
        echo '<textarea name="' . esc_attr( self::OPTION_NAME ) . '[' . esc_attr( $key ) . ']" class="large-text" rows="3" placeholder="' . esc_attr( $placeholder ) . '">' . esc_textarea( $value ) . '</textarea>';
        echo '<p class="description">' . esc_html__( 'Shown to customers at the bottom of the Stripe Checkout page. Leave blank to use the built-in default.', 'subscription-manager-for-stripe' ) . '</p>';
    }

    public function checkout_msg_upgrade_callback() {
        $this->checkout_msg_field(
            'checkout_msg_upgrade',
            __( 'Your current subscription will be cancelled and the new subscription will take effect immediately.', 'subscription-manager-for-stripe' )
        );
    }

    public function checkout_msg_trial_callback() {
        $this->checkout_msg_field(
            'checkout_msg_trial',
            __( 'You get a free trial. Your payment method is saved but will not be charged until after the trial ends.', 'subscription-manager-for-stripe' )
        );
    }

    public function checkout_msg_no_trial_callback() {
        $this->checkout_msg_field(
            'checkout_msg_no_trial',
            __( 'Your subscription starts immediately and will be charged today. The trial period is only available to new customers.', 'subscription-manager-for-stripe' )
        );
    }

    public function checkout_msg_onetime_upgrade_callback() {
        $this->checkout_msg_field(
            'checkout_msg_onetime_upgrade',
            __( 'Your current subscription will be cancelled and the Lifetime plan will take effect immediately.', 'subscription-manager-for-stripe' )
        );
    }

    public function checkout_msg_onetime_new_callback() {
        $this->checkout_msg_field(
            'checkout_msg_onetime_new',
            __( 'You will get immediate access to the Lifetime plan. The trial period is only available on recurring subscriptions.', 'subscription-manager-for-stripe' )
        );
    }

    /**
     * Render settings page (now standalone, not under WooCommerce).
     */
    public function render_settings_page() {
        // -- OAuth status notices (transient-based) --
        $user_id = get_current_user_id();
        $oauth_success = get_transient( 'strp_sub_oauth_success_' . $user_id );
        if ( $oauth_success ) {
            delete_transient( 'strp_sub_oauth_success_' . $user_id );
            echo '<div class="notice notice-success is-dismissible"><p>' . esc_html__( 'Stripe account connected successfully.', 'subscription-manager-for-stripe' ) . '</p></div>';
        }
        $oauth_error = get_transient( 'strp_sub_oauth_error_' . $user_id );
        if ( $oauth_error ) {
            delete_transient( 'strp_sub_oauth_error_' . $user_id );
            echo '<div class="notice notice-error is-dismissible"><p>' . esc_html( $oauth_error ) . '</p></div>';
        }
        $oauth_disconnected = get_transient( 'strp_sub_oauth_disconnected_' . $user_id );
        if ( $oauth_disconnected ) {
            delete_transient( 'strp_sub_oauth_disconnected_' . $user_id );
            echo '<div class="notice notice-info is-dismissible"><p>' . esc_html__( 'Stripe account disconnected.', 'subscription-manager-for-stripe' ) . '</p></div>';
        }
        ?>
        <div class="wrap">
            <h1><?php echo esc_html( get_admin_page_title() ); ?></h1>
            <?php $this->render_upgrade_banner(); ?>
            <form method="post" action="options.php">
                <?php
                settings_fields( 'strp_sub_settings_group' );
                do_settings_sections( 'strp-sub-settings' );
                submit_button();
                ?>
            </form>
        </div>
        <?php
    }

    /**
     * Sanitize and encrypt OAuth Client Secret before storage.
     * Ignores the '********' mask payload.
     */
    public function sanitize_oauth_client_secret( $input ) {
        if ( $input === '********' ) {
            return get_option( 'strp_sub_oauth_client_secret', '' );
        }
        $sanitized = sanitize_text_field( $input );
        if ( empty( $sanitized ) ) {
            return '';
        }
        return self::encrypt_secret( $sanitized );
    }

    /**
     * Retrieve the decrypted OAuth client secret.
     *
     * @return string Plaintext secret or empty string.
     */
    public static function get_oauth_client_secret() {
        if ( defined( 'STRP_SUB_OAUTH_CLIENT_SECRET' ) ) {
            return STRP_SUB_OAUTH_CLIENT_SECRET;
        }
        $stored = get_option( 'strp_sub_oauth_client_secret', '' );
        if ( empty( $stored ) ) {
            return '';
        }
        $decrypted = self::decrypt_secret( $stored );
        // Backward compatibility: if decryption fails, treat as plaintext and re-encrypt.
        if ( false === $decrypted ) {
            $decrypted = $stored;
            update_option( 'strp_sub_oauth_client_secret', self::encrypt_secret( $decrypted ) );
        }
        return $decrypted;
    }

    /**
     * Encrypt a secret value for storage at rest using AES-256-GCM.
     *
     * @param string $value Plaintext value.
     * @return string Base64-encoded ciphertext.
     */
    private static function encrypt_secret( $value ) {
        $key = hash( 'sha256', wp_salt( 'auth' ) . 'strp_sub_secret_enc', true );
        $iv  = openssl_random_pseudo_bytes( 12 );
        $tag = '';
        $ciphertext = openssl_encrypt( $value, 'aes-256-gcm', $key, OPENSSL_RAW_DATA, $iv, $tag, '', 16 );
        if ( false === $ciphertext ) {
            return $value;
        }
        return base64_encode( $iv . $tag . $ciphertext );
    }

    /**
     * Decrypt a secret value from storage.
     *
     * @param string $encrypted Base64-encoded ciphertext.
     * @return string|false Plaintext value or false on failure.
     */
    private static function decrypt_secret( $encrypted ) {
        $raw = base64_decode( $encrypted, true );
        if ( false === $raw || strlen( $raw ) < 29 ) {
            return false;
        }
        $key  = hash( 'sha256', wp_salt( 'auth' ) . 'strp_sub_secret_enc', true );
        $iv   = substr( $raw, 0, 12 );
        $tag  = substr( $raw, 12, 16 );
        $data = substr( $raw, 28 );
        return openssl_decrypt( $data, 'aes-256-gcm', $key, OPENSSL_RAW_DATA, $iv, $tag );
    }

    /**
     * Sanitize settings
     */
    public function sanitize_settings( $input ) {
        $sanitized = array();

        if ( isset( $input['test_mode'] ) ) {
            $sanitized['test_mode'] = 'yes';
        } else {
            $sanitized['test_mode'] = 'no';
        }

        if ( isset( $input['test_publishable_key'] ) ) {
            $sanitized['test_publishable_key'] = sanitize_text_field( $input['test_publishable_key'] );
        }

        if ( isset( $input['live_publishable_key'] ) ) {
            $sanitized['live_publishable_key'] = sanitize_text_field( $input['live_publishable_key'] );
        }

        // Secret keys are intentionally not persisted.
        // (The whitelist approach above already ensures they are never copied
        // into $sanitized -- no unset() is needed here.)

        $old_settings = get_option( self::OPTION_NAME, array() );

        if ( isset( $input['test_webhook_secret'] ) ) {
            if ( $input['test_webhook_secret'] !== '********' ) {
                $sanitized['test_webhook_secret'] = sanitize_text_field( $input['test_webhook_secret'] );
            } else {
                $sanitized['test_webhook_secret'] = isset( $old_settings['test_webhook_secret'] ) ? $old_settings['test_webhook_secret'] : '';
            }
        }

        if ( isset( $input['live_webhook_secret'] ) ) {
            if ( $input['live_webhook_secret'] !== '********' ) {
                $sanitized['live_webhook_secret'] = sanitize_text_field( $input['live_webhook_secret'] );
            } else {
                $sanitized['live_webhook_secret'] = isset( $old_settings['live_webhook_secret'] ) ? $old_settings['live_webhook_secret'] : '';
            }
        }

        if ( isset( $input['log_level'] ) ) {
            $valid_levels = array( 'error', 'warning', 'info', 'debug' );
            $sanitized['log_level'] = in_array( $input['log_level'], $valid_levels, true ) ? $input['log_level'] : 'info';
        }

        if ( isset( $input['trial_period_days'] ) ) {
            $sanitized['trial_period_days'] = max( 1, min( 365, intval( $input['trial_period_days'] ) ) );
        }

        if ( isset( $input['monthly_product_id'] ) ) {
            $sanitized['monthly_product_id'] = intval( $input['monthly_product_id'] );
        }

        if ( isset( $input['annual_product_id'] ) ) {
            $sanitized['annual_product_id'] = intval( $input['annual_product_id'] );
        }

        if ( isset( $input['lifetime_product_id'] ) ) {
            $sanitized['lifetime_product_id'] = intval( $input['lifetime_product_id'] );
        }

        $checkout_msg_keys = array(
            'checkout_msg_upgrade',
            'checkout_msg_trial',
            'checkout_msg_no_trial',
            'checkout_msg_onetime_upgrade',
            'checkout_msg_onetime_new',
        );
        foreach ( $checkout_msg_keys as $msg_key ) {
            if ( isset( $input[ $msg_key ] ) ) {
                $sanitized[ $msg_key ] = sanitize_textarea_field( $input[ $msg_key ] );
            }
        }

        if ( isset( $input['strp_sub_wipe_data'] ) ) {
            $sanitized['strp_sub_wipe_data'] = 'yes';
        } else {
            $sanitized['strp_sub_wipe_data'] = 'no';
        }

        if ( isset( $input['enable_automatic_tax'] ) ) {
            $sanitized['enable_automatic_tax'] = 'yes';
        } else {
            $sanitized['enable_automatic_tax'] = 'no';
        }

        // Note: strp_sub_oauth_client_id and strp_sub_oauth_client_secret are
        // registered as separate settings in the same settings group and are
        // saved automatically by WordPress -- no manual update_option() required.

        // Clean up any legacy secret-key values from older versions.
        $existing = get_option( self::OPTION_NAME, array() );
        if ( isset( $existing['test_secret_key'] ) || isset( $existing['live_secret_key'] ) ) {
            unset( $existing['test_secret_key'], $existing['live_secret_key'] );
            update_option( self::OPTION_NAME, $existing );
        }

        self::flush_cache();

        return $sanitized;
    }

    /**
     * Get a setting value
     */
    /** @var array|null Cached settings array to avoid repeated get_option() calls. */
    private static $cached_settings = null;

    public static function get( $key, $default = '' ) {
        if ( null === self::$cached_settings ) {
            self::$cached_settings = get_option( self::OPTION_NAME, array() );
        }
        return isset( self::$cached_settings[ $key ] ) ? self::$cached_settings[ $key ] : $default;
    }

    /**
     * Invalidate the settings cache (call after saving settings).
     */
    public static function flush_cache() {
        self::$cached_settings = null;
    }

    /**
     * Check if test mode is enabled
     */
    public static function is_test_mode() {
        return self::get( 'test_mode', 'yes' ) === 'yes';
    }

    /**
     * Get publishable key (test or live)
     */
    public static function get_publishable_key() {
        if ( self::is_test_mode() ) {
            return defined( 'STRP_SUB_TEST_PUBLISHABLE_KEY' ) ? STRP_SUB_TEST_PUBLISHABLE_KEY : self::get( 'test_publishable_key' );
        }
        return defined( 'STRP_SUB_LIVE_PUBLISHABLE_KEY' ) ? STRP_SUB_LIVE_PUBLISHABLE_KEY : self::get( 'live_publishable_key' );
    }

    /**
     * Resolve runtime Stripe API key. OAuth is required by default.
     */
    public static function get_runtime_api_key() {
        if ( class_exists( 'STRP_SUB_OAuth' ) && STRP_SUB_OAuth::is_connected() ) {
            return STRP_SUB_OAuth::get_access_token();
        }

        return '';
    }

    /**
     * Get secret key (test or live). Deprecated for runtime API calls.
     */
    public static function get_secret_key() {
        return '';
    }

    /**
     * Get webhook secret (test or live)
     */
    public static function get_webhook_secret() {
        if ( self::is_test_mode() ) {
            return defined( 'STRP_SUB_TEST_WEBHOOK_SECRET' ) ? STRP_SUB_TEST_WEBHOOK_SECRET : self::get( 'test_webhook_secret' );
        }
        return defined( 'STRP_SUB_LIVE_WEBHOOK_SECRET' ) ? STRP_SUB_LIVE_WEBHOOK_SECRET : self::get( 'live_webhook_secret' );
    }

    /**
     * Get the configured trial period in days (minimum 1, maximum 365).
     *
     * @return int
     */
    public static function get_trial_period_days() {
        return max( 1, (int) self::get( 'trial_period_days', 21 ) );
    }

    /**
     * Check if Stripe automatic tax is enabled.
     *
     * @return bool
     */
    public static function get_automatic_tax_enabled() {
        return self::get( 'enable_automatic_tax', 'yes' ) === 'yes';
    }

    /**
     * Get the checkout custom_text submit message for a given context.
     *
     * @param string $type One of: upgrade, trial, no_trial, onetime_upgrade, onetime_new.
     * @return string
     */
    public static function get_checkout_message( $type ) {
        $stored = self::get( 'checkout_msg_' . $type, '' );
        if ( ! empty( $stored ) ) {
            return $stored;
        }

        $trial_days = self::get_trial_period_days();
        $defaults   = array(
            'upgrade'         => __( 'Your current subscription will be cancelled and the new subscription will take effect immediately.', 'subscription-manager-for-stripe' ),
            'trial'           => sprintf(
                /* translators: %d: number of free trial days */
                __( 'You get a %d-day free trial. Your payment method is saved but will not be charged until after the trial ends.', 'subscription-manager-for-stripe' ),
                $trial_days
            ),
            'no_trial'        => __( 'Your subscription starts immediately and will be charged today. The trial period is only available to new customers.', 'subscription-manager-for-stripe' ),
            'onetime_upgrade' => __( 'Your current subscription will be cancelled and the Lifetime plan will take effect immediately.', 'subscription-manager-for-stripe' ),
            'onetime_new'     => __( 'You will get immediate access to the Lifetime plan. The trial period is only available on recurring subscriptions.', 'subscription-manager-for-stripe' ),
        );

        return isset( $defaults[ $type ] ) ? $defaults[ $type ] : '';
    }

    /**
     * Whether the upgrade banner should render for the current user.
     *
     * Gates on: Freemius loaded, user is not on a paid plan, user has not
     * dismissed the banner. Shared by the render and enqueue callbacks so
     * both stay in sync.
     *
     * @return bool
     */
    private function should_show_upgrade_banner() {
        if ( ! function_exists( 'strp_sub_fs' ) || ! strp_sub_fs() ) {
            return false;
        }
        if ( strp_sub_fs()->is_paying() ) {
            return false;
        }
        if ( get_user_meta( get_current_user_id(), 'strp_sub_upgrade_banner_dismissed', true ) ) {
            return false;
        }
        return true;
    }

    /**
     * Is the current admin request the plugin's settings page?
     *
     * @return bool
     */
    private function is_settings_page_request() {
        // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- admin page identity check, no state change.
        if ( ! isset( $_GET['page'] ) ) {
            return false;
        }
        // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- admin page identity check, no state change.
        $page = sanitize_text_field( wp_unslash( $_GET['page'] ) );
        return 'strp-sub-settings' === $page;
    }

    /**
     * Enqueue the upgrade-banner JS on the settings page for free users.
     *
     * Registers a static JS file and attaches ajaxUrl + nonce via
     * wp_add_inline_script (no inline <script> tags -- WP.org compliance).
     */
    public function enqueue_upgrade_banner_assets() {
        if ( ! $this->is_settings_page_request() ) {
            return;
        }
        if ( ! $this->should_show_upgrade_banner() ) {
            return;
        }

        wp_enqueue_script(
            'strp-sub-admin-upgrade-banner',
            STRP_SUB_PLUGIN_URL . 'assets/js/admin-upgrade-banner.js',
            array(),
            STRP_SUB_VERSION,
            true
        );

        $data = array(
            'ajaxUrl' => admin_url( 'admin-ajax.php' ),
            'nonce'   => wp_create_nonce( 'strp_sub_dismiss_upgrade_banner' ),
        );

        wp_add_inline_script(
            'strp-sub-admin-upgrade-banner',
            'var strpSubUpgradeBanner = ' . wp_json_encode( $data ) . ';',
            'before'
        );
    }

    /**
     * Render the upgrade banner for free-plan users on the settings page.
     * Dismissible per-user via AJAX + user meta. The dismiss handler lives in
     * assets/js/admin-upgrade-banner.js, enqueued by enqueue_upgrade_banner_assets().
     */
    public function render_upgrade_banner() {
        if ( ! $this->should_show_upgrade_banner() ) {
            return;
        }

        $pricing_url = '';
        if ( method_exists( strp_sub_fs(), 'get_upgrade_url' ) ) {
            $pricing_url = strp_sub_fs()->get_upgrade_url();
        }
        if ( empty( $pricing_url ) ) {
            $pricing_url = strp_sub_fs()->pricing_url();
        }
        ?>
        <div id="strp-sub-upgrade-banner" style="background:#f0f6ff;border:1px solid #c3d9f7;border-radius:6px;padding:20px 24px;margin:20px 0 16px;position:relative;">
            <button type="button" id="strp-sub-dismiss-banner" style="position:absolute;top:8px;right:12px;background:none;border:none;font-size:18px;cursor:pointer;color:#666;line-height:1;" aria-label="<?php esc_attr_e( 'Dismiss', 'subscription-manager-for-stripe' ); ?>">&times;</button>
            <h3 style="margin:0 0 8px;font-size:15px;color:#1d2327;">
                <?php esc_html_e( 'You\'re on the free plan', 'subscription-manager-for-stripe' ); ?>
            </h3>
            <p style="margin:0 0 12px;color:#50575e;font-size:13px;line-height:1.5;max-width:640px;">
                <?php esc_html_e( 'Right now you get checkout, webhooks, and WooCommerce sync. Upgrading adds a revenue dashboard, email templates you can actually customize, a cancellation flow that tries to save churning subscribers, and webhook health monitoring so nothing breaks silently. Starts at $149/yr.', 'subscription-manager-for-stripe' ); ?>
            </p>
            <?php if ( $pricing_url ) : ?>
                <a href="<?php echo esc_url( $pricing_url ); ?>" style="display:inline-block;background:#2271b1;color:#fff;text-decoration:none;padding:7px 16px;border-radius:4px;font-size:13px;font-weight:500;">
                    <?php esc_html_e( 'See plans', 'subscription-manager-for-stripe' ); ?>
                </a>
            <?php endif; ?>
        </div>
        <?php
    }

    /**
     * AJAX handler: dismiss upgrade banner for the current user.
     */
    public function ajax_dismiss_upgrade_banner() {
        check_ajax_referer( 'strp_sub_dismiss_upgrade_banner' );

        if ( ! current_user_can( 'manage_options' ) ) {
            wp_send_json_error();
        }

        update_user_meta( get_current_user_id(), 'strp_sub_upgrade_banner_dismissed', 1 );
        wp_send_json_success();
    }
}
