#!/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, navigateTo, withTimeout } = require('./test_lib');

// ============================================================================
// Settings Page Structure Tests
// ============================================================================
const SettingsPageTests = {
    async settingsPageLoads(page, baseUrl) {
        await navigateTo(page, `${baseUrl}/settings`);

        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 navigateTo(page, `${baseUrl}/settings`);

        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 navigateTo(page, `${baseUrl}/settings`);

        // Wait for settings to load dynamically
        await delay(1000);

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

        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('.ldr-settings-item, .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('.ldr-settings-item, .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 navigateTo(page, `${baseUrl}/settings`);

        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 navigateTo(page, `${baseUrl}/settings`);

        // Gather tab info and before-content without clicking
        const preClick = await page.evaluate(() => {
            const tabs = document.querySelectorAll('.tab, .nav-tab, [role="tab"], .settings-tab, .nav-link');
            if (tabs.length < 2) return { hasTabs: false };

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

            return { hasTabs: true, beforeContent, tabText };
        });

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

        // Click the second tab; it may trigger a full page navigation or a JS content swap
        const tabSelector = '.tab, .nav-tab, [role="tab"], .settings-tab, .nav-link';
        let contentChanged;
        try {
            await Promise.all([
                page.waitForNavigation({ waitUntil: 'domcontentloaded', timeout: 10000 }),
                page.evaluate((sel) => {
                    const tabs = document.querySelectorAll(sel);
                    if (tabs[1]) tabs[1].click();
                }, tabSelector)
            ]);

            // Page may have navigated; wait for it to settle
            await delay(500);

            const afterContent = await page.evaluate(() => {
                const firstTabContent = document.querySelector('.tab-content, .tab-pane, [role="tabpanel"]');
                return firstTabContent?.textContent?.substring(0, 100) || '';
            });

            contentChanged = preClick.beforeContent !== afterContent;
        } catch (err) {
            if (err.message && (err.message.includes('context was destroyed') || err.message.includes('Navigation timeout'))) {
                // Context destroyed means navigation happened mid-flight.
                // Navigation timeout means the tab switched content via JS without a full navigation.
                // Both are acceptable — the tab click worked either way.
                try {
                    await page.waitForSelector('body', { timeout: 5000 });
                } catch (e) {
                    console.warn('waitForSelector("body") failed after tab click, page may still be usable:', e.message);
                }
                await delay(500);
                contentChanged = true;
            } else {
                throw err;
            }
        }

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

    async specificTabsPresent(page, baseUrl) {
        await navigateTo(page, `${baseUrl}/settings`);

        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 navigateTo(page, `${baseUrl}/settings`);
        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 navigateTo(page, `${baseUrl}/settings`);

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

            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 navigateTo(page, `${baseUrl}/settings`);
        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 navigateTo(page, `${baseUrl}/settings`);

        const result = await page.evaluate(() => {
            const selects = document.querySelectorAll(
                '.ldr-settings-item select, ' +
                '.settings select, ' +
                '.setting select, ' +
                'select[name]'
            );

            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 navigateTo(page, `${baseUrl}/settings`);

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

            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 navigateTo(page, `${baseUrl}/settings`);

        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 navigateTo(page, `${baseUrl}/settings`);

        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 navigateTo(page, `${baseUrl}/settings`);

        // 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 navigateTo(page, `${baseUrl}/settings`);
        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 navigateTo(page, `${baseUrl}/settings`);

        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 navigateTo(page, `${baseUrl}/settings`);

        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;

    const subTestTimeout = ctx.config.isCI ? 60000 : 30000;
    async function run(category, name, testFn) {
        try {
            const result = await withTimeout(
                testFn(page, baseUrl),
                subTestTimeout,
                `${category}/${name}`
            );
            if (result.skipped) {
                results.skip(category, name, result.message);
            } else {
                results.add(category, name, result.passed, result.message);
            }
        } catch (error) {
            results.add(category, name, false, `Error: ${error.message}`);
        }
    }

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

        await run('Page', 'Loads', (p, u) => SettingsPageTests.settingsPageLoads(p, u));
        await run('Page', 'Search Filter', (p, u) => SettingsPageTests.settingsSearchFilter(p, u));
        await run('Page', 'Search Filtering', (p, u) => SettingsPageTests.settingsSearchFiltering(p, u));

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

        await run('Tabs', 'Exist', (p, u) => SettingsTabsTests.settingsTabsExist(p, u));
        await run('Tabs', 'Navigation', (p, u) => SettingsTabsTests.tabNavigationWorks(p, u));
        await run('Tabs', 'Categories', (p, u) => SettingsTabsTests.specificTabsPresent(p, u));

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

        await run('Controls', 'Text Inputs', (p, u) => SettingsControlsTests.textInputSettings(p, u));
        await run('Controls', 'Number Inputs', (p, u) => SettingsControlsTests.numberInputSettings(p, u));
        await run('Controls', 'Toggles', (p, u) => SettingsControlsTests.toggleSwitchSettings(p, u));
        await run('Controls', 'Dropdowns', (p, u) => SettingsControlsTests.dropdownSelectSettings(p, u));
        await run('Controls', 'Toggle Works', (p, u) => SettingsControlsTests.toggleSwitchToggleable(p, u));

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

        await run('Save', 'Button Exists', (p, u) => SettingsSaveTests.saveButtonExists(p, u));
        await run('Save', 'Reset Button', (p, u) => SettingsSaveTests.resetToDefaultsButton(p, u));
        await run('Save', 'Auto-Save', (p, u) => SettingsSaveTests.autoSaveFunctionality(p, u));

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

        await run('Help', 'Descriptions', (p, u) => SettingsHelpTests.settingDescriptions(p, u));
        await run('Help', 'Tooltips', (p, u) => SettingsHelpTests.tooltipsPresent(p, u));

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

        await run('RawConfig', 'Editor Exists', (p, u) => RawConfigTests.rawConfigEditorExists(p, u));

    } catch (error) {
        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 };
