<?php

namespace GriffinForms\Includes\Integrations\Stripe;

use GriffinForms\Settings;

/**
 * Stripe Payment Integration
 *
 * Handles configuration and management of Stripe payment processing
 * for forms including one-time payments, subscriptions, and webhook handling.
 *
 * @since 1.0.0
 */
class Main extends \GriffinForms\Includes\Integrations\Format
{
    /**
     * Set integration metadata key prefix
     */
    protected function setMeta()
    {
        $this->meta         = 'stripe';
        $this->id           = 'stripe';
        $this->option_group = 'payments';
    }

    /**
     * Build integration metadata/info
     *
     * @return array Integration metadata
     */
    protected function buildInfo(): array
    {
        return [
            'id'       => 'stripe',
            'name'     => 'Stripe',
            'category' => 'Payments',
        ];
    }

    /**
     * Get current integration status
     *
     * @return array Status array
     */
    public function getStatus(): array
    {
        return [
            'configured' => $this->isConfigured(),
            'active'     => $this->isConfigured(),
            'message'    => $this->isConfigured() ? 'Configured' : 'Not configured',
        ];
    }

    /**
     * Get configuration form fields
     *
     * @return array Form field definitions
     */
    public function getConfigFields(): array
    {
        return [
            ['name' => 'stripe_publishable_key', 'label' => 'Publishable Key', 'type' => 'text', 'required' => true],
            ['name' => 'stripe_secret_key', 'label' => 'Secret Key', 'type' => 'password', 'required' => true],
            // Webhook secret intentionally hidden/deferred; not currently used.
        ];
    }

    /**
     * Validate Stripe connection
     *
     * Makes a test API call to Stripe's servers to verify the secret key is valid.
     *
     * @return array ['success' => bool, 'message' => string]
     */
    protected function validateConnection(): array
    {
        $secret_key = $this->getOption('secret_key');
        return $this->validateWithStripe($secret_key);
    }

    /**
     * Validate Stripe keys with Stripe's API
     *
     * Makes a test verification request to Stripe's API
     * to ensure the secret key is valid.
     *
     * @param string $secret_key The Stripe secret key
     * @return array ['success' => bool, 'message' => string]
     */
    private function validateWithStripe(string $secret_key): array
    {
        // Check if Stripe PHP SDK is available
        $form_id = $this->resolveFormContextId();

        if (!class_exists('\Stripe\StripeClient')) {
            $message = 'Stripe PHP SDK is not installed. Please install it via Composer.';
            $this->log->add('error', 'form', $form_id, get_current_user_id(), $message, 'Integration (stripe)');
            return [
                'success' => false,
                'message' => $message,
            ];
        }

        try {
            // Initialize Stripe client with the secret key
            $stripe = new \Stripe\StripeClient($secret_key);

            // Make a test API call to retrieve account information
            $account = $stripe->accounts->retrieve();

            if (!empty($account->id)) {
                $message = 'Stripe connection test successful - Account ID: ' . $account->id;
                $this->log->add('success', 'form', $form_id, get_current_user_id(), $message, 'Integration (stripe)');
                return [
                    'success' => true,
                    'message' => 'Stripe is properly configured and working correctly.',
                ];
            }

            $message = 'Stripe API returned empty account information.';
            $this->log->add('error', 'form', $form_id, get_current_user_id(), $message, 'Integration (stripe)');
            return [
                'success' => false,
                'message' => 'Unable to retrieve account information from Stripe.',
            ];
        } catch (\Stripe\Exception\AuthenticationException $e) {
            $message = 'Stripe authentication failed - Invalid secret key.';
            $this->log->add('error', 'form', $form_id, get_current_user_id(), $message, 'Integration (stripe)');
            return [
                'success' => false,
                'message' => 'Invalid Stripe secret key. Please verify your secret key is correct.',
            ];
        } catch (\Stripe\Exception\ApiErrorException $e) {
            $message = 'Stripe API error during connection test: ' . $e->getMessage();
            $this->log->add('error', 'form', $form_id, get_current_user_id(), $message, 'Integration (stripe)');
            return [
                'success' => false,
                'message' => 'Stripe API error: ' . $e->getMessage(),
            ];
        } catch (\Exception $e) {
            $message = 'Stripe connection error: ' . $e->getMessage();
            $this->log->add('error', 'form', $form_id, get_current_user_id(), $message, 'Integration (stripe)');
            return [
                'success' => false,
                'message' => 'Error connecting to Stripe: ' . $e->getMessage(),
            ];
        }
    }

    /**
     * Check if external library is installed
     *
     * @return bool True if Stripe PHP SDK is installed
     */
    public function isLibraryInstalled(): bool
    {
        return class_exists('\Stripe\StripeClient');
    }

    /**
     * Get library installation instructions
     *
     * @return string Installation guide HTML
     */
    public function getLibraryInstructions(): string
    {
        return 'Install Stripe PHP SDK via Composer: <code>composer require stripe/stripe-php</code>';
    }

    /**
     * Check if Stripe is fully configured
     *
     * Configured means all required keys are set:
     * - Publishable key is set
     * - Secret key is set
     * Webhook secret is optional for basic functionality.
     *
     * @return bool True if fully configured
     */
    public function isConfigured(): bool
    {
        $publishable_key = $this->settings->getOption('stripe_publishable_key');
        $secret_key = $this->settings->getOption('stripe_secret_key');

        return !empty($publishable_key) && !empty($secret_key);
    }

    /**
     * Get configuration form HTML
     *
     * Returns HTML markup for the Stripe configuration form
     * to be displayed in the integrations modal.
     *
     * @return string HTML form markup
     */
    public function getConfigurationFormHtml(): string
    {
        $publishable_key = $this->getOption('publishable_key', '');
        $secret_key = $this->getOption('secret_key', '');
        $frontend_label = $this->getOption('frontend_label', '');
        $frontend_description = $this->getOption('frontend_description', '');
        $hide_logo = (bool) $this->settings->getOption('stripe_frontend_hide_logo', false);

        // Import form control factory
        $factory = new \GriffinForms\Includes\Integrations\FormControls\Factory();

        // Build form fields with factory
        $fields_html = '';

        $fields_html .= $factory->create(
            'text',
            'stripe_publishable_key',
            $publishable_key,
            'stripe',
            [
                'label' => __('Publishable Key', 'griffinforms-form-builder'),
                'type' => 'text',
                'required' => true,
                'description' => __('Get your Publishable Key from your Stripe Dashboard', 'griffinforms-form-builder'),
            ]
        )->render();

        $fields_html .= $factory->create(
            'password',
            'stripe_secret_key',
            $secret_key,
            'stripe',
            [
                'label' => __('Secret Key', 'griffinforms-form-builder'),
                'type' => 'password',
                'required' => true,
                'description' => __('Keep this secret key private and never share it publicly', 'griffinforms-form-builder'),
            ]
        )->render();

        $fields_html .= $factory->create(
            'text',
            'stripe_frontend_label',
            $frontend_label,
            'stripe',
            [
                'label' => __('Frontend Label', 'griffinforms-form-builder'),
                'type' => 'text',
                'required' => false,
                'description' => __('Optional: Overrides the label shown to users (defaults to "Stripe").', 'griffinforms-form-builder'),
            ]
        )->render();

        $fields_html .= $factory->create(
            'textarea',
            'stripe_frontend_description',
            $frontend_description,
            'stripe',
            [
                'label' => __('Frontend Description', 'griffinforms-form-builder'),
                'required' => false,
                'description' => __('Optional: Custom description shown under the label on the payment selector.', 'griffinforms-form-builder'),
            ]
        )->render();

        $fields_html .= $factory->create(
            'checkbox',
            'stripe_frontend_hide_logo',
            $hide_logo ? '1' : '',
            'stripe',
            [
                'label' => __('Hide Provider Logo', 'griffinforms-form-builder'),
                'description' => __('Enable to hide the Stripe logo on the payment selector.', 'griffinforms-form-builder'),
            ]
        )->render();

        // Use base template
        return $this->renderConfigurationFormTemplate('gf-stripe-config-form', 'stripe', $fields_html);
    }

    /**
     * Schema for per-form customer field mappings.
     */
    public function getFormSettingsSchema(): array
    {
        $field_options = $this->getFormFieldOptionsForMapping();
        $placeholder = __('Select a form field', 'griffinforms-form-builder');
        $schema = [
            [
                'name'    => '__gf_form_settings_mode',
                'type'    => 'hidden',
                'default' => 'custom',
            ],
        ];

        foreach ($this->getCustomerMappingFields() as $key => $label) {
            $schema[] = [
                'name'        => $key,
                'type'        => 'select',
                'label'       => $label,
                'options'     => $field_options,
                'placeholder' => $placeholder,
                'description' => $this->getCustomerFieldDescription($key),
                'default'     => '',
            ];
        }

        return $schema;
    }

    /**
     * Default per-form settings for Stripe.
     */
    public function getDefaultFormSettings(): array
    {
        return array_fill_keys(array_keys($this->getCustomerMappingFields()), '');
    }

    /**
     * Sanitize per-form settings.
     *
     * @param array $settings
     * @return array
     */
    public function validateFormSettings(array $settings)
    {
        $definitions = $this->getCustomerMappingFields();
        $options = $this->getFormFieldOptionsForMapping();
        $valid_ids = array_map('strval', array_keys($options));
        $form_id = $this->resolveFormContextId();

        $sanitized = [];
        foreach ($definitions as $key => $label) {
            $value = isset($settings[$key]) ? trim((string) $settings[$key]) : '';
            if ($value !== '') {
                if (!ctype_digit($value)) {
                    $value = preg_replace('/[^0-9]/', '', $value);
                }
                $value = $value === '' ? '' : (string) absint($value);

                if ($value !== '' && !in_array($value, $valid_ids, true)) {
                    $this->log->add(
                        'notice',
                        'form',
                        $form_id,
                        get_current_user_id(),
                        sprintf(
                            'Stripe customer mapping for "%s" references an unknown or unsupported field ID (%s).',
                            $label,
                            $value
                        ),
                        'Integration (stripe)'
                    );
                    $value = '';
                }
            }
            $sanitized[$key] = $value;
        }

        return $sanitized;
    }

    /**
     * Get configuration JavaScript
     *
     * Returns JavaScript code for form handling and validation
     *
     * @return string JavaScript code
     */
    public function getConfigurationJs(): string
    {
        $js = "
        /**
         * Stripe Configuration Handler
         */
        (function() {
            const form = document.getElementById('gf-stripe-config-form');
            if (!form) return;

            const cancelBtn = form.querySelector('.gf-integration-btn-cancel');

            // Cancel button handler - goes back to info view
            if (cancelBtn) {
                cancelBtn.addEventListener('click', function(e) {
                    e.preventDefault();
                    window.loadIntegrationInfo('stripe');
                });
            }

            // Form submission handler
            form.addEventListener('submit', function(e) {
                e.preventDefault();

                const formId = window.griffinformsResolveActiveFormId ? window.griffinformsResolveActiveFormId() : null;
                // Validate required fields
                const publishableKey = form.querySelector('#gf-stripe-stripe_publishable_key').value.trim();
                const secretKey = form.querySelector('#gf-stripe-stripe_secret_key').value.trim();

                if (!publishableKey || !secretKey) {
                    window.showIntegrationsMessage('danger', 'Please fill in all required fields');
                    return;
                }

                // Get optional fields
                const frontendLabelField = form.querySelector('#gf-stripe-stripe_frontend_label');
                const frontendDescriptionField = form.querySelector('#gf-stripe-stripe_frontend_description');
                const frontendLabel = frontendLabelField ? frontendLabelField.value.trim() : '';
                const frontendDescription = frontendDescriptionField ? frontendDescriptionField.value.trim() : '';
                const hideLogoField = form.querySelector('#gf-stripe-stripe_frontend_hide_logo');
                const frontendHideLogo = hideLogoField ? hideLogoField.checked : false;

                // Collect form data
                const data = {
                    action: 'saveIntegrationConfiguration',
                    integration_id: 'stripe',
                    nonce: window.griffinformsIntegrationsNonce || '',
                    form_id: formId || '',
                    stripe_publishable_key: publishableKey,
                    stripe_secret_key: secretKey,
                    stripe_frontend_label: frontendLabel,
                    stripe_frontend_description: frontendDescription,
                    stripe_frontend_hide_logo: frontendHideLogo ? 1 : 0
                };

                // Send AJAX request
                jQuery.ajax({
                    url: ajaxurl,
                    type: 'POST',
                    data: data,
                    success: function(response) {
                        if (response.success) {
                            window.showIntegrationsMessage('success', 'Stripe configuration saved successfully');
                            setTimeout(() => {
                                window.loadIntegrationInfo('stripe');
                            }, 1000);
                        } else {
                            const message = (response.data && response.data.msg) ? response.data.msg : 'Failed to save configuration';
                            window.showIntegrationsMessage('danger', message);
                        }
                    },
                    error: function(xhr, status, error) {
                        console.error('Stripe configuration error:', error);
                        window.showIntegrationsMessage('danger', 'Error saving Stripe configuration');
                    }
                });
            });
        })();
        ";

        return $js;
    }

    /**
     * Save configuration
     *
     * Saves Stripe configuration to WordPress options.
     * Publishable and secret keys are required.
     * Webhook secret is optional.
     *
     * @param array $config Configuration data
     * @return bool True if saved successfully
     */
    protected function saveConfiguration(array $config): bool
    {
        try {
            $publishable_key = isset($config['stripe_publishable_key']) ? sanitize_text_field($config['stripe_publishable_key']) : '';
            $secret_key = isset($config['stripe_secret_key']) ? sanitize_text_field($config['stripe_secret_key']) : '';
            // Webhook secret deferred (not used yet)
            $frontend_label = isset($config['stripe_frontend_label']) ? sanitize_text_field($config['stripe_frontend_label']) : '';
            $frontend_description = isset($config['stripe_frontend_description']) ? sanitize_textarea_field($config['stripe_frontend_description']) : '';
            $frontend_hide_logo = !empty($config['stripe_frontend_hide_logo']);

            // Validate all required fields
            if (empty($publishable_key) || empty($secret_key)) {
                return false;
            }

            // Basic length validation only (allow test/dummy keys)
            if (!$this->isValidStripeKey($publishable_key, 'pk_')) {
                $this->log->add(
                    'notice',
                    'integration',
                    0,
                    get_current_user_id(),
                    'Stripe publishable key saved without standard prefix.',
                    'stripe_config'
                );
            }
            if (!$this->isValidStripeKey($secret_key, 'sk_')) {
                $this->log->add(
                    'notice',
                    'integration',
                    0,
                    get_current_user_id(),
                    'Stripe secret key saved without standard prefix.',
                    'stripe_config'
                );
            }

            // Save all required options
            $this->settings->updateOption('stripe_publishable_key', $publishable_key, 'payments');
            $this->settings->updateOption('stripe_secret_key', $secret_key, 'payments');

            $this->settings->updateOption('stripe_frontend_label', $frontend_label, 'payments');
            $this->settings->updateOption('stripe_frontend_description', $frontend_description, 'payments');
            $this->settings->updateOption('stripe_frontend_hide_logo', $frontend_hide_logo ? '1' : '0', 'payments');

            return true;
        } catch (\Exception $e) {
            $message = 'Failed to save Stripe configuration: ' . $e->getMessage();
            $this->log->add('error', 'integration', 0, get_current_user_id(), $message, 'stripe_config');
            return false;
        }
    }

    /**
     * Validate Stripe key format
     *
     * @param string $key The key to validate
     * @param string $prefix Expected prefix (pk_ or sk_)
     * @return bool True if key format is valid
     */
    private function isValidStripeKey(string $key, string $prefix): bool
    {
        // Allow arbitrary strings (use prefix only for guidance). Ensure non-empty length.
        return strlen(trim($key)) > 5;
    }

    /**
     * Custom disable logic for Stripe
     *
     * Clears the Stripe configuration and ensures integration is marked as disabled.
     *
     * @return void
     */
    protected function onDisable()
    {
        // No additional cleanup needed beyond clearAllOptions()
    }

    /**
     * Field labels used for customer attribute mapping.
     */
    protected function getCustomerMappingFields(): array
    {
        return [
            'customer_name_field'           => __('Customer Name Field', 'griffinforms-form-builder'),
            'customer_email_field'          => __('Customer Email Field', 'griffinforms-form-builder'),
            'customer_phone_field'          => __('Customer Phone Field', 'griffinforms-form-builder'),
            'billing_address_line1_field'   => __('Billing Address Line 1 Field', 'griffinforms-form-builder'),
            'billing_address_line2_field'   => __('Billing Address Line 2 Field', 'griffinforms-form-builder'),
            'billing_city_field'            => __('Billing City Field', 'griffinforms-form-builder'),
            'billing_state_field'           => __('Billing State / Region Field', 'griffinforms-form-builder'),
            'billing_postal_code_field'     => __('Billing Postal Code Field', 'griffinforms-form-builder'),
            'billing_country_field'         => __('Billing Country Field', 'griffinforms-form-builder'),
            'tax_id_field'                  => __('Tax or VAT ID Field', 'griffinforms-form-builder'),
        ];
    }

    /**
     * Descriptions for customer mapping fields.
     */
    protected function getCustomerFieldDescription(string $key): string
    {
        $descriptions = [
            'customer_name_field'         => __('Recommended. Used on invoices, receipts, and for SCA compliance.', 'griffinforms-form-builder'),
            'customer_email_field'        => __('Required for email receipts and many regional compliance checks.', 'griffinforms-form-builder'),
            'customer_phone_field'        => __('Optional but useful when Stripe requires phone verification.', 'griffinforms-form-builder'),
            'billing_address_line1_field' => __('Map to either a full address field (preferred) or a single-line text field. When an address field is selected we automatically grab its street line.', 'griffinforms-form-builder'),
            'billing_address_line2_field' => __('Optional second address line.', 'griffinforms-form-builder'),
            'billing_city_field'          => __('Map to a city input or select your compound address field for auto detection.', 'griffinforms-form-builder'),
            'billing_state_field'         => __('State, province, or region field. Works with either individual text/select inputs or the address field type.', 'griffinforms-form-builder'),
            'billing_postal_code_field'   => __('Postal or ZIP code. Works with individual fields or the compound address field.', 'griffinforms-form-builder'),
            'billing_country_field'       => __('Two-letter country selection improves tax and compliance checks. Map to the address field to auto-detect or to a dedicated select.', 'griffinforms-form-builder'),
            'tax_id_field'                => __('Optional. Map to VAT/GST/Tax ID fields when collecting business payments.', 'griffinforms-form-builder'),
        ];

        return $descriptions[$key] ?? '';
    }

    protected function isAddressField(string $field_id): bool
    {
        if (!is_array($this->form_field_meta_cache)) {
            $this->getFormFieldOptionsForMapping();
        }

        $type = $this->form_field_meta_cache[$field_id]['type'] ?? '';
        return $type === 'address';
    }
}
