/**
 * Security Test Framework
 * Comprehensive security testing utilities for WordPress HVAC plugin
 */

const { getBrowserManager } = require('../../framework/browser/BrowserManager');
const { getAuthManager } = require('../../framework/authentication/AuthManager');
const BasePage = require('../../framework/base/BasePage');

class SecurityTestFramework {
    constructor(config = {}) {
        this.config = {
            baseUrl: 'https://upskill-staging.measurequick.com',
            timeout: 30000,
            screenshotOnFailure: true,
            ...config
        };
        
        this.browserManager = getBrowserManager();
        this.authManager = getAuthManager();
        this.testResults = [];
    }

    /**
     * Initialize security test framework
     * @param {Object} config - Configuration object
     * @returns {Promise<void>}
     */
    async initialize(config = {}) {
        this.config = { ...this.config, ...config };
        await this.browserManager.initialize(this.config);
        await this.authManager.initialize(this.config);
    }

    /**
     * Test authentication redirects for protected URLs
     * @param {string[]} protectedUrls - Array of URLs that should require authentication
     * @returns {Promise<Object>}
     */
    async testAuthenticationRedirects(protectedUrls) {
        console.log('🔒 Testing authentication redirects...');
        
        const results = {
            passed: 0,
            failed: 0,
            tests: []
        };

        for (const url of protectedUrls) {
            const testResult = await this.testSingleUrlAuthRedirect(url);
            results.tests.push(testResult);
            
            if (testResult.passed) {
                results.passed++;
            } else {
                results.failed++;
            }
        }

        console.log(`  ✅ Passed: ${results.passed}, ❌ Failed: ${results.failed}`);
        return results;
    }

    /**
     * Test single URL for proper authentication redirect
     * @param {string} url - URL to test
     * @returns {Promise<Object>}
     * @private
     */
    async testSingleUrlAuthRedirect(url) {
        const fullUrl = url.startsWith('http') ? url : this.config.baseUrl + url;
        const testResult = {
            url: url,
            fullUrl: fullUrl,
            passed: false,
            statusCode: null,
            redirectUrl: null,
            error: null
        };

        try {
            console.log(`  🔍 Testing: ${url}`);
            
            const page = this.browserManager.getCurrentPage();
            
            // Navigate to protected URL without authentication
            const response = await page.goto(fullUrl, { 
                waitUntil: 'networkidle',
                timeout: this.config.timeout 
            });
            
            testResult.statusCode = response.status();
            testResult.redirectUrl = page.url();
            
            // Check if properly redirected to login
            const isRedirected = this.isRedirectedToLogin(testResult.redirectUrl, fullUrl);
            
            // Check for proper status codes
            const hasValidStatus = response.status() === 302 || 
                                 response.status() === 200 && isRedirected;
            
            testResult.passed = isRedirected && hasValidStatus;
            
            if (testResult.passed) {
                console.log(`    ✅ Properly redirected to login`);
            } else {
                console.log(`    ❌ Not properly protected - Status: ${response.status()}, URL: ${page.url()}`);
                
                if (this.config.screenshotOnFailure) {
                    await this.takeSecurityScreenshot(`auth-fail-${url.replace(/[^a-zA-Z0-9]/g, '-')}.png`);
                }
            }
            
        } catch (error) {
            testResult.error = error.message;
            console.log(`    ❌ Error testing ${url}: ${error.message}`);
        }

        return testResult;
    }

    /**
     * Check if URL is redirected to login page
     * @param {string} currentUrl - Current page URL
     * @param {string} originalUrl - Original requested URL
     * @returns {boolean}
     * @private
     */
    isRedirectedToLogin(currentUrl, originalUrl) {
        // If still on the same URL, not redirected
        if (currentUrl === originalUrl) {
            return false;
        }
        
        // Check for login page indicators
        const loginIndicators = [
            'community-login',
            'wp-login.php',
            'login',
            'auth',
            'signin'
        ];
        
        return loginIndicators.some(indicator => 
            currentUrl.toLowerCase().includes(indicator.toLowerCase())
        );
    }

    /**
     * Test role-based access control
     * @param {Object} testScenarios - Test scenarios with roles and expected access
     * @returns {Promise<Object>}
     */
    async testRoleBasedAccess(testScenarios) {
        console.log('👥 Testing role-based access control...');
        
        const results = {
            passed: 0,
            failed: 0,
            tests: []
        };

        for (const scenario of testScenarios) {
            const testResult = await this.testRoleAccess(scenario);
            results.tests.push(testResult);
            
            if (testResult.passed) {
                results.passed++;
            } else {
                results.failed++;
            }
        }

        console.log(`  ✅ Passed: ${results.passed}, ❌ Failed: ${results.failed}`);
        return results;
    }

    /**
     * Test access control for specific role
     * @param {Object} scenario - Test scenario
     * @returns {Promise<Object>}
     * @private
     */
    async testRoleAccess(scenario) {
        const { user, url, expectedAccess } = scenario;
        const testResult = {
            user: user.username,
            role: user.role,
            url: url,
            expectedAccess: expectedAccess,
            actualAccess: false,
            passed: false,
            error: null
        };

        try {
            console.log(`  🔍 Testing ${user.role} access to ${url}`);
            
            // Login as specified user
            await this.authManager.login(user);
            
            const page = this.browserManager.getCurrentPage();
            const fullUrl = url.startsWith('http') ? url : this.config.baseUrl + url;
            
            // Navigate to URL
            const response = await page.goto(fullUrl, { 
                waitUntil: 'networkidle',
                timeout: this.config.timeout 
            });
            
            // Determine if user has access
            testResult.actualAccess = this.determineAccess(response, page.url(), fullUrl);
            testResult.passed = testResult.actualAccess === expectedAccess;
            
            if (testResult.passed) {
                console.log(`    ✅ Access control working correctly`);
            } else {
                console.log(`    ❌ Access control failed - Expected: ${expectedAccess}, Actual: ${testResult.actualAccess}`);
                
                if (this.config.screenshotOnFailure) {
                    await this.takeSecurityScreenshot(`role-fail-${user.role}-${url.replace(/[^a-zA-Z0-9]/g, '-')}.png`);
                }
            }
            
            // Logout
            await this.authManager.logout();
            
        } catch (error) {
            testResult.error = error.message;
            console.log(`    ❌ Error testing role access: ${error.message}`);
        }

        return testResult;
    }

    /**
     * Determine if user has access based on response and URL
     * @param {Response} response - Page response
     * @param {string} currentUrl - Current page URL
     * @param {string} requestedUrl - Originally requested URL
     * @returns {boolean}
     * @private
     */
    determineAccess(response, currentUrl, requestedUrl) {
        // If redirected to login, no access
        if (this.isRedirectedToLogin(currentUrl, requestedUrl)) {
            return false;
        }
        
        // If status is 403 (Forbidden), no access
        if (response.status() === 403) {
            return false;
        }
        
        // If status is 404 (Not Found), might indicate access control
        if (response.status() === 404) {
            return false;
        }
        
        // If status is 200 and on the same URL, has access
        if (response.status() === 200 && currentUrl === requestedUrl) {
            return true;
        }
        
        // Default to no access for safety
        return false;
    }

    /**
     * Test for common WordPress security vulnerabilities
     * @returns {Promise<Object>}
     */
    async testCommonVulnerabilities() {
        console.log('🛡️  Testing common security vulnerabilities...');
        
        const results = {
            passed: 0,
            failed: 0,
            tests: []
        };

        // Test directory browsing
        const directoryTest = await this.testDirectoryBrowsing();
        results.tests.push(directoryTest);
        
        // Test file inclusion vulnerabilities
        const fileInclusionTest = await this.testFileInclusion();
        results.tests.push(fileInclusionTest);
        
        // Test WordPress version disclosure
        const versionDisclosureTest = await this.testVersionDisclosure();
        results.tests.push(versionDisclosureTest);
        
        // Test admin access without authentication
        const adminAccessTest = await this.testUnauthenticatedAdminAccess();
        results.tests.push(adminAccessTest);

        // Count results
        results.tests.forEach(test => {
            if (test.passed) results.passed++;
            else results.failed++;
        });

        console.log(`  ✅ Passed: ${results.passed}, ❌ Failed: ${results.failed}`);
        return results;
    }

    /**
     * Test directory browsing vulnerabilities
     * @returns {Promise<Object>}
     * @private
     */
    async testDirectoryBrowsing() {
        const testResult = {
            testName: 'Directory Browsing',
            passed: true,
            vulnerabilities: []
        };

        const directoriesToTest = [
            '/wp-content/',
            '/wp-content/plugins/',
            '/wp-content/themes/',
            '/wp-content/uploads/',
            '/wp-includes/',
            '/wp-admin/'
        ];

        for (const dir of directoriesToTest) {
            try {
                const page = this.browserManager.getCurrentPage();
                const response = await page.goto(this.config.baseUrl + dir, { timeout: 10000 });
                
                if (response.status() === 200) {
                    const content = await page.content();
                    if (content.includes('Index of') || content.includes('Directory listing')) {
                        testResult.passed = false;
                        testResult.vulnerabilities.push(`Directory browsing enabled for ${dir}`);
                    }
                }
            } catch (error) {
                // Directory might be properly protected - continue
            }
        }

        return testResult;
    }

    /**
     * Test file inclusion vulnerabilities
     * @returns {Promise<Object>}
     * @private
     */
    async testFileInclusion() {
        const testResult = {
            testName: 'File Inclusion',
            passed: true,
            vulnerabilities: []
        };

        const payloads = [
            '../../../../etc/passwd',
            '..\\..\\..\\..\\windows\\system32\\drivers\\etc\\hosts',
            'php://filter/read=convert.base64-encode/resource=wp-config.php'
        ];

        for (const payload of payloads) {
            try {
                const page = this.browserManager.getCurrentPage();
                const testUrl = `${this.config.baseUrl}/?file=${encodeURIComponent(payload)}`;
                const response = await page.goto(testUrl, { timeout: 10000 });
                
                if (response.status() === 200) {
                    const content = await page.content();
                    if (content.includes('root:') || content.includes('# localhost')) {
                        testResult.passed = false;
                        testResult.vulnerabilities.push(`File inclusion vulnerability with payload: ${payload}`);
                    }
                }
            } catch (error) {
                // Error might indicate protection - continue
            }
        }

        return testResult;
    }

    /**
     * Test WordPress version disclosure
     * @returns {Promise<Object>}
     * @private
     */
    async testVersionDisclosure() {
        const testResult = {
            testName: 'Version Disclosure',
            passed: true,
            disclosures: []
        };

        try {
            const page = this.browserManager.getCurrentPage();
            await page.goto(this.config.baseUrl, { timeout: 10000 });
            
            const content = await page.content();
            
            // Check for WordPress version in meta tags
            const versionRegex = /<meta name="generator" content="WordPress (\d+\.\d+(?:\.\d+)?)"/i;
            const versionMatch = content.match(versionRegex);
            
            if (versionMatch) {
                testResult.passed = false;
                testResult.disclosures.push(`WordPress version disclosed in meta tag: ${versionMatch[1]}`);
            }
            
            // Check readme.html file
            try {
                await page.goto(`${this.config.baseUrl}/readme.html`, { timeout: 10000 });
                const readmeContent = await page.content();
                if (readmeContent.includes('WordPress') && readmeContent.includes('Version')) {
                    testResult.passed = false;
                    testResult.disclosures.push('WordPress version disclosed in readme.html');
                }
            } catch (error) {
                // Readme might be removed - good practice
            }
        } catch (error) {
            console.warn(`Version disclosure test error: ${error.message}`);
        }

        return testResult;
    }

    /**
     * Test unauthenticated admin access
     * @returns {Promise<Object>}
     * @private
     */
    async testUnauthenticatedAdminAccess() {
        const testResult = {
            testName: 'Unauthenticated Admin Access',
            passed: true,
            vulnerabilities: []
        };

        try {
            const page = this.browserManager.getCurrentPage();
            const response = await page.goto(`${this.config.baseUrl}/wp-admin/`, { timeout: 10000 });
            
            // Should be redirected to login
            if (!this.isRedirectedToLogin(page.url(), `${this.config.baseUrl}/wp-admin/`)) {
                testResult.passed = false;
                testResult.vulnerabilities.push('Admin area accessible without authentication');
            }
        } catch (error) {
            console.warn(`Admin access test error: ${error.message}`);
        }

        return testResult;
    }

    /**
     * Test CSRF protection
     * @param {Object} formData - Form data to test
     * @returns {Promise<Object>}
     */
    async testCSRFProtection(formData) {
        console.log('🔐 Testing CSRF protection...');
        
        const testResult = {
            testName: 'CSRF Protection',
            passed: false,
            error: null
        };

        try {
            // Login first
            await this.authManager.loginAsMasterTrainer();
            
            const page = this.browserManager.getCurrentPage();
            await page.goto(formData.formUrl);
            
            // Try to submit form without CSRF token
            const response = await page.evaluate(async (data) => {
                const form = new FormData();
                Object.keys(data.fields).forEach(key => {
                    form.append(key, data.fields[key]);
                });
                
                return await fetch(data.submitUrl, {
                    method: 'POST',
                    body: form
                });
            }, formData);
            
            // If request is rejected (403/400), CSRF protection is working
            testResult.passed = response.status === 403 || response.status === 400;
            
        } catch (error) {
            testResult.error = error.message;
        }

        return testResult;
    }

    /**
     * Take security-related screenshot
     * @param {string} filename - Screenshot filename
     * @returns {Promise<string>}
     * @private
     */
    async takeSecurityScreenshot(filename) {
        try {
            return await this.browserManager.takeScreenshot(`security-${filename}`);
        } catch (error) {
            console.warn(`Failed to take security screenshot: ${error.message}`);
            return null;
        }
    }

    /**
     * Generate comprehensive security test report
     * @param {Object} allTestResults - All test results
     * @returns {Object}
     */
    generateSecurityReport(allTestResults) {
        const report = {
            timestamp: new Date().toISOString(),
            baseUrl: this.config.baseUrl,
            totalTests: 0,
            totalPassed: 0,
            totalFailed: 0,
            securityScore: 0,
            categories: {},
            recommendations: [],
            criticalIssues: []
        };

        // Process results by category
        Object.keys(allTestResults).forEach(category => {
            const categoryResults = allTestResults[category];
            report.categories[category] = {
                tests: categoryResults.tests || [categoryResults],
                passed: categoryResults.passed || (categoryResults.passed ? 1 : 0),
                failed: categoryResults.failed || (categoryResults.passed ? 0 : 1)
            };
            
            report.totalTests += report.categories[category].tests.length;
            report.totalPassed += report.categories[category].passed;
            report.totalFailed += report.categories[category].failed;
        });

        // Calculate security score (0-100)
        report.securityScore = report.totalTests > 0 
            ? Math.round((report.totalPassed / report.totalTests) * 100)
            : 0;

        // Generate recommendations based on failures
        this.generateSecurityRecommendations(report, allTestResults);

        return report;
    }

    /**
     * Generate security recommendations
     * @param {Object} report - Security report
     * @param {Object} testResults - Test results
     * @private
     */
    generateSecurityRecommendations(report, testResults) {
        if (report.securityScore < 100) {
            report.recommendations.push('Review and strengthen security configurations');
        }

        if (testResults.authRedirects && testResults.authRedirects.failed > 0) {
            report.criticalIssues.push('Some protected URLs are not properly secured');
            report.recommendations.push('Implement proper authentication checks for all protected pages');
        }

        if (testResults.roleAccess && testResults.roleAccess.failed > 0) {
            report.criticalIssues.push('Role-based access control has issues');
            report.recommendations.push('Review and fix user role permissions');
        }

        if (testResults.vulnerabilities) {
            testResults.vulnerabilities.tests.forEach(test => {
                if (!test.passed && test.vulnerabilities) {
                    test.vulnerabilities.forEach(vuln => {
                        report.criticalIssues.push(vuln);
                    });
                }
            });
        }
    }

    /**
     * Clean up security test framework
     * @returns {Promise<void>}
     */
    async cleanup() {
        await this.authManager.cleanup();
        await this.browserManager.cleanup();
    }
}

module.exports = SecurityTestFramework;