(function() {
    'use strict';
    // URL state sync module for ZDDC Archive

    // Default values for URL params
    var DEFAULT_SORT_FIELD = 'trackingNumber';
    var DEFAULT_SORT_DIRECTION = 'asc';
    var DEFAULT_ENABLED_TYPES = ['issued', 'received'];

    // Map URL param names to state paths
    var PARAM_MAP = {
        sort: 'sortField',
        dir: 'sortDirection',
        tn: 'columnFilters.trackingNumber',
        ti: 'columnFilters.title',
        rv: 'columnFilters.revisions',
        types: 'enabledFolderTypes',
        gf: 'groupingFilter',
        tf: 'transmittalFilter',
        projects: 'projectFilter',
        show: 'visibleProjects'
    };

    // Serialize current state to URL query string
    function serialize() {
        var params = new URLSearchParams();

        // Sort field
        if (window.app.sortField !== DEFAULT_SORT_FIELD) {
            params.set('sort', window.app.sortField);
        }

        // Sort direction
        if (window.app.sortDirection !== DEFAULT_SORT_DIRECTION) {
            params.set('dir', window.app.sortDirection);
        }

        // Column filters
        if (window.app.columnFilters.trackingNumber !== '') {
            params.set('tn', window.app.columnFilters.trackingNumber);
        }
        if (window.app.columnFilters.title !== '') {
            params.set('ti', window.app.columnFilters.title);
        }
        if (window.app.columnFilters.revisions !== '') {
            params.set('rv', window.app.columnFilters.revisions);
        }

        // Folder types (only if different from default [issued, received])
        var enabledTypes = Array.from(window.app.enabledFolderTypes).sort();
        var defaultTypes = DEFAULT_ENABLED_TYPES.slice().sort();
        if (JSON.stringify(enabledTypes) !== JSON.stringify(defaultTypes)) {
            params.set('types', enabledTypes.join(','));
        }

        // Grouping filter
        if (window.app.groupingFilter !== '') {
            params.set('gf', window.app.groupingFilter);
        }

        // Transmittal filter
        if (window.app.transmittalFilter !== '') {
            params.set('tf', window.app.transmittalFilter);
        }

        // Project filter — always preserved if set (for shareable URLs)
        if (window.app.projectFilter && window.app.projectFilter.size > 0) {
            params.set('projects', Array.from(window.app.projectFilter).join(','));
        }

        // Visibility filter (project picker). Emit only when it's a strict subset
        // of projectFilter — the common "everything visible" case keeps URLs clean.
        if (window.app.visibleProjects && window.app.projectFilter
            && window.app.projectFilter.size > 0) {
            var pfSize = window.app.projectFilter.size;
            var vp = Array.from(window.app.visibleProjects).filter(function(n) {
                return window.app.projectFilter.has(n);
            });
            if (vp.length < pfSize) {
                params.set('show', vp.slice().sort().join(','));
            }
        }

        // Build query string
        var qs = params.toString();
        return qs ? '?' + qs : '';
    }

    // Push state to URL without triggering popstate
    function push() {
        var result = serialize();
        if (result === location.search) {
            return;
        }
        try {
            history.replaceState(null, '', location.pathname + result);
        } catch (e) {
            // Silently swallow errors (e.g., file:// protocol restrictions)
        }
    }

    // Restore state from URL query string
    function restore() {
        var params = new URLSearchParams(location.search);

        // Restore sort field
        if (params.has('sort')) {
            var sortValue = params.get('sort');
            if (sortValue === 'trackingNumber' || sortValue === 'title') {
                window.app.sortField = sortValue;
            }
        }

        // Restore sort direction
        if (params.has('dir')) {
            var dirValue = params.get('dir');
            if (dirValue === 'asc' || dirValue === 'desc') {
                window.app.sortDirection = dirValue;
            }
        }

        // Restore column filters with AST parsing
        if (params.has('tn')) {
            var tnValue = params.get('tn');
            window.app.columnFilters.trackingNumber = tnValue;
            window.app.columnFilterASTs.trackingNumber = zddc.filter.parse(tnValue);
        }
        if (params.has('ti')) {
            var tiValue = params.get('ti');
            window.app.columnFilters.title = tiValue;
            window.app.columnFilterASTs.title = zddc.filter.parse(tiValue);
        }
        if (params.has('rv')) {
            var rvValue = params.get('rv');
            window.app.columnFilters.revisions = rvValue;
            window.app.columnFilterASTs.revisions = zddc.filter.parse(rvValue);
        }

        // Restore folder types
        if (params.has('types')) {
            var typesValue = params.get('types');
            var typeValues = typesValue.split(',').map(function(t) { return t.trim(); });
            // Validate against app.FOLDER_TYPE_NAMES
            var validTypes = typeValues.filter(function(t) {
                return window.app.FOLDER_TYPE_NAMES.indexOf(t) !== -1;
            });
            window.app.enabledFolderTypes = new Set(validTypes);
        }

        // Restore grouping filter
        if (params.has('gf')) {
            window.app.groupingFilter = params.get('gf');
        }

        // Restore transmittal filter
        if (params.has('tf')) {
            window.app.transmittalFilter = params.get('tf');
        }

        // Restore project filter
        if (params.has('projects')) {
            var projValue = params.get('projects');
            var projNames = projValue.split(',').map(function(p) { return p.trim(); }).filter(Boolean);
            window.app.projectFilter = new Set(projNames);
        }

        // Restore visibility filter. autoConnectHttpSource will intersect against
        // projectFilter / availableProjects after the project list resolves, so
        // dropping bogus names is handled there. We just parse here.
        if (params.has('show')) {
            var showValue = params.get('show');
            var showNames = showValue.split(',').map(function(p) { return p.trim(); }).filter(Boolean);
            window.app.visibleProjects = new Set(showNames);
        }

        // Update DOM inputs to reflect restored values
        updateFilterInputs();
    }

    // Update DOM filter inputs to match restored state
    function updateFilterInputs() {
        // Column filter inputs
        document.querySelectorAll('.column-filter[data-filter-field]').forEach(function(input) {
            var field = input.getAttribute('data-filter-field');
            var filterValue = window.app.columnFilters[field] || '';
            input.value = filterValue;
            if (filterValue !== '') {
                input.classList.add('filter-active');
            } else {
                input.classList.remove('filter-active');
            }
        });

        // Grouping filter
        var groupingFilterEl = document.getElementById('groupingFilter');
        if (groupingFilterEl) {
            groupingFilterEl.value = window.app.groupingFilter;
            if (window.app.groupingFilter !== '') {
                groupingFilterEl.classList.add('filter-active');
            } else {
                groupingFilterEl.classList.remove('filter-active');
            }
        }

        // Transmittal filter
        var transmittalFilterEl = document.getElementById('transmittalFilter');
        if (transmittalFilterEl) {
            transmittalFilterEl.value = window.app.transmittalFilter;
            if (window.app.transmittalFilter !== '') {
                transmittalFilterEl.classList.add('filter-active');
            } else {
                transmittalFilterEl.classList.remove('filter-active');
            }
        }
    }

    // Register module
    window.app.modules.urlState = {
        serialize: serialize,
        push: push,
        restore: restore
    };

})();
