/**
 * GroupingUtils — Shared scan grouping algorithms.
 *
 * Eliminates duplication of grouping logic across ScansPage, ScanSelector,
 * ReportsPage, and ScanStore.
 * Depends on: SeverityConfig, FormatUtils (must load first).
 *
 * CR-05 fix.
 */
var GroupingUtils = {

    // Severity search keywords shared by the ScansPage / ScanSelector search.
    SEVERITY_KEYWORDS: {
        low: ['low', 'minor', 'safe'],
        moderate: ['moderate', 'mod', 'medium'],
        high: ['high', 'elevated', 'risky'],
        critical: ['critical', 'severe', 'dangerous', 'urgent'],
    },

    /**
     * Group scans by roomName. Returns array of room objects sorted by
     * highest severity (desc), then latest timestamp (desc).
     *
     * Each room object: { roomName, scans, totalPct, avgPct, count, highestSeverity, latestTimestamp }
     */
    groupByRoom: function (scanList) {
        var rooms = {};
        for (var i = 0; i < scanList.length; i++) {
            var s = scanList[i];
            var name = s.roomName || 'Unassigned';
            if (!rooms[name]) {
                rooms[name] = { roomName: name, scans: [], totalPct: 0, latestTimestamp: 0, highestSeverity: 'low' };
            }
            rooms[name].scans.push(s);
            rooms[name].totalPct += s.percentage;
            if (s.timestamp > rooms[name].latestTimestamp) rooms[name].latestTimestamp = s.timestamp;
            if (SeverityConfig.order(s.severity) > SeverityConfig.order(rooms[name].highestSeverity)) {
                rooms[name].highestSeverity = s.severity;
            }
        }
        var result = [];
        for (var r in rooms) {
            var room = rooms[r];
            room.avgPct = Math.round(room.totalPct / room.scans.length);
            room.count = room.scans.length;
            result.push(room);
        }
        result.sort(function (a, b) {
            var diff = SeverityConfig.compare(a.highestSeverity, b.highestSeverity);
            return diff !== 0 ? diff : b.latestTimestamp - a.latestTimestamp;
        });
        return result;
    },

    /**
     * Group scans into Today / Yesterday / This Week / Older buckets.
     * Returns array of { label, scans } in that fixed order.
     */
    groupByDate: function (scanList) {
        var groups = {};
        var order = ['Today', 'Yesterday', 'This Week', 'Older'];
        for (var i = 0; i < scanList.length; i++) {
            var g = FormatUtils.dateGroup(scanList[i].timestamp);
            if (!groups[g]) groups[g] = [];
            groups[g].push(scanList[i]);
        }
        var result = [];
        for (var o = 0; o < order.length; o++) {
            if (groups[order[o]]) result.push({ label: order[o], scans: groups[order[o]] });
        }
        return result;
    },

    /**
     * Group scans by severity, most severe group first.
     * Returns array of { label, severity, scans }.
     */
    groupBySeverity: function (scanList) {
        var sevOrder = ['critical', 'high', 'moderate', 'low'];
        var groups = {};
        for (var i = 0; i < scanList.length; i++) {
            var sev = scanList[i].severity || 'low';
            if (!groups[sev]) groups[sev] = [];
            groups[sev].push(scanList[i]);
        }
        var result = [];
        for (var o = 0; o < sevOrder.length; o++) {
            if (groups[sevOrder[o]]) {
                var cfg = SeverityConfig.get(sevOrder[o]);
                result.push({ label: cfg.labelLong, severity: sevOrder[o], scans: groups[sevOrder[o]] });
            }
        }
        return result;
    },

    /**
     * Group scans by property. getPropertyById resolves property records.
     * Primary property first, then alphabetical; unassigned scans last.
     * Returns array of { label, isPrimary, scans }.
     */
    groupByProperty: function (scanList, getPropertyById) {
        var propMap = {};
        var unassigned = [];
        for (var i = 0; i < scanList.length; i++) {
            var s = scanList[i];
            if (!s.propertyId) { unassigned.push(s); continue; }
            if (!propMap[s.propertyId]) propMap[s.propertyId] = [];
            propMap[s.propertyId].push(s);
        }
        var result = [];
        for (var pid in propMap) {
            var prop = getPropertyById(pid);
            result.push({
                label: prop ? (prop.name || prop.address || 'Unnamed') : 'Unknown',
                isPrimary: prop ? prop.isPrimary : false,
                scans: propMap[pid],
            });
        }
        result.sort(function (a, b) {
            if (a.isPrimary && !b.isPrimary) return -1;
            if (!a.isPrimary && b.isPrimary) return 1;
            return a.label.localeCompare(b.label);
        });
        if (unassigned.length > 0) result.push({ label: 'Unassigned', isPrimary: false, scans: unassigned });
        return result;
    },

    /**
     * Create an accordion toggle function for a given setState function.
     * Returns a toggle(key) function that flips boolean keys in an object.
     *
     * Usage: var toggle = GroupingUtils.createAccordionToggle(setExpanded);
     *
     * CR-08 fix.
     */
    createAccordionToggle: function (setter) {
        return function (key) {
            setter(function (prev) {
                var next = {};
                for (var k in prev) { next[k] = prev[k]; }
                next[key] = !prev[key];
                return next;
            });
        };
    },
};

window.GroupingUtils = GroupingUtils;
