/**
 * Change Password Form Validation Test
 * Tests the change password form validation including:
 * - CSS class consistency
 * - Required field validation
 * - Minlength validation
 * - Password mismatch detection
 * - Password strength indicator
 * CI-compatible: Works in both local and CI environments
 */

const puppeteer = require('puppeteer');
const AuthHelper = require('./auth_helper');
const { Timer, CI_TEST_USER } = require('./auth_helper');
const { getPuppeteerLaunchOptions } = require('./puppeteer_config');
const fs = require('fs');
const path = require('path');

async function testChangePasswordValidation() {
    const isCI = !!process.env.CI;
    const testTimer = new Timer('test_change_password_validation');
    console.log(`🧪 Running change password validation test (CI mode: ${isCI})`);
    // Create screenshots directory if it doesn't exist
    const screenshotsDir = path.join(__dirname, 'screenshots');
    if (!fs.existsSync(screenshotsDir)) {
        fs.mkdirSync(screenshotsDir, { recursive: true });
    }

    const browser = await puppeteer.launch(getPuppeteerLaunchOptions());
    const page = await browser.newPage();
    const baseUrl = 'http://127.0.0.1:5000';

    // Increase default timeout in CI
    if (isCI) {
        page.setDefaultTimeout(60000);
        page.setDefaultNavigationTimeout(60000);
    }

    let testsPassed = 0;
    let testsFailed = 0;

    // Test user credentials - ensureAuthenticated will use CI_TEST_USER or register with DEFAULT_TEST_USER password
    const testUser = {
        password: isCI ? CI_TEST_USER.password : 'T3st!Secure#2024$LDR'  // DEFAULT_TEST_USER.password
    };

    console.log('🧪 Starting change password validation tests...\n');

    try {
        // IMPORTANT: This test must NOT use the shared CI_TEST_USER because it tests
        // password change functionality. Even though we're only testing validation
        // (mismatched passwords, same-as-current detection), using a dedicated user
        // ensures we don't accidentally break other tests if validation logic changes.
        // See AI Code Review concern about "Test Isolation Failure".
        console.log('📋 Setup: Registering dedicated test user...');
        const authHelper = new AuthHelper(page, baseUrl);
        const dedicatedUsername = `changepwd_test_${Date.now()}`;
        const dedicatedPassword = 'T3st!Secure#2024$LDR';

        try {
            // Always register a new user for this test to ensure isolation
            await authHelper.register(dedicatedUsername, dedicatedPassword);
            // Update testUser.password to match the registered user
            testUser.password = dedicatedPassword;
            console.log(`✅ Registered dedicated user: ${dedicatedUsername}\n`);
        } catch (authError) {
            console.log(`⚠️  Could not register test user: ${authError.message}`);
            console.log('   Skipping change password tests - requires authenticated user\n');
            await browser.close();
            testTimer.summary();
            console.log('❌ Test skipped - no test user available');
            process.exit(1); // Auth failure should not be silent
        }

        // Navigate to change password page
        // NOTE: Using 'domcontentloaded' instead of 'networkidle2' to avoid hangs
        // caused by WebSocket/polling keeping the network active.
        console.log('📄 Navigating to change password page...');
        await page.goto(`${baseUrl}/auth/change-password`, {
            waitUntil: 'domcontentloaded',
            timeout: 30000
        });

        // Check if we were redirected (not authenticated)
        const currentUrl = page.url();
        if (currentUrl.includes('/auth/login')) {
            console.log('⚠️  Redirected to login - user not authenticated');
            console.log('   Attempting to login...');
            await authHelper.login(dedicatedUsername, dedicatedPassword);
            await page.goto(`${baseUrl}/auth/change-password`, {
                waitUntil: 'domcontentloaded',
                timeout: 30000
            });
        }

        // Wait for the form - try multiple selectors
        try {
            // First wait for the page to have any form elements
            await page.waitForFunction(() => {
                const form = document.querySelector('form');
                const input = document.querySelector('input[name="current_password"]');
                return form && input;
            }, { timeout: 15000 });
            console.log('✅ Change password page loaded\n');
        } catch {
            console.log('⚠️  Change password page not accessible');
            console.log(`   Current URL: ${page.url()}`);
            // Log page content for debugging
            const pageContent = await page.evaluate(() => document.body.innerHTML.substring(0, 500));
            console.log(`   Page content preview: ${pageContent.substring(0, 200)}...`);

            // Check if this is a server error (CI environment issue)
            if (pageContent.includes('Server error') || pageContent.includes('error')) {
                console.log('❌ Server error detected - cannot run change password tests');
                await browser.close();
                process.exit(1); // Infrastructure error should not be silent
            }
            throw new Error('Cannot access change password page');
        }

        // Test 1: Check CSS class consistency
        console.log('📋 Test 1: CSS class consistency');

        const currentPasswordInput = await page.$('input[name="current_password"]');
        const currentPasswordClass = await page.evaluate(el => el.className, currentPasswordInput);

        if (currentPasswordClass.includes('ldr-form-control')) {
            console.log('✅ Current password input uses ldr-form-control class');
            testsPassed++;
        } else {
            console.log(`❌ Current password input has incorrect class: "${currentPasswordClass}"`);
            testsFailed++;
        }

        const newPasswordInput = await page.$('input[name="new_password"]');
        const newPasswordClass = await page.evaluate(el => el.className, newPasswordInput);

        if (newPasswordClass.includes('ldr-form-control')) {
            console.log('✅ New password input uses ldr-form-control class');
            testsPassed++;
        } else {
            console.log(`❌ New password input has incorrect class: "${newPasswordClass}"`);
            testsFailed++;
        }

        const confirmPasswordInput = await page.$('input[name="confirm_password"]');
        const confirmPasswordClass = await page.evaluate(el => el.className, confirmPasswordInput);

        if (confirmPasswordClass.includes('ldr-form-control')) {
            console.log('✅ Confirm password input uses ldr-form-control class');
            testsPassed++;
        } else {
            console.log(`❌ Confirm password input has incorrect class: "${confirmPasswordClass}"`);
            testsFailed++;
        }

        // Test 2: Required field validation - current password
        console.log('\n📋 Test 2: Current password required validation');

        let validity = await page.evaluate(el => ({
            valid: el.validity.valid,
            valueMissing: el.validity.valueMissing,
            required: el.required
        }), currentPasswordInput);

        console.log(`   Current password - required: ${validity.required}, valueMissing: ${validity.valueMissing}`);

        if (validity.required && validity.valueMissing) {
            console.log('✅ Current password is required and empty triggers valueMissing');
            testsPassed++;
        } else {
            console.log('❌ Current password should be required');
            testsFailed++;
        }

        // Test 3: New password minlength validation
        console.log('\n📋 Test 3: New password minlength validation');

        await page.type('input[name="new_password"]', 'short', { delay: 50 });

        validity = await page.evaluate(el => ({
            valid: el.validity.valid,
            tooShort: el.validity.tooShort,
            minLength: el.minLength
        }), newPasswordInput);

        console.log(`   Value: "short" (5 chars), minLength: ${validity.minLength}, tooShort: ${validity.tooShort}`);

        if (validity.tooShort) {
            console.log('✅ New password too short correctly triggers tooShort validity');
            testsPassed++;
        } else {
            console.log('❌ New password too short should trigger tooShort validity');
            testsFailed++;
        }

        // Test 4: Password strength indicator
        console.log('\n📋 Test 4: Password strength indicator');

        // Clear and type a weak password (short, lowercase-only, no digit)
        // Strength algorithm: +1 for length>=8, +1 for length>=12, +1 for lowercase, +1 for digit
        // "abcdefg" scores 1 (lowercase only) → strength<=1 → weak
        await page.evaluate(() => { document.querySelector('input[name="new_password"]').value = ''; });
        await page.type('input[name="new_password"]', 'abcdefg', { delay: 50 });
        await new Promise(resolve => setTimeout(resolve, 200));

        const strengthBar = await page.$('#password-strength');
        const strengthVisible = await page.evaluate(el => el.style.display !== 'none', strengthBar);
        let strengthClasses = await page.evaluate(el => el.className, strengthBar);

        console.log(`   Weak password "abcdefg" - visible: ${strengthVisible}, classes: "${strengthClasses}"`);

        if (strengthVisible) {
            console.log('✅ Password strength indicator is visible');
            testsPassed++;
        } else {
            console.log('❌ Password strength indicator should be visible');
            testsFailed++;
        }

        if (strengthClasses.includes('ldr-strength-weak')) {
            console.log('✅ Weak password shows ldr-strength-weak class');
            testsPassed++;
        } else {
            console.log(`❌ Expected ldr-strength-weak class, got: "${strengthClasses}"`);
            testsFailed++;
        }

        // Test strong password
        await page.evaluate(() => { document.querySelector('input[name="new_password"]').value = ''; });
        await page.type('input[name="new_password"]', 'StrongPass123!', { delay: 50 });
        await new Promise(resolve => setTimeout(resolve, 200));

        strengthClasses = await page.evaluate(el => el.className, strengthBar);
        console.log(`   Strong password - classes: "${strengthClasses}"`);

        if (strengthClasses.includes('ldr-strength-strong')) {
            console.log('✅ Strong password shows ldr-strength-strong class');
            testsPassed++;
        } else {
            console.log(`❌ Expected ldr-strength-strong class, got: "${strengthClasses}"`);
            testsFailed++;
        }

        // Test 5: Password mismatch detection
        console.log('\n📋 Test 5: Password mismatch detection');

        // Fill form with mismatched passwords
        await page.evaluate(() => {
            document.querySelector('input[name="current_password"]').value = '';
            document.querySelector('input[name="new_password"]').value = '';
            document.querySelector('input[name="confirm_password"]').value = '';
        });

        await page.type('input[name="current_password"]', testUser.password, { delay: 30 });
        await page.type('input[name="new_password"]', 'NewPassword123!', { delay: 30 });
        await page.type('input[name="confirm_password"]', 'DifferentPassword!', { delay: 30 });

        // Set up dialog handler to catch the alert
        let alertMessage = null;
        page.once('dialog', async dialog => {
            alertMessage = dialog.message();
            await dialog.accept();
        });

        // Try to submit the form
        await page.click('button[type="submit"]');
        await new Promise(resolve => setTimeout(resolve, 1000));

        if (alertMessage && alertMessage.toLowerCase().includes('match')) {
            console.log(`✅ Password mismatch shows alert: "${alertMessage}"`);
            testsPassed++;
        } else {
            console.log('❌ Password mismatch should show alert about non-matching passwords');
            console.log(`   Alert received: ${alertMessage}`);
            testsFailed++;
        }

        // Test 6: Same password detection (new = current)
        console.log('\n📋 Test 6: New password same as current detection');

        // Clear and fill with same password
        await page.evaluate(() => {
            document.querySelector('input[name="current_password"]').value = '';
            document.querySelector('input[name="new_password"]').value = '';
            document.querySelector('input[name="confirm_password"]').value = '';
        });

        await page.type('input[name="current_password"]', testUser.password, { delay: 30 });
        await page.type('input[name="new_password"]', testUser.password, { delay: 30 });
        await page.type('input[name="confirm_password"]', testUser.password, { delay: 30 });

        // Set up dialog handler
        // Single test sequence; no concurrent writers to alertMessage.
        // eslint-disable-next-line require-atomic-updates
        alertMessage = null;
        page.once('dialog', async dialog => {
            alertMessage = dialog.message();
            await dialog.accept();
        });

        // Try to submit the form
        await page.click('button[type="submit"]');
        await new Promise(resolve => setTimeout(resolve, 1000));

        if (alertMessage && (alertMessage.toLowerCase().includes('different') || alertMessage.toLowerCase().includes('same'))) {
            console.log(`✅ Same password shows alert: "${alertMessage}"`);
            testsPassed++;
        } else {
            // Check if server rejected it
            const afterUrl = page.url();
            const errorAlert = await page.$('.alert');
            if (afterUrl.includes('/auth/change-password') && errorAlert) {
                const errorText = await page.evaluate(el => el.textContent, errorAlert);
                if (errorText.toLowerCase().includes('different')) {
                    console.log(`✅ Server rejected same password: "${errorText.trim().substring(0, 50)}"`);
                    testsPassed++;
                } else {
                    console.log(`⚠️  Alert shown but unexpected message: "${errorText.trim().substring(0, 50)}"`);
                }
            } else {
                console.log('⚠️  Same password validation might be server-side only');
                // Don't fail - this might be expected behavior
            }
        }

        // Take a screenshot of the final state (skip in CI)
        if (!isCI) {
            await page.screenshot({
                path: path.join(screenshotsDir, 'change_password_validation_test.png'),
                fullPage: true
            });
            console.log('\n📸 Screenshot saved to screenshots/change_password_validation_test.png');
        }

        // Summary
        console.log('\n' + '='.repeat(50));
        console.log(`📊 Test Summary: ${testsPassed} passed, ${testsFailed} failed`);
        console.log('='.repeat(50));

        if (testsFailed > 0) {
            throw new Error(`${testsFailed} test(s) failed`);
        }

        console.log('\n🎉 All change password validation tests passed!');

    } catch (error) {
        console.error('\n❌ Test failed:', error.message);

        // Take error screenshot (skip in CI)
        if (!isCI) {
            try {
                await page.screenshot({
                    path: path.join(screenshotsDir, 'change_password_validation_error.png'),
                    fullPage: true
                });
                console.log('📸 Error screenshot saved');
            } catch (screenshotError) {
                console.log('⚠️  Could not take error screenshot:', screenshotError.message);
            }
        }

        await browser.close();
        testTimer.summary();
        process.exit(1);
    }

    await browser.close();
    testTimer.summary();
    console.log('\n✅ Test completed successfully');
}

// Run the test
testChangePasswordValidation().catch(console.error);
