/**
 * Simplyin HyvaPayment - 3D Secure Handler Utility
 * Handles 3D Secure authentication flows for credit card payments
 * 
 * Requirements: 11.1, 11.2, 11.3, 11.4, 11.5, 11.6, 11.7, 11.8
 * 
 * Usage:
 * // Initialize the handler
 * ThreeDSecureHandler.init({
 *     returnUrl: 'https://store.com/checkout/success',
 *     iframeContainerId: '3ds-iframe-container'
 * });
 * 
 * // Set up callbacks
 * ThreeDSecureHandler.onComplete((result) => console.log('3DS completed', result));
 * ThreeDSecureHandler.onCancel(() => console.log('3DS cancelled'));
 * ThreeDSecureHandler.onError((error) => console.error('3DS error', error));
 * 
 * // Handle 3DS redirect
 * ThreeDSecureHandler.handleRedirect({
 *     redirectUrl: 'https://3ds-provider.com/auth',
 *     method: 'iframe' // or 'redirect'
 * });
 */

'use strict';

/**
 * ThreeDSecureHandler Utility
 * Manages 3D Secure authentication flows for credit card payments
 * Supports both iframe-based and full redirect methods
 * 
 * Validates: Requirements 11.1, 11.2, 11.3, 11.4, 11.5, 11.6, 11.7, 11.8
 */
const ThreeDSecureHandler = {
    // ==========================================
    // Configuration Properties
    // ==========================================
    
    /**
     * Configuration object
     * @type {Object}
     */
    config: {
        returnUrl: '',
        iframeContainerId: '3ds-iframe-container',
        modalContainerId: '3ds-modal-container',
        timeout: 120000 // 2 minutes timeout
    },
    
    /**
     * Whether the handler has been initialized
     * @type {boolean}
     */
    isInitialized: false,
    
    /**
     * Current 3DS session data
     * @type {Object|null}
     */
    currentSession: null,
    
    /**
     * Modal element reference
     * @type {HTMLElement|null}
     */
    modalElement: null,
    
    /**
     * Iframe element reference
     * @type {HTMLIFrameElement|null}
     */
    iframeElement: null,
    
    /**
     * Timeout timer reference
     * @type {number|null}
     */
    timeoutTimer: null,
    
    /**
     * PostMessage listener reference
     * @type {Function|null}
     */
    messageListener: null,
    
    // ==========================================
    // Callback Properties
    // ==========================================
    
    /**
     * Callbacks for 3DS events
     * @type {Object}
     */
    callbacks: {
        onComplete: null,
        onCancel: null,
        onError: null
    },
    
    // ==========================================
    // Initialization Methods
    // ==========================================
    
    /**
     * Initialize the 3D Secure handler
     * 
     * @param {Object} config - Configuration options
     * @param {string} config.returnUrl - The URL to return to after 3DS completion
     * @param {string} [config.iframeContainerId] - Container ID for iframe display
     * @param {string} [config.modalContainerId] - Container ID for modal display
     * @param {number} [config.timeout] - Timeout in milliseconds (default: 120000)
     * @returns {boolean} True if initialization was successful
     */
    init(config) {
        if (!config || !config.returnUrl) {
            console.error('[Simplyin 3DSHandler] Return URL is required');
            return false;
        }
        
        this.config = {
            ...this.config,
            ...config
        };
        
        // Set up postMessage listener
        this._setupMessageListener();
        
        this.isInitialized = true;
        console.log('[Simplyin 3DSHandler] Initialized successfully');
        
        return true;
    },
    
    /**
     * Set up the postMessage event listener
     * Validates: Requirement 11.8 (listen for postMessage events from 3DS iframe)
     * 
     * @private
     */
    _setupMessageListener() {
        // Remove existing listener if any
        if (this.messageListener) {
            window.removeEventListener('message', this.messageListener);
        }
        
        this.messageListener = (event) => {
            this.handlePostMessage(event);
        };
        
        window.addEventListener('message', this.messageListener);
    },
    
    // ==========================================
    // Redirect Handling Methods
    // ==========================================
    
    /**
     * Handle 3DS redirect based on the method specified
     * Validates: Requirements 11.1, 11.2 (determine iframe or full-page redirect)
     * 
     * @param {Object} response - The 3DS response from payment API
     * @param {string} response.redirectUrl - The 3DS authentication URL
     * @param {string} response.method - The redirect method ('iframe' or 'redirect')
     * @param {string} [response.paymentId] - The payment ID for tracking
     * @returns {boolean} True if redirect was initiated successfully
     */
    handleRedirect(response) {
        if (!this.isInitialized) {
            console.error('[Simplyin 3DSHandler] Handler not initialized. Call init() first.');
            return false;
        }
        
        if (!response || !response.redirectUrl) {
            console.error('[Simplyin 3DSHandler] Redirect URL is required');
            this._triggerError(new Error('3D Secure redirect URL is missing'));
            return false;
        }
        
        // Store session data before redirect
        // Validates: Requirement 11.4 (store payment session data before redirect)
        this._storeSessionData(response);
        
        const method = response.method || 'redirect';
        
        console.log(`[Simplyin 3DSHandler] Handling redirect with method: ${method}`);
        
        if (method === 'iframe') {
            return this.showIframeModal(response.redirectUrl);
        } else {
            return this.performFullRedirect(response.redirectUrl);
        }
    },
    
    /**
     * Store payment session data before redirect
     * Validates: Requirement 11.4 (store payment session data before redirect)
     * 
     * @private
     * @param {Object} response - The 3DS response data
     */
    _storeSessionData(response) {
        this.currentSession = {
            paymentId: response.paymentId || null,
            redirectUrl: response.redirectUrl,
            method: response.method || 'redirect',
            returnUrl: this.config.returnUrl,
            timestamp: Date.now()
        };
        
        // Store in session storage for recovery after redirect
        if (typeof window !== 'undefined' && window.SessionStorage) {
            window.SessionStorage.set3DSData({
                paymentId: this.currentSession.paymentId,
                redirectUrl: this.currentSession.redirectUrl,
                allowIframe: this.currentSession.method === 'iframe',
                returnUrl: this.currentSession.returnUrl
            });
        } else {
            // Fallback to native sessionStorage
            try {
                sessionStorage.setItem('simplyin_3ds_data', JSON.stringify(this.currentSession));
            } catch (error) {
                console.warn('[Simplyin 3DSHandler] Failed to store session data:', error);
            }
        }
        
        console.log('[Simplyin 3DSHandler] Session data stored');
    },
    
    // ==========================================
    // Iframe Modal Methods
    // Validates: Requirement 11.1
    // ==========================================
    
    /**
     * Display the 3D Secure page in a modal iframe
     * Validates: Requirement 11.1 (display 3DS page in modal iframe)
     * 
     * @param {string} url - The 3DS authentication URL
     * @returns {boolean} True if modal was displayed successfully
     */
    showIframeModal(url) {
        if (!url) {
            console.error('[Simplyin 3DSHandler] URL is required for iframe modal');
            return false;
        }
        
        try {
            // Create modal if it doesn't exist
            this._createModal();
            
            // Create and configure iframe
            this._createIframe(url);
            
            // Show the modal
            this._showModal();
            
            // Start timeout timer
            this._startTimeout();
            
            console.log('[Simplyin 3DSHandler] Iframe modal displayed');
            return true;
        } catch (error) {
            console.error('[Simplyin 3DSHandler] Failed to show iframe modal:', error);
            this._triggerError(error);
            return false;
        }
    },
    
    /**
     * Create the modal container element
     * Validates: Requirement 11.8 (modal with close button)
     * 
     * @private
     */
    _createModal() {
        // Check if modal already exists
        let modal = document.getElementById(this.config.modalContainerId);
        
        if (!modal) {
            modal = document.createElement('div');
            modal.id = this.config.modalContainerId;
            document.body.appendChild(modal);
        }
        
        // Set modal HTML with Tailwind CSS classes
        modal.innerHTML = `
            <div class="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50" 
                 id="3ds-modal-backdrop">
                <div class="relative bg-white rounded-lg shadow-xl w-full max-w-lg mx-4 overflow-hidden">
                    <!-- Modal Header with Close Button -->
                    <div class="flex items-center justify-between p-4 border-b border-gray-200">
                        <h3 class="text-lg font-semibold text-gray-900">
                            Payment Verification
                        </h3>
                        <button type="button" 
                                id="3ds-close-button"
                                class="text-gray-400 hover:text-gray-600 focus:outline-none focus:ring-2 focus:ring-green-500 rounded-lg p-1"
                                aria-label="Close">
                            <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
                            </svg>
                        </button>
                    </div>
                    
                    <!-- Iframe Container -->
                    <div id="${this.config.iframeContainerId}" 
                         class="w-full bg-gray-50" 
                         style="height: 450px;">
                        <!-- Loading indicator -->
                        <div id="3ds-loading" class="flex items-center justify-center h-full">
                            <div class="text-center">
                                <svg class="animate-spin h-10 w-10 text-green-600 mx-auto mb-4" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
                                    <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
                                    <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
                                </svg>
                                <p class="text-gray-600">Loading payment verification...</p>
                            </div>
                        </div>
                    </div>
                    
                    <!-- Modal Footer -->
                    <div class="p-4 border-t border-gray-200 bg-gray-50">
                        <p class="text-sm text-gray-500 text-center">
                            Please complete the verification in the window above.
                        </p>
                    </div>
                </div>
            </div>
        `;
        
        // Set up close button handler
        const closeButton = modal.querySelector('#3ds-close-button');
        if (closeButton) {
            closeButton.addEventListener('click', () => {
                this._handleCancel();
            });
        }
        
        // Set up backdrop click handler
        const backdrop = modal.querySelector('#3ds-modal-backdrop');
        if (backdrop) {
            backdrop.addEventListener('click', (event) => {
                if (event.target === backdrop) {
                    this._handleCancel();
                }
            });
        }
        
        this.modalElement = modal;
    },
    
    /**
     * Create the iframe element
     * 
     * @private
     * @param {string} url - The 3DS URL to load
     */
    _createIframe(url) {
        const container = document.getElementById(this.config.iframeContainerId);
        
        if (!container) {
            throw new Error('Iframe container not found');
        }
        
        // Create iframe
        const iframe = document.createElement('iframe');
        iframe.id = '3ds-iframe';
        iframe.src = url;
        iframe.className = 'w-full h-full border-0';
        iframe.setAttribute('sandbox', 'allow-forms allow-scripts allow-same-origin allow-top-navigation');
        iframe.setAttribute('allow', 'payment');
        
        // Handle iframe load
        iframe.onload = () => {
            // Hide loading indicator
            const loading = document.getElementById('3ds-loading');
            if (loading) {
                loading.style.display = 'none';
            }
            console.log('[Simplyin 3DSHandler] Iframe loaded');
        };
        
        // Handle iframe error
        iframe.onerror = () => {
            console.error('[Simplyin 3DSHandler] Iframe failed to load');
            this._triggerError(new Error('Failed to load 3D Secure verification page'));
        };
        
        // Clear container and add iframe
        const loading = container.querySelector('#3ds-loading');
        if (loading) {
            container.insertBefore(iframe, loading);
        } else {
            container.innerHTML = '';
            container.appendChild(iframe);
        }
        
        this.iframeElement = iframe;
    },
    
    /**
     * Show the modal
     * 
     * @private
     */
    _showModal() {
        if (this.modalElement) {
            this.modalElement.style.display = 'block';
            document.body.style.overflow = 'hidden'; // Prevent background scrolling
        }
    },
    
    /**
     * Hide the modal
     * 
     * @private
     */
    _hideModal() {
        if (this.modalElement) {
            this.modalElement.style.display = 'none';
            document.body.style.overflow = ''; // Restore scrolling
        }
        
        // Clear timeout
        this._clearTimeout();
    },
    
    /**
     * Close and clean up the modal
     */
    closeModal() {
        this._hideModal();
        
        // Remove iframe
        if (this.iframeElement) {
            this.iframeElement.remove();
            this.iframeElement = null;
        }
        
        // Clear modal content
        if (this.modalElement) {
            this.modalElement.innerHTML = '';
        }
        
        console.log('[Simplyin 3DSHandler] Modal closed');
    },
    
    // ==========================================
    // Full Redirect Methods
    // Validates: Requirement 11.2
    // ==========================================
    
    /**
     * Perform a full-page redirect to the 3DS URL
     * Validates: Requirement 11.2 (perform full-page redirect when iframe not allowed)
     * 
     * @param {string} url - The 3DS authentication URL
     * @returns {boolean} True if redirect was initiated
     */
    performFullRedirect(url) {
        if (!url) {
            console.error('[Simplyin 3DSHandler] URL is required for redirect');
            return false;
        }
        
        console.log('[Simplyin 3DSHandler] Performing full redirect to:', url);
        
        // Session data should already be stored by handleRedirect
        // Perform the redirect
        window.location.href = url;
        
        return true;
    },
    
    // ==========================================
    // PostMessage Handling
    // Validates: Requirement 11.8
    // ==========================================
    
    /**
     * Handle postMessage events from the 3DS iframe
     * Validates: Requirement 11.8 (listen for postMessage events from 3DS iframe)
     * 
     * @param {MessageEvent} event - The message event
     */
    handlePostMessage(event) {
        // Validate origin if possible
        // Note: In production, you should validate the origin against known 3DS provider domains
        
        let data;
        try {
            // Handle both string and object data
            data = typeof event.data === 'string' ? JSON.parse(event.data) : event.data;
        } catch (error) {
            // Not a JSON message, ignore
            return;
        }
        
        // Check if this is a 3DS-related message
        if (!data || !data.type) {
            return;
        }
        
        console.log('[Simplyin 3DSHandler] Received postMessage:', data.type);
        
        switch (data.type) {
            case '3ds_complete':
            case '3DS_COMPLETE':
            case 'PAYMENT_COMPLETE':
                this._handleComplete(data);
                break;
                
            case '3ds_cancel':
            case '3DS_CANCEL':
            case 'PAYMENT_CANCEL':
                this._handleCancel();
                break;
                
            case '3ds_error':
            case '3DS_ERROR':
            case 'PAYMENT_ERROR':
                this._handleError(data);
                break;
                
            case '3ds_resize':
            case '3DS_RESIZE':
                this._handleResize(data);
                break;
                
            default:
                // Unknown message type, log for debugging
                console.log('[Simplyin 3DSHandler] Unknown message type:', data.type);
        }
    },
    
    /**
     * Handle 3DS completion
     * Validates: Requirement 11.5 (trigger payment status polling on success)
     * 
     * @private
     * @param {Object} data - Completion data
     */
    _handleComplete(data) {
        console.log('[Simplyin 3DSHandler] 3DS completed successfully');
        
        // Close modal if open
        this.closeModal();
        
        // Clear stored session data
        this._clearSessionData();
        
        // Trigger completion callback
        if (this.callbacks.onComplete) {
            this.callbacks.onComplete({
                success: true,
                paymentId: data.paymentId || this.currentSession?.paymentId,
                transactionId: data.transactionId,
                status: data.status || 'completed',
                data: data
            });
        }
        
        this.currentSession = null;
    },
    
    /**
     * Handle 3DS cancellation
     * Validates: Requirement 11.6 (display cancellation message with retry option)
     * 
     * @private
     */
    _handleCancel() {
        console.log('[Simplyin 3DSHandler] 3DS cancelled by user');
        
        // Close modal if open
        this.closeModal();
        
        // Trigger cancellation callback
        if (this.callbacks.onCancel) {
            this.callbacks.onCancel();
        }
        
        // Note: Session data is NOT cleared on cancel to allow retry
    },
    
    /**
     * Handle 3DS error
     * Validates: Requirement 11.7 (display error message with failure reason)
     * 
     * @private
     * @param {Object} data - Error data
     */
    _handleError(data) {
        const errorMessage = data.message || data.error || '3D Secure verification failed';
        console.error('[Simplyin 3DSHandler] 3DS error:', errorMessage);
        
        // Close modal if open
        this.closeModal();
        
        // Clear stored session data
        this._clearSessionData();
        
        // Create error object
        const error = new Error(errorMessage);
        error.code = data.code || 'THREEDS_ERROR';
        error.details = data;
        
        this._triggerError(error);
        
        this.currentSession = null;
    },
    
    /**
     * Handle iframe resize request
     * 
     * @private
     * @param {Object} data - Resize data
     */
    _handleResize(data) {
        if (this.iframeElement && data.height) {
            const container = document.getElementById(this.config.iframeContainerId);
            if (container) {
                container.style.height = `${data.height}px`;
            }
        }
    },
    
    // ==========================================
    // Callback Registration Methods
    // ==========================================
    
    /**
     * Set callback for 3DS completion
     * Validates: Requirement 11.5 (completion callback)
     * 
     * @param {Function} callback - Callback function receiving result object
     */
    onComplete(callback) {
        this.callbacks.onComplete = callback;
    },
    
    /**
     * Set callback for 3DS cancellation
     * Validates: Requirement 11.6 (cancellation handling)
     * 
     * @param {Function} callback - Callback function
     */
    onCancel(callback) {
        this.callbacks.onCancel = callback;
    },
    
    /**
     * Set callback for 3DS errors
     * Validates: Requirement 11.7 (error handling)
     * 
     * @param {Function} callback - Callback function receiving error object
     */
    onError(callback) {
        this.callbacks.onError = callback;
    },
    
    // ==========================================
    // Timeout Handling
    // ==========================================
    
    /**
     * Start the timeout timer
     * 
     * @private
     */
    _startTimeout() {
        this._clearTimeout();
        
        this.timeoutTimer = setTimeout(() => {
            console.warn('[Simplyin 3DSHandler] 3DS verification timed out');
            
            const error = new Error('3D Secure verification timed out. Please try again.');
            error.code = 'THREEDS_TIMEOUT';
            
            this.closeModal();
            this._triggerError(error);
        }, this.config.timeout);
    },
    
    /**
     * Clear the timeout timer
     * 
     * @private
     */
    _clearTimeout() {
        if (this.timeoutTimer) {
            clearTimeout(this.timeoutTimer);
            this.timeoutTimer = null;
        }
    },
    
    // ==========================================
    // Session Data Management
    // ==========================================
    
    /**
     * Clear stored session data
     * 
     * @private
     */
    _clearSessionData() {
        if (typeof window !== 'undefined' && window.SessionStorage) {
            window.SessionStorage.remove3DSData();
        } else {
            try {
                sessionStorage.removeItem('simplyin_3ds_data');
            } catch (error) {
                console.warn('[Simplyin 3DSHandler] Failed to clear session data:', error);
            }
        }
    },
    
    /**
     * Restore session data (for handling return from redirect)
     * Validates: Requirement 11.3 (return URL handling)
     * 
     * @returns {Object|null} Restored session data or null
     */
    restoreSession() {
        let sessionData = null;
        
        if (typeof window !== 'undefined' && window.SessionStorage) {
            sessionData = window.SessionStorage.get3DSData();
        } else {
            try {
                const stored = sessionStorage.getItem('simplyin_3ds_data');
                if (stored) {
                    sessionData = JSON.parse(stored);
                }
            } catch (error) {
                console.warn('[Simplyin 3DSHandler] Failed to restore session data:', error);
            }
        }
        
        if (sessionData) {
            this.currentSession = sessionData;
            console.log('[Simplyin 3DSHandler] Session restored');
        }
        
        return sessionData;
    },
    
    /**
     * Check if there's a pending 3DS session
     * 
     * @returns {boolean} True if there's a pending session
     */
    hasPendingSession() {
        const session = this.restoreSession();
        return session !== null;
    },
    
    // ==========================================
    // Error Handling
    // ==========================================
    
    /**
     * Trigger error callback
     * 
     * @private
     * @param {Error} error - The error object
     */
    _triggerError(error) {
        if (this.callbacks.onError) {
            this.callbacks.onError(error);
        }
    },
    
    // ==========================================
    // Cleanup Methods
    // ==========================================
    
    /**
     * Destroy the handler and clean up resources
     */
    destroy() {
        console.log('[Simplyin 3DSHandler] Destroying...');
        
        // Close modal
        this.closeModal();
        
        // Remove modal element
        if (this.modalElement) {
            this.modalElement.remove();
            this.modalElement = null;
        }
        
        // Remove message listener
        if (this.messageListener) {
            window.removeEventListener('message', this.messageListener);
            this.messageListener = null;
        }
        
        // Clear timeout
        this._clearTimeout();
        
        // Reset state
        this.isInitialized = false;
        this.currentSession = null;
        this.callbacks = {
            onComplete: null,
            onCancel: null,
            onError: null
        };
        
        console.log('[Simplyin 3DSHandler] Destroyed successfully');
    },
    
    // ==========================================
    // Status Methods
    // ==========================================
    
    /**
     * Get current status (for debugging)
     * 
     * @returns {Object} Status information
     */
    getStatus() {
        return {
            isInitialized: this.isInitialized,
            hasCurrentSession: this.currentSession !== null,
            currentSession: this.currentSession,
            config: this.config,
            hasModal: this.modalElement !== null,
            hasIframe: this.iframeElement !== null,
            hasCallbacks: {
                onComplete: this.callbacks.onComplete !== null,
                onCancel: this.callbacks.onCancel !== null,
                onError: this.callbacks.onError !== null
            }
        };
    },
    
    /**
     * Check if handler is ready
     * 
     * @returns {boolean} True if initialized and ready
     */
    isReady() {
        return this.isInitialized;
    },
    
    /**
     * Get current session data
     * 
     * @returns {Object|null} Current session data
     */
    getCurrentSession() {
        return this.currentSession;
    }
};

// Export for use in templates
if (typeof window !== 'undefined') {
    window.ThreeDSecureHandler = ThreeDSecureHandler;
}

// Export for module systems (testing)
if (typeof module !== 'undefined' && module.exports) {
    module.exports = { ThreeDSecureHandler };
}
