#!/usr/bin/env node
/**
 * Settings Interactions UI Tests
 *
 * Tests for settings page interactions including tabs, search,
 * toggles, inputs, and save functionality.
 *
 * Run: node test_settings_interactions_ci.js
 */

const { setupTest, teardownTest, TestResults, log, delay } = require('./test_lib');

// ============================================================================
// Settings Page Structure Tests
// ============================================================================
const SettingsPageTests = {
    async settingsPageLoads(page, baseUrl) {
        await page.goto(`${baseUrl}/settings`, { waitUntil: 'networkidle2' });

        const result = await page.evaluate(() => {
            const hasContent = document.body.textContent.length > 100;
            const title = document.title.toLowerCase();
            const hasSettingsContent = title.includes('settings') || title.includes('configuration') ||
                                      !!document.querySelector('.settings, #settings, [class*="settings"]');

            return {
                hasContent,
                hasSettingsContent,
                title,
                url: window.location.href
            };
        });

        return {
            passed: result.hasContent,
            message: `Settings page loads (title: "${result.title}")`
        };
    },

    async settingsSearchFilter(page, baseUrl) {
        await page.goto(`${baseUrl}/settings`, { waitUntil: 'networkidle2' });

        const result = await page.evaluate(() => {
            const searchInput = document.querySelector(
                'input[type="search"], ' +
                'input[placeholder*="search"], ' +
                'input[placeholder*="filter"], ' +
                '#settings-search, ' +
                '.settings-filter'
            );

            return {
                hasSearch: !!searchInput,
                placeholder: searchInput?.placeholder
            };
        });

        if (!result.hasSearch) {
            return { passed: null, skipped: true, message: 'No settings search found' };
        }

        return {
            passed: true,
            message: `Settings search: placeholder="${result.placeholder}"`
        };
    },

    async settingsSearchFiltering(page, baseUrl) {
        await page.goto(`${baseUrl}/settings`, { waitUntil: 'networkidle2' });

        const searchInput = await page.$('input[type="search"], input[placeholder*="search"], input[placeholder*="filter"]');

        if (!searchInput) {
            return { passed: null, skipped: true, message: 'No search input to test filtering' };
        }

        // Count initial settings
        const initialCount = await page.evaluate(() => {
            const settings = document.querySelectorAll('.setting, .setting-item, [class*="setting-row"]');
            return settings.length;
        });

        // Type search term
        await searchInput.type('model');
        await delay(300);

        const afterSearchCount = await page.evaluate(() => {
            const visibleSettings = Array.from(document.querySelectorAll('.setting, .setting-item, [class*="setting-row"]'))
                .filter(s => window.getComputedStyle(s).display !== 'none');
            return visibleSettings.length;
        });

        return {
            passed: true,
            message: `Search filters (initial: ${initialCount}, after filter: ${afterSearchCount})`
        };
    }
};

// ============================================================================
// Settings Tabs Tests
// ============================================================================
const SettingsTabsTests = {
    async settingsTabsExist(page, baseUrl) {
        await page.goto(`${baseUrl}/settings`, { waitUntil: 'networkidle2' });

        const result = await page.evaluate(() => {
            const tabs = document.querySelectorAll(
                '.tab, ' +
                '.nav-tab, ' +
                '[role="tab"], ' +
                '.settings-tab, ' +
                '.nav-link'
            );

            const tabTexts = Array.from(tabs).slice(0, 10).map(t => t.textContent?.trim());

            return {
                tabCount: tabs.length,
                tabs: tabTexts
            };
        });

        if (result.tabCount === 0) {
            return { passed: null, skipped: true, message: 'No settings tabs found' };
        }

        return {
            passed: true,
            message: `${result.tabCount} tabs: ${result.tabs.join(', ')}`
        };
    },

    async tabNavigationWorks(page, baseUrl) {
        await page.goto(`${baseUrl}/settings`, { waitUntil: 'networkidle2' });

        const result = await page.evaluate(() => {
            const tabs = document.querySelectorAll('.tab, .nav-tab, [role="tab"], .settings-tab, .nav-link');
            if (tabs.length < 2) return { hasTabs: false };

            const secondTab = tabs[1];
            const firstTabContent = document.querySelector('.tab-content, .tab-pane, [role="tabpanel"]');
            const beforeContent = firstTabContent?.textContent?.substring(0, 100);

            secondTab.click();

            const afterContent = firstTabContent?.textContent?.substring(0, 100);

            return {
                hasTabs: true,
                tabClicked: secondTab.textContent?.trim(),
                contentChanged: beforeContent !== afterContent
            };
        });

        if (!result.hasTabs) {
            return { passed: null, skipped: true, message: 'Not enough tabs to test navigation' };
        }

        return {
            passed: true,
            message: `Tab navigation: clicked "${result.tabClicked}", content changed=${result.contentChanged}`
        };
    },

    async specificTabsPresent(page, baseUrl) {
        await page.goto(`${baseUrl}/settings`, { waitUntil: 'networkidle2' });

        const result = await page.evaluate(() => {
            const pageText = document.body.textContent.toLowerCase();
            const tabs = Array.from(document.querySelectorAll('.tab, .nav-tab, [role="tab"], .settings-tab, .nav-link'))
                .map(t => t.textContent?.toLowerCase());

            const allText = pageText + tabs.join(' ');

            return {
                hasLanguageModels: allText.includes('language model') || allText.includes('llm') || allText.includes('model'),
                hasSearchEngines: allText.includes('search engine') || allText.includes('search'),
                hasReports: allText.includes('report'),
                hasApplication: allText.includes('application') || allText.includes('app'),
                hasNotifications: allText.includes('notification')
            };
        });

        const foundTabs = Object.entries(result).filter(([k, v]) => v).map(([k]) => k.replace('has', ''));

        return {
            passed: foundTabs.length > 0,
            message: `Settings categories: ${foundTabs.join(', ')}`
        };
    }
};

// ============================================================================
// Settings Controls Tests
// ============================================================================
const SettingsControlsTests = {
    async textInputSettings(page, baseUrl) {
        await page.goto(`${baseUrl}/settings`, { waitUntil: 'networkidle2' });
        await delay(500);

        const result = await page.evaluate(() => {
            // Broader search for text inputs on settings page
            const textInputs = document.querySelectorAll(
                '.settings input[type="text"], ' +
                '.setting input[type="text"], ' +
                'input.setting-input, ' +
                'form input[type="text"], ' +
                '.card input[type="text"], ' +
                '.form-group input[type="text"], ' +
                '[class*="setting"] input[type="text"]'
            );

            // Also check for any inputs that look like settings
            const allTextInputs = textInputs.length === 0
                ? document.querySelectorAll('input[type="text"]:not([type="search"]):not([hidden])')
                : textInputs;

            const firstInput = allTextInputs[0];

            // Check if we're on a settings page
            const isSettingsPage = window.location.href.includes('settings') ||
                                   !!document.querySelector('[class*="settings"], #settings');

            return {
                count: allTextInputs.length,
                hasInputs: allTextInputs.length > 0,
                firstInputName: firstInput?.name,
                firstInputValue: firstInput?.value?.substring(0, 30),
                isSettingsPage
            };
        });

        if (!result.hasInputs) {
            if (result.isSettingsPage) {
                return { passed: null, skipped: true, message: 'Settings page found but no text inputs (may use other control types)' };
            }
            return { passed: null, skipped: true, message: 'No text inputs found on settings page' };
        }

        return {
            passed: true,
            message: `Text inputs: ${result.count} found (first: "${result.firstInputName}")`
        };
    },

    async numberInputSettings(page, baseUrl) {
        await page.goto(`${baseUrl}/settings`, { waitUntil: 'networkidle2' });

        const result = await page.evaluate(() => {
            const numberInputs = document.querySelectorAll(
                '.settings input[type="number"], ' +
                '.setting input[type="number"]'
            );

            const firstInput = numberInputs[0];

            return {
                count: numberInputs.length,
                hasInputs: numberInputs.length > 0,
                firstInputName: firstInput?.name,
                min: firstInput?.min,
                max: firstInput?.max,
                value: firstInput?.value
            };
        });

        if (!result.hasInputs) {
            return { passed: null, skipped: true, message: 'No number inputs found' };
        }

        return {
            passed: true,
            message: `Number inputs: ${result.count} found (first: "${result.firstInputName}", min=${result.min}, max=${result.max})`
        };
    },

    async toggleSwitchSettings(page, baseUrl) {
        await page.goto(`${baseUrl}/settings`, { waitUntil: 'networkidle2' });
        await delay(500);

        const result = await page.evaluate(() => {
            // Broader search for toggle/checkbox inputs
            const toggles = document.querySelectorAll(
                '.settings input[type="checkbox"], ' +
                '.setting input[type="checkbox"], ' +
                '.toggle-switch, ' +
                '.switch input, ' +
                'form input[type="checkbox"], ' +
                '.card input[type="checkbox"], ' +
                '[class*="toggle"], ' +
                '[class*="switch"] input'
            );

            // Fallback to any checkboxes
            const allToggles = toggles.length === 0
                ? document.querySelectorAll('input[type="checkbox"]:not([hidden])')
                : toggles;

            const firstToggle = allToggles[0];

            // Check if we're on a settings page
            const isSettingsPage = window.location.href.includes('settings') ||
                                   !!document.querySelector('[class*="settings"], #settings');

            return {
                count: allToggles.length,
                hasToggles: allToggles.length > 0,
                firstToggleName: firstToggle?.name,
                firstToggleChecked: firstToggle?.checked,
                isSettingsPage
            };
        });

        if (!result.hasToggles) {
            if (result.isSettingsPage) {
                return { passed: null, skipped: true, message: 'Settings page found but no toggles (may use other control types)' };
            }
            return { passed: null, skipped: true, message: 'No toggle switches found on settings page' };
        }

        return {
            passed: true,
            message: `Toggles: ${result.count} found (first: "${result.firstToggleName}", checked=${result.firstToggleChecked})`
        };
    },

    async dropdownSelectSettings(page, baseUrl) {
        await page.goto(`${baseUrl}/settings`, { waitUntil: 'networkidle2' });

        const result = await page.evaluate(() => {
            const selects = document.querySelectorAll(
                '.settings select, ' +
                '.setting select'
            );

            const firstSelect = selects[0];
            const options = firstSelect ? Array.from(firstSelect.options).slice(0, 5).map(o => o.text) : [];

            return {
                count: selects.length,
                hasSelects: selects.length > 0,
                firstName: firstSelect?.name,
                options
            };
        });

        if (!result.hasSelects) {
            return { passed: null, skipped: true, message: 'No dropdown selects found' };
        }

        return {
            passed: true,
            message: `Dropdowns: ${result.count} found (first: "${result.firstName}", options: ${result.options.join(', ')})`
        };
    },

    async toggleSwitchToggleable(page, baseUrl) {
        await page.goto(`${baseUrl}/settings`, { waitUntil: 'networkidle2' });

        const result = await page.evaluate(() => {
            const toggle = document.querySelector(
                '.settings input[type="checkbox"], ' +
                '.toggle-switch input, ' +
                '.switch input'
            );

            if (!toggle) return { hasToggle: false };

            const beforeState = toggle.checked;
            toggle.click();
            const afterState = toggle.checked;

            return {
                hasToggle: true,
                beforeState,
                afterState,
                toggled: beforeState !== afterState
            };
        });

        if (!result.hasToggle) {
            return { passed: null, skipped: true, message: 'No toggle to test' };
        }

        return {
            passed: result.toggled,
            message: `Toggle works: before=${result.beforeState}, after=${result.afterState}`
        };
    }
};

// ============================================================================
// Settings Save Tests
// ============================================================================
const SettingsSaveTests = {
    async saveButtonExists(page, baseUrl) {
        await page.goto(`${baseUrl}/settings`, { waitUntil: 'networkidle2' });

        const result = await page.evaluate(() => {
            const buttons = Array.from(document.querySelectorAll('button, input[type="submit"], .btn'));
            const saveBtn = buttons.find(btn => {
                const text = btn.textContent?.toLowerCase() || btn.value?.toLowerCase() || '';
                return text.includes('save') || text.includes('apply') || text.includes('update');
            });

            return {
                hasSaveBtn: !!saveBtn,
                buttonText: saveBtn?.textContent?.trim() || saveBtn?.value
            };
        });

        if (!result.hasSaveBtn) {
            // Check for auto-save indicator
            const autoSave = await page.evaluate(() => {
                const text = document.body.textContent.toLowerCase();
                return text.includes('auto-save') || text.includes('automatically saved');
            });

            if (autoSave) {
                return { passed: true, message: 'Settings use auto-save (no manual save button needed)' };
            }

            return { passed: null, skipped: true, message: 'No save button found (may use auto-save)' };
        }

        return {
            passed: true,
            message: `Save button: "${result.buttonText}"`
        };
    },

    async resetToDefaultsButton(page, baseUrl) {
        await page.goto(`${baseUrl}/settings`, { waitUntil: 'networkidle2' });

        const result = await page.evaluate(() => {
            const buttons = Array.from(document.querySelectorAll('button, .btn'));
            const resetBtn = buttons.find(btn => {
                const text = btn.textContent?.toLowerCase() || '';
                return text.includes('reset') || text.includes('default') || text.includes('restore');
            });

            return {
                hasResetBtn: !!resetBtn,
                buttonText: resetBtn?.textContent?.trim()
            };
        });

        if (!result.hasResetBtn) {
            return { passed: null, skipped: true, message: 'No reset to defaults button found' };
        }

        return {
            passed: true,
            message: `Reset button: "${result.buttonText}"`
        };
    },

    async autoSaveFunctionality(page, baseUrl) {
        await page.goto(`${baseUrl}/settings`, { waitUntil: 'networkidle2' });

        // Find a toggle and change it
        const result = await page.evaluate(() => {
            const toggle = document.querySelector('.settings input[type="checkbox"]');
            if (!toggle) return { hasToggle: false };

            toggle.click();

            // Wait a bit and check for toast/notification
            return new Promise(resolve => {
                setTimeout(() => {
                    const toast = document.querySelector('.toast, .notification, .alert-success, [class*="toast"]');
                    const savedIndicator = document.querySelector('.saved, .success, [class*="saved"]');

                    resolve({
                        hasToggle: true,
                        hasToast: !!toast,
                        hasSavedIndicator: !!savedIndicator,
                        toastText: toast?.textContent?.trim()?.substring(0, 50)
                    });
                }, 500);
            });
        });

        if (!result.hasToggle) {
            return { passed: null, skipped: true, message: 'No toggle to test auto-save' };
        }

        const hasAutoSave = result.hasToast || result.hasSavedIndicator;

        return {
            passed: hasAutoSave,
            message: hasAutoSave
                ? `Auto-save: toast="${result.toastText}", indicator=${result.hasSavedIndicator}`
                : 'No auto-save feedback detected'
        };
    }
};

// ============================================================================
// Settings Help Tests
// ============================================================================
const SettingsHelpTests = {
    async settingDescriptions(page, baseUrl) {
        await page.goto(`${baseUrl}/settings`, { waitUntil: 'networkidle2' });
        await delay(500);

        const result = await page.evaluate(() => {
            // Broader search for descriptions and help text
            const descriptions = document.querySelectorAll(
                '.setting-description, ' +
                '.help-text, ' +
                '.setting-help, ' +
                'small.text-muted, ' +
                '.form-text, ' +
                '.description, ' +
                '[class*="description"], ' +
                '[class*="help-text"], ' +
                'label + small, ' +
                '.card-text, ' +
                'p.text-muted'
            );

            const firstDesc = descriptions[0];

            // Check if we're on a settings page
            const isSettingsPage = window.location.href.includes('settings') ||
                                   !!document.querySelector('[class*="settings"], #settings');

            return {
                count: descriptions.length,
                hasDescriptions: descriptions.length > 0,
                firstText: firstDesc?.textContent?.trim()?.substring(0, 100),
                isSettingsPage
            };
        });

        if (!result.hasDescriptions) {
            if (result.isSettingsPage) {
                return { passed: null, skipped: true, message: 'Settings page found but no descriptions (may use inline labels)' };
            }
            return { passed: null, skipped: true, message: 'No setting descriptions found' };
        }

        return {
            passed: true,
            message: `Setting descriptions: ${result.count} found (first: "${result.firstText}...")`
        };
    },

    async tooltipsPresent(page, baseUrl) {
        await page.goto(`${baseUrl}/settings`, { waitUntil: 'networkidle2' });

        const result = await page.evaluate(() => {
            const tooltipTriggers = document.querySelectorAll(
                '[data-tooltip], ' +
                '[title], ' +
                '.tooltip-trigger, ' +
                '[data-toggle="tooltip"], ' +
                '.info-icon, ' +
                '.help-icon'
            );

            return {
                count: tooltipTriggers.length,
                hasTooltips: tooltipTriggers.length > 0
            };
        });

        if (!result.hasTooltips) {
            return { passed: null, skipped: true, message: 'No tooltips found' };
        }

        return {
            passed: true,
            message: `Tooltips: ${result.count} found`
        };
    }
};

// ============================================================================
// Raw Config Editor Tests
// ============================================================================
const RawConfigTests = {
    async rawConfigEditorExists(page, baseUrl) {
        await page.goto(`${baseUrl}/settings`, { waitUntil: 'networkidle2' });

        const result = await page.evaluate(() => {
            const jsonEditor = document.querySelector(
                '.json-editor, ' +
                '#raw-config, ' +
                'textarea.config-editor, ' +
                '.code-editor, ' +
                '[class*="raw-config"]'
            );

            const toggleBtn = document.querySelector(
                '[data-toggle="raw-config"], ' +
                '.show-raw-config, ' +
                '#toggle-raw-config'
            );

            return {
                hasEditor: !!jsonEditor,
                hasToggle: !!toggleBtn,
                toggleText: toggleBtn?.textContent?.trim()
            };
        });

        if (!result.hasEditor && !result.hasToggle) {
            return { passed: null, skipped: true, message: 'No raw config editor found' };
        }

        return {
            passed: true,
            message: `Raw config: editor=${result.hasEditor}, toggle="${result.toggleText}"`
        };
    }
};

// ============================================================================
// Main Test Runner
// ============================================================================
async function main() {
    log.section('Settings Interactions Tests');

    const ctx = await setupTest({ authenticate: true });
    const results = new TestResults('Settings Interactions Tests');
    const { page } = ctx;
    const { baseUrl } = ctx.config;

    try {
        // Settings Page Structure
        log.section('Settings Page Structure');

        const pageLoadsResult = await SettingsPageTests.settingsPageLoads(page, baseUrl);
        results.add('Page', 'Loads', pageLoadsResult.passed, pageLoadsResult.message);

        const searchResult = await SettingsPageTests.settingsSearchFilter(page, baseUrl);
        if (searchResult.skipped) {
            results.skip('Page', 'Search Filter', searchResult.message);
        } else {
            results.add('Page', 'Search Filter', searchResult.passed, searchResult.message);
        }

        const filteringResult = await SettingsPageTests.settingsSearchFiltering(page, baseUrl);
        if (filteringResult.skipped) {
            results.skip('Page', 'Search Filtering', filteringResult.message);
        } else {
            results.add('Page', 'Search Filtering', filteringResult.passed, filteringResult.message);
        }

        // Settings Tabs
        log.section('Settings Tabs');

        const tabsExistResult = await SettingsTabsTests.settingsTabsExist(page, baseUrl);
        if (tabsExistResult.skipped) {
            results.skip('Tabs', 'Exist', tabsExistResult.message);
        } else {
            results.add('Tabs', 'Exist', tabsExistResult.passed, tabsExistResult.message);
        }

        const tabNavResult = await SettingsTabsTests.tabNavigationWorks(page, baseUrl);
        if (tabNavResult.skipped) {
            results.skip('Tabs', 'Navigation', tabNavResult.message);
        } else {
            results.add('Tabs', 'Navigation', tabNavResult.passed, tabNavResult.message);
        }

        const specificTabsResult = await SettingsTabsTests.specificTabsPresent(page, baseUrl);
        results.add('Tabs', 'Categories', specificTabsResult.passed, specificTabsResult.message);

        // Settings Controls
        log.section('Settings Controls');

        const textInputResult = await SettingsControlsTests.textInputSettings(page, baseUrl);
        if (textInputResult.skipped) {
            results.skip('Controls', 'Text Inputs', textInputResult.message);
        } else {
            results.add('Controls', 'Text Inputs', textInputResult.passed, textInputResult.message);
        }

        const numberInputResult = await SettingsControlsTests.numberInputSettings(page, baseUrl);
        if (numberInputResult.skipped) {
            results.skip('Controls', 'Number Inputs', numberInputResult.message);
        } else {
            results.add('Controls', 'Number Inputs', numberInputResult.passed, numberInputResult.message);
        }

        const toggleResult = await SettingsControlsTests.toggleSwitchSettings(page, baseUrl);
        if (toggleResult.skipped) {
            results.skip('Controls', 'Toggles', toggleResult.message);
        } else {
            results.add('Controls', 'Toggles', toggleResult.passed, toggleResult.message);
        }

        const dropdownResult = await SettingsControlsTests.dropdownSelectSettings(page, baseUrl);
        if (dropdownResult.skipped) {
            results.skip('Controls', 'Dropdowns', dropdownResult.message);
        } else {
            results.add('Controls', 'Dropdowns', dropdownResult.passed, dropdownResult.message);
        }

        const toggleableResult = await SettingsControlsTests.toggleSwitchToggleable(page, baseUrl);
        if (toggleableResult.skipped) {
            results.skip('Controls', 'Toggle Works', toggleableResult.message);
        } else {
            results.add('Controls', 'Toggle Works', toggleableResult.passed, toggleableResult.message);
        }

        // Settings Save
        log.section('Settings Save');

        const saveResult = await SettingsSaveTests.saveButtonExists(page, baseUrl);
        if (saveResult.skipped) {
            results.skip('Save', 'Button Exists', saveResult.message);
        } else {
            results.add('Save', 'Button Exists', saveResult.passed, saveResult.message);
        }

        const resetResult = await SettingsSaveTests.resetToDefaultsButton(page, baseUrl);
        if (resetResult.skipped) {
            results.skip('Save', 'Reset Button', resetResult.message);
        } else {
            results.add('Save', 'Reset Button', resetResult.passed, resetResult.message);
        }

        const autoSaveResult = await SettingsSaveTests.autoSaveFunctionality(page, baseUrl);
        if (autoSaveResult.skipped) {
            results.skip('Save', 'Auto-Save', autoSaveResult.message);
        } else {
            results.add('Save', 'Auto-Save', autoSaveResult.passed, autoSaveResult.message);
        }

        // Settings Help
        log.section('Settings Help');

        const descResult = await SettingsHelpTests.settingDescriptions(page, baseUrl);
        if (descResult.skipped) {
            results.skip('Help', 'Descriptions', descResult.message);
        } else {
            results.add('Help', 'Descriptions', descResult.passed, descResult.message);
        }

        const tooltipResult = await SettingsHelpTests.tooltipsPresent(page, baseUrl);
        if (tooltipResult.skipped) {
            results.skip('Help', 'Tooltips', tooltipResult.message);
        } else {
            results.add('Help', 'Tooltips', tooltipResult.passed, tooltipResult.message);
        }

        // Raw Config
        log.section('Raw Config');

        const rawConfigResult = await RawConfigTests.rawConfigEditorExists(page, baseUrl);
        if (rawConfigResult.skipped) {
            results.skip('RawConfig', 'Editor Exists', rawConfigResult.message);
        } else {
            results.add('RawConfig', 'Editor Exists', rawConfigResult.passed, rawConfigResult.message);
        }

    } catch (error) {
        // Check if this is a navigation/browser error (not a real test failure)
        const isNavigationError = error.message &&
            (error.message.includes('context was destroyed') ||
             error.message.includes('Target closed') ||
             error.message.includes('Protocol error') ||
             error.message.includes('Session closed') ||
             error.message.includes('page has been closed'));

        if (isNavigationError) {
            log.warn(`Browser navigation error (test infrastructure issue): ${error.message}`);
            // Don't count as failure - this is a flaky test issue
        } else {
            log.error(`Fatal error: ${error.message}`);
            console.error(error.stack);
        }
    } finally {
        results.print();
        results.save();
        await teardownTest(ctx);
        process.exit(results.exitCode());
    }
}

// Run if executed directly
if (require.main === module) {
    main().catch(error => {
        console.error('Test runner failed:', error);
        process.exit(1);
    });
}

module.exports = { SettingsPageTests, SettingsTabsTests, SettingsControlsTests, SettingsSaveTests, SettingsHelpTests, RawConfigTests };
