{% extends "base.html" %}

{% block title %}Resources - AWS Inventory Browser{% endblock %}

{% block content %}
<div class="flex flex-col h-full max-w-full overflow-hidden gap-2" x-data="{
    // Collapsible filters - collapsed by default to maximize table space
    filtersCollapsed: true,

    // Simple filter mode fields
    selectedTypes: [],
    selectedRegions: [],
    snapshot: '',
    search: '',
    showTypeDropdown: false,
    showRegionDropdown: false,

    // Group filter
    availableGroups: [],
    selectedGroupFilter: '',
    groupFilterMode: 'none',  // 'none', 'in_group', 'not_in_group'
    showGroupFilterDropdown: false,

    // Add to Group modal
    showAddToGroupModal: false,
    selectedResources: [],
    targetGroupName: '',
    addToGroupLoading: false,

    // Group members cache for advanced filter
    groupMembersCache: {},  // { groupName: Set of 'name|type' keys }

    toggleType(t) {
        const idx = this.selectedTypes.indexOf(t);
        if (idx === -1) this.selectedTypes.push(t);
        else this.selectedTypes.splice(idx, 1);
    },

    toggleRegion(r) {
        const idx = this.selectedRegions.indexOf(r);
        if (idx === -1) this.selectedRegions.push(r);
        else this.selectedRegions.splice(idx, 1);
    },

    // Advanced filter mode with nested groups
    advancedMode: false,
    // Root filter group - contains conditions and nested groups
    filterRoot: {
        logic: 'AND',
        items: []  // Each item is either {type:'condition',...} or {type:'group', logic:'AND/OR', items:[...]}
    },
    nextGroupId: 1,  // For generating unique IDs
    baseFilterFields: [
        { value: 'name', label: 'Name', type: 'text' },
        { value: 'arn', label: 'ARN', type: 'text' },
        { value: 'resource_type', label: 'Type', type: 'select' },
        { value: 'region', label: 'Region', type: 'select' },
        { value: 'snapshot_name', label: 'Snapshot', type: 'select' },
        { value: 'config_hash', label: 'Config Hash', type: 'text' },
        { value: 'group_membership', label: 'Group Membership', type: 'group' },
        { value: '_created_by', label: 'Created By', type: 'text', isTagField: true },
        { value: '_created_by_type', label: 'Creator Type', type: 'select', isTagField: true },
        { value: '_created_at', label: 'Creation Time', type: 'text', isTagField: true }
    ],
    availableTagKeys: [],
    fieldValues: {},  // Cache of available values per field
    loadingValues: {},  // Track loading state per field

    get filterFields() {
        // Combine base fields with dynamic tag fields
        const tagFields = this.availableTagKeys.map(key => ({
            value: 'tag:' + key,
            label: 'Tag: ' + key,
            type: 'select',
            isTag: true,
            tagKey: key
        }));
        return [...this.baseFilterFields, ...tagFields];
    },

    filterOperators: [
        { value: 'equals', label: 'equals', multi: false },
        { value: 'not_equals', label: 'does not equal', multi: false },
        { value: 'in', label: 'is one of', multi: true },
        { value: 'not_in', label: 'is not one of', multi: true },
        { value: 'contains', label: 'contains', multi: false },
        { value: 'contains_any', label: 'contains any of', multi: true },
        { value: 'not_contains', label: 'does not contain', multi: false },
        { value: 'starts_with', label: 'starts with', multi: false },
        { value: 'not_starts_with', label: 'does not start with', multi: false },
        { value: 'ends_with', label: 'ends with', multi: false },
        { value: 'not_ends_with', label: 'does not end with', multi: false },
        { value: 'is_empty', label: 'is empty', multi: false },
        { value: 'is_not_empty', label: 'is not empty', multi: false },
        { value: 'in_group', label: 'is in group', multi: false, groupOnly: true },
        { value: 'not_in_group', label: 'is not in group', multi: false, groupOnly: true }
    ],

    // Get operators available for a field type
    getOperatorsForField(fieldValue) {
        const field = this.filterFields.find(f => f.value === fieldValue);
        if (field && field.type === 'group') {
            return this.filterOperators.filter(op => op.groupOnly);
        }
        return this.filterOperators.filter(op => !op.groupOnly);
    },

    isMultiOperator(operator) {
        const op = this.filterOperators.find(o => o.value === operator);
        return op ? op.multi : false;
    },

    // UI state
    savedFilters: [],
    savedViews: [],
    showSaveFilterModal: false,
    showSaveViewModal: false,
    showColumnModal: false,
    filterName: '',
    filterDescription: '',
    viewName: '',
    viewDescription: '',
    sortBy: 'name',
    sortOrder: 'asc',
    baseColumns: [
        { field: 'name', label: 'Name', visible: true, isBase: true, width: 220, frozen: true },
        { field: 'arn', label: 'ARN', visible: true, isBase: true, width: 350, frozen: false },
        { field: 'resource_type', label: 'Type', visible: true, isBase: true, width: 160, frozen: false },
        { field: 'region', label: 'Region', visible: true, isBase: true, width: 130, frozen: false },
        { field: 'snapshot_name', label: 'Snapshot', visible: true, isBase: true, width: 180, frozen: false },
        { field: 'canonical_name', label: 'Canonical Name', visible: false, isBase: true, width: 200, frozen: false },
        { field: 'normalized_name', label: 'Normalized Name', visible: false, isBase: true, width: 200, frozen: false },
        { field: 'normalization_method', label: 'Normalization Method', visible: false, isBase: true, width: 150, frozen: false },
        { field: '_created_by', label: 'Created By', visible: false, isBase: true, width: 280, frozen: false, isTagField: true },
        { field: '_created_by_type', label: 'Creator Type', visible: false, isBase: true, width: 120, frozen: false, isTagField: true },
        { field: '_created_at', label: 'Creation Time', visible: false, isBase: true, width: 180, frozen: false, isTagField: true },
        { field: 'tags', label: 'All Tags', visible: false, isBase: true, width: 280, frozen: false },
        { field: 'created_at', label: 'Created', visible: false, isBase: true, width: 180, frozen: false },
        { field: 'config_hash', label: 'Config Hash', visible: false, isBase: true, width: 160, frozen: false }
    ],
    tagColumns: [],  // Dynamic tag columns

    // Column resize state
    resizingColumn: null,
    resizeStartX: 0,
    resizeStartWidth: 0,

    getColumnWidth(field) {
        const col = this.columns.find(c => c.field === field);
        return col ? col.width : 150;
    },

    setColumnWidth(field, width) {
        const minWidth = 80;
        const maxWidth = 600;
        const newWidth = Math.max(minWidth, Math.min(maxWidth, width));

        // Check in base columns
        let col = this.baseColumns.find(c => c.field === field);
        if (col) {
            col.width = newWidth;
            return;
        }
        // Check in tag columns
        col = this.tagColumns.find(c => c.field === field);
        if (col) col.width = newWidth;
    },

    get columns() {
        return [...this.baseColumns, ...this.tagColumns];
    },

    initTagColumns() {
        // Create tag columns from available tag keys
        this.tagColumns = this.availableTagKeys.map(key => ({
            field: 'tag:' + key,
            label: 'Tag: ' + key,
            visible: false,
            isTag: true,
            tagKey: key,
            width: 150,
            frozen: false
        }));
    },

    toggleFrozen(field) {
        let col = this.baseColumns.find(c => c.field === field);
        if (col) {
            col.frozen = !col.frozen;
            return;
        }
        col = this.tagColumns.find(c => c.field === field);
        if (col) col.frozen = !col.frozen;
    },
    currentViewId: null,
    resourceData: null,
    allResources: null,

    get visibleColumns() {
        return this.columns.filter(c => c.visible);
    },

    toggleColumn(field) {
        // Check in base columns first
        let col = this.baseColumns.find(c => c.field === field);
        if (col) {
            col.visible = !col.visible;
            return;
        }
        // Check in tag columns
        col = this.tagColumns.find(c => c.field === field);
        if (col) col.visible = !col.visible;
    },

    async loadFieldValues(field) {
        // Don't reload if already cached
        if (this.fieldValues[field]) return;

        this.loadingValues[field] = true;

        try {
            if (field === 'resource_type') {
                // Types: global across inventory (all snapshots)
                const resp = await fetch('/api/resources/types');
                const data = await resp.json();
                this.fieldValues[field] = data.types || [];
            } else if (field === 'region') {
                // Regions: global across inventory (all snapshots)
                const resp = await fetch('/api/resources/regions');
                const data = await resp.json();
                this.fieldValues[field] = data.regions || [];
            } else if (field === 'snapshot_name') {
                // Snapshots: always global
                const resp = await fetch('/api/snapshots');
                const data = await resp.json();
                this.fieldValues[field] = (data.snapshots || []).map(s => s.name);
            } else if (field.startsWith('tag:')) {
                // Tag values: global across inventory (all snapshots)
                const tagKey = field.substring(4);
                const resp = await fetch(`/api/resources/tags/values?key=${encodeURIComponent(tagKey)}`);
                const data = await resp.json();
                this.fieldValues[field] = data.values || [];
            }
        } catch (e) {
            console.error('Failed to load values for', field, e);
            this.fieldValues[field] = [];
        }
        this.loadingValues[field] = false;
    },

    getFieldType(field) {
        const f = this.filterFields.find(ff => ff.value === field);
        return f ? f.type : 'text';
    },

    setSort(field) {
        if (this.sortBy === field) {
            this.sortOrder = this.sortOrder === 'asc' ? 'desc' : 'asc';
        } else {
            this.sortBy = field;
            this.sortOrder = 'asc';
        }
        this.applySort();
    },

    applySort() {
        if (this.resourceData && this.resourceData.resources) {
            this.resourceData.resources.sort((a, b) => {
                let aVal = a[this.sortBy] || '';
                let bVal = b[this.sortBy] || '';
                if (typeof aVal === 'string') aVal = aVal.toLowerCase();
                if (typeof bVal === 'string') bVal = bVal.toLowerCase();
                if (aVal < bVal) return this.sortOrder === 'asc' ? -1 : 1;
                if (aVal > bVal) return this.sortOrder === 'asc' ? 1 : -1;
                return 0;
            });
        }
    },

    // Add a condition to a group (or root if no groupId)
    addCondition(group = null) {
        const targetGroup = group || this.filterRoot;
        targetGroup.items.push({
            type: 'condition',
            field: 'name',
            operator: 'contains',
            values: []  // Array for multi-select support
        });
    },

    // Add a nested group
    addGroup(parentGroup = null) {
        const targetGroup = parentGroup || this.filterRoot;
        targetGroup.items.push({
            type: 'group',
            id: this.nextGroupId++,
            logic: targetGroup.logic === 'AND' ? 'OR' : 'AND',  // Alternate logic
            items: []
        });
    },

    // Remove an item (condition or group) from a group
    removeItem(group, index) {
        group.items.splice(index, 1);
    },

    // Toggle value in multi-select
    toggleValue(condition, value) {
        const idx = condition.values.indexOf(value);
        if (idx === -1) {
            condition.values.push(value);
        } else {
            condition.values.splice(idx, 1);
        }
    },

    needsValue(operator) {
        return !['is_empty', 'is_not_empty'].includes(operator);
    },

    // Clear all filters
    clearFilters() {
        this.filterRoot = { logic: 'AND', items: [] };
    },

    // Load group members into cache for filtering
    async loadGroupMembersForFilter(groupName) {
        if (this.groupMembersCache[groupName]) return;

        try {
            const response = await fetch('/api/groups/' + encodeURIComponent(groupName) + '/members?limit=1000');
            if (response.ok) {
                const result = await response.json();
                // Create a Set of 'name|type' keys for fast lookup
                const memberSet = new Set();
                for (const member of result.members) {
                    memberSet.add(member.resource_name + '|' + member.resource_type);
                }
                this.groupMembersCache[groupName] = memberSet;
            }
        } catch (error) {
            console.error('Failed to load group members:', error);
            this.groupMembersCache[groupName] = new Set();
        }
    },

    // Check if resource is in a group (by name + type)
    isResourceInGroup(resource, groupName) {
        const memberSet = this.groupMembersCache[groupName];
        if (!memberSet) return false;

        const resourceName = resource.name || this.extractResourceName(resource.arn, resource.resource_type);
        const key = resourceName + '|' + resource.resource_type;
        return memberSet.has(key);
    },

    // Simple resource name extraction from ARN
    extractResourceName(arn, resourceType) {
        if (!arn) return '';
        const parts = arn.split(':');
        const lastPart = parts[parts.length - 1] || '';
        if (lastPart.includes('/')) {
            return lastPart.split('/').pop() || lastPart;
        }
        return lastPart;
    },

    // Evaluate a single condition against a resource
    evaluateCondition(resource, condition) {
        // Handle group_membership field specially
        if (condition.field === 'group_membership') {
            const groupName = condition.values[0];
            if (!groupName) return true;

            const isInGroup = this.isResourceInGroup(resource, groupName);
            if (condition.operator === 'in_group') {
                return isInGroup;
            } else if (condition.operator === 'not_in_group') {
                return !isInGroup;
            }
            return true;
        }

        // Get search values (array for multi-select)
        const searchValues = (condition.values || []).map(v => v.toLowerCase());
        const singleValue = searchValues[0] || '';

        // Get field value from resource
        let fieldValue = '';
        // Check if this is a tag field (either tag:KEY or a creator field like _created_by)
        const fieldDef = this.baseFilterFields.find(f => f.value === condition.field);
        if (condition.field.startsWith('tag:')) {
            const tagKey = condition.field.substring(4);
            const tags = resource.tags || {};
            fieldValue = (tags[tagKey] || '').toString().toLowerCase();
        } else if (fieldDef && fieldDef.isTagField) {
            // Creator fields are stored in tags
            const tags = resource.tags || {};
            fieldValue = (tags[condition.field] || '').toString().toLowerCase();
        } else if (condition.field === 'tag_key') {
            // Legacy: any tag key matches
            const tags = resource.tags || {};
            const tagKeys = Object.keys(tags).map(k => k.toLowerCase());
            return this.evaluateMultiField(tagKeys, condition.operator, searchValues);
        } else if (condition.field === 'tag_value') {
            // Legacy: any tag value matches
            const tags = resource.tags || {};
            const tagValues = Object.values(tags).map(v => (v || '').toString().toLowerCase());
            return this.evaluateMultiField(tagValues, condition.operator, searchValues);
        } else {
            fieldValue = (resource[condition.field] || '').toString().toLowerCase();
        }

        return this.evaluateOperator(fieldValue, condition.operator, searchValues, singleValue);
    },

    // Evaluate operator with support for multi-value conditions
    evaluateOperator(fieldValue, operator, searchValues, singleValue) {
        switch (operator) {
            case 'equals':
                return fieldValue === singleValue;
            case 'not_equals':
                return fieldValue !== singleValue;
            case 'in':
                return searchValues.includes(fieldValue);
            case 'not_in':
                return !searchValues.includes(fieldValue);
            case 'contains':
                return fieldValue.includes(singleValue);
            case 'contains_any':
                return searchValues.some(sv => fieldValue.includes(sv));
            case 'not_contains':
                return !fieldValue.includes(singleValue);
            case 'starts_with':
                return fieldValue.startsWith(singleValue);
            case 'not_starts_with':
                return !fieldValue.startsWith(singleValue);
            case 'ends_with':
                return fieldValue.endsWith(singleValue);
            case 'not_ends_with':
                return !fieldValue.endsWith(singleValue);
            case 'is_empty':
                return !fieldValue || fieldValue.trim() === '';
            case 'is_not_empty':
                return fieldValue && fieldValue.trim() !== '';
            default:
                return true;
        }
    },

    // Evaluate when field has multiple values (like tag keys/values)
    evaluateMultiField(fieldValues, operator, searchValues) {
        const singleValue = searchValues[0] || '';
        switch (operator) {
            case 'equals':
                return fieldValues.some(v => v === singleValue);
            case 'not_equals':
                return !fieldValues.some(v => v === singleValue);
            case 'in':
                return fieldValues.some(v => searchValues.includes(v));
            case 'not_in':
                return !fieldValues.some(v => searchValues.includes(v));
            case 'contains':
                return fieldValues.some(v => v.includes(singleValue));
            case 'contains_any':
                return fieldValues.some(fv => searchValues.some(sv => fv.includes(sv)));
            case 'not_contains':
                return !fieldValues.some(v => v.includes(singleValue));
            case 'starts_with':
                return fieldValues.some(v => v.startsWith(singleValue));
            case 'not_starts_with':
                return !fieldValues.some(v => v.startsWith(singleValue));
            case 'ends_with':
                return fieldValues.some(v => v.endsWith(singleValue));
            case 'not_ends_with':
                return !fieldValues.some(v => v.endsWith(singleValue));
            case 'is_empty':
                return fieldValues.length === 0;
            case 'is_not_empty':
                return fieldValues.length > 0;
            default:
                return true;
        }
    },

    // Recursively evaluate a filter group
    evaluateGroup(resource, group) {
        if (!group.items || group.items.length === 0) return true;

        const results = group.items.map(item => {
            if (item.type === 'group') {
                return this.evaluateGroup(resource, item);
            } else {
                return this.evaluateCondition(resource, item);
            }
        });

        if (group.logic === 'AND') {
            return results.every(r => r);
        } else {
            return results.some(r => r);
        }
    },

    // Collect all group names from filter conditions
    collectGroupNamesFromFilter(group) {
        const groupNames = [];
        for (const item of (group.items || [])) {
            if (item.type === 'group') {
                groupNames.push(...this.collectGroupNamesFromFilter(item));
            } else if (item.field === 'group_membership' && item.values && item.values[0]) {
                groupNames.push(item.values[0]);
            }
        }
        return groupNames;
    },

    async applyAdvancedFilter() {
        if (!this.allResources) return;

        if (!this.filterRoot.items || this.filterRoot.items.length === 0) {
            this.resourceData = { ...this.allResources };
            this.applySort();
            return;
        }

        // Pre-load group members for any group_membership conditions
        const groupNames = this.collectGroupNamesFromFilter(this.filterRoot);
        const uniqueGroups = [...new Set(groupNames)];
        await Promise.all(uniqueGroups.map(name => this.loadGroupMembersForFilter(name)));

        const filtered = this.allResources.resources.filter(resource => {
            return this.evaluateGroup(resource, this.filterRoot);
        });

        this.resourceData = {
            ...this.allResources,
            resources: filtered,
            count: filtered.length
        };
        this.applySort();
    },

    // Apply simple mode filters client-side (for multi-select)
    applySimpleFilter() {
        if (!this.allResources) return;

        let filtered = this.allResources.resources;

        // Filter by search term
        if (this.search) {
            const searchLower = this.search.toLowerCase();
            filtered = filtered.filter(r =>
                (r.name && r.name.toLowerCase().includes(searchLower)) ||
                (r.arn && r.arn.toLowerCase().includes(searchLower))
            );
        }

        // Filter by selected types
        if (this.selectedTypes.length > 0) {
            filtered = filtered.filter(r => this.selectedTypes.includes(r.resource_type));
        }

        // Filter by selected regions
        if (this.selectedRegions.length > 0) {
            filtered = filtered.filter(r => this.selectedRegions.includes(r.region));
        }

        this.resourceData = {
            ...this.allResources,
            resources: filtered,
            count: filtered.length
        };
        this.applySort();
    },

    // Count total conditions in filter tree
    countConditions(group = null) {
        const g = group || this.filterRoot;
        let count = 0;
        for (const item of g.items || []) {
            if (item.type === 'group') {
                count += this.countConditions(item);
            } else {
                count++;
            }
        }
        return count;
    },

    // Serialize a group for saving
    serializeGroup(group) {
        return {
            logic: group.logic,
            items: group.items.map(item => {
                if (item.type === 'group') {
                    return { type: 'group', ...this.serializeGroup(item) };
                } else {
                    return {
                        type: 'condition',
                        field: item.field,
                        operator: item.operator,
                        values: item.values || []
                    };
                }
            })
        };
    },

    // Deserialize a group from saved config
    deserializeGroup(config) {
        return {
            logic: config.logic || 'AND',
            items: (config.items || []).map(item => {
                if (item.type === 'group') {
                    return { type: 'group', id: this.nextGroupId++, ...this.deserializeGroup(item) };
                } else {
                    // Handle legacy single value format
                    let values = item.values || [];
                    if (values.length === 0 && item.value) {
                        values = [item.value];
                    }
                    return {
                        type: 'condition',
                        field: item.field,
                        operator: item.operator,
                        values: values
                    };
                }
            })
        };
    },

    getFilterConfig() {
        if (this.advancedMode) {
            return {
                version: 2,  // New nested format
                ...this.serializeGroup(this.filterRoot)
            };
        } else {
            return {
                version: 3,  // Simple mode with multi-select
                resource_types: this.selectedTypes.length > 0 ? [...this.selectedTypes] : null,
                regions: this.selectedRegions.length > 0 ? [...this.selectedRegions] : null,
                snapshot: this.snapshot || null,
                search: this.search || null
            };
        }
    },

    loadFilterConfig(config) {
        if (config.version === 2 || config.items) {
            // New nested format (advanced mode)
            this.advancedMode = true;
            this.filterRoot = this.deserializeGroup(config);
        } else if (config.conditions && config.conditions.length > 0) {
            // Legacy flat format - convert to new format
            this.advancedMode = true;
            this.filterRoot = {
                logic: config.logic || 'AND',
                items: config.conditions.map(c => ({
                    type: 'condition',
                    field: c.field,
                    operator: c.operator,
                    values: c.value ? [c.value] : []
                }))
            };
        } else if (config.version === 3) {
            // Simple mode with multi-select (v3)
            this.advancedMode = false;
            this.selectedTypes = config.resource_types || [];
            this.selectedRegions = config.regions || [];
            this.snapshot = config.snapshot || '';
            this.search = config.search || '';
        } else {
            // Legacy simple mode filter (single values)
            this.advancedMode = false;
            this.selectedTypes = config.resource_type ? [config.resource_type] : [];
            this.selectedRegions = config.region ? [config.region] : [];
            this.snapshot = config.snapshot || '';
            this.search = config.search || '';
        }
    },

    // Load available groups
    async loadGroups() {
        try {
            const resp = await fetch('/api/groups');
            const data = await resp.json();
            this.availableGroups = data.groups || [];
        } catch (e) {
            console.error('Failed to load groups:', e);
            this.availableGroups = [];
        }
    },

    // Set group filter
    setGroupFilter(mode, groupName) {
        this.groupFilterMode = mode;
        this.selectedGroupFilter = groupName;
        this.showGroupFilterDropdown = false;
    },

    // Clear group filter
    clearGroupFilter() {
        this.groupFilterMode = 'none';
        this.selectedGroupFilter = '';
    },

    // Update selected resources from Tabulator
    updateSelectedResources(resources) {
        this.selectedResources = resources || [];
    },

    // Add selected resources to group
    async addSelectedToGroup() {
        if (!this.targetGroupName || this.selectedResources.length === 0) return;

        this.addToGroupLoading = true;
        try {
            // Build list of resources with optional logical_id for stable CloudFormation matching
            const arns = this.selectedResources.map(r => {
                const item = {
                    arn: r.arn,
                    resource_type: r.resource_type
                };
                // Include CloudFormation logical ID if available for stable matching
                // across resource recreations (when ARN suffix changes)
                if (r.tags && r.tags['aws:cloudformation:logical-id']) {
                    item.logical_id = r.tags['aws:cloudformation:logical-id'];
                }
                return item;
            });
            const resp = await fetch(`/api/groups/${encodeURIComponent(this.targetGroupName)}/members`, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ arns: arns })
            });
            const result = await resp.json();

            if (result.added > 0) {
                // Show success notification
                const groupName = this.targetGroupName;
                this.showAddToGroupModal = false;
                this.targetGroupName = '';
                // Clear selection in Tabulator
                if (window.resourceTable) {
                    window.resourceTable.deselectRow();
                }
                this.selectedResources = [];
                // Reload groups to update counts
                this.loadGroups();
                alert('Added ' + result.added + ' resource(s) to group');
            } else if (result.skipped > 0) {
                alert('All ' + result.skipped + ' resource(s) already exist in the group.');
            }
        } catch (e) {
            console.error('Failed to add resources to group:', e);
            alert('Failed to add resources to group. Please try again.');
        }
        this.addToGroupLoading = false;
    },

    // Open add to group modal
    openAddToGroupModal() {
        this.targetGroupName = '';
        this.showAddToGroupModal = true;
    }
}">
    <!-- Header - Compact -->
    <div class="flex items-center justify-between flex-shrink-0">
        <h1 class="text-xl font-bold text-gray-900">Resource Explorer</h1>
        <div class="flex space-x-2">
            <button @click="showColumnModal = true" class="btn btn-secondary">
                <svg class="-ml-0.5 mr-2 h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 17V7m0 10a2 2 0 01-2 2H5a2 2 0 01-2-2V7a2 2 0 012-2h2a2 2 0 012 2m0 10a2 2 0 002 2h2a2 2 0 002-2M9 7a2 2 0 012-2h2a2 2 0 012 2m0 10V7m0 10a2 2 0 002 2h2a2 2 0 002-2V7a2 2 0 00-2-2h-2a2 2 0 00-2 2"/>
                </svg>
                Columns
            </button>
            <button @click="exportCSV()" class="btn btn-secondary">
                <svg class="-ml-0.5 mr-2 h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"/>
                </svg>
                CSV
            </button>
            <button @click="exportYAML()" class="btn btn-secondary">
                <svg class="-ml-0.5 mr-2 h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"/>
                </svg>
                YAML
            </button>
        </div>
    </div>

    <!-- Saved Views & Filters Bar - Compact single row -->
    <div class="bg-white shadow rounded-lg px-3 py-2 flex items-center gap-4 flex-shrink-0 text-sm">
        <div class="flex items-center gap-2">
            <span class="text-gray-500 font-medium">Views:</span>
            <div id="saved-views-list" hx-get="/api/views" hx-trigger="load" hx-swap="innerHTML" class="flex flex-wrap gap-1">
                <span class="text-gray-400">...</span>
            </div>
            <button @click="showSaveViewModal = true; viewName = ''; viewDescription = '';"
                    class="text-blue-600 hover:text-blue-500 text-xs">+ Save</button>
        </div>
        <div class="border-l border-gray-200 h-5"></div>
        <div class="flex items-center gap-2">
            <span class="text-gray-500 font-medium">Filters:</span>
            <div id="saved-filters-list" hx-get="/api/filters" hx-trigger="load" hx-swap="innerHTML" class="flex flex-wrap gap-1">
                <span class="text-gray-400">...</span>
            </div>
            <button @click="showSaveFilterModal = true; filterName = ''; filterDescription = '';"
                    class="text-blue-600 hover:text-blue-500 text-xs">+ Save</button>
        </div>
    </div>

    <!-- Filters -->
    <div class="bg-white shadow rounded-lg flex-shrink-0">
        <!-- Collapsible Header - Compact -->
        <div class="px-3 py-2 flex items-center justify-between cursor-pointer"
             :class="filtersCollapsed ? '' : 'border-b border-gray-200'"
             @click="filtersCollapsed = !filtersCollapsed">
            <div class="flex items-center gap-2">
                <svg class="h-4 w-4 text-gray-500 transition-transform duration-200"
                     :class="filtersCollapsed ? '' : 'rotate-90'"
                     fill="none" viewBox="0 0 24 24" stroke="currentColor">
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"/>
                </svg>
                <span class="text-sm font-medium text-gray-900">Filters</span>
                <span x-show="advancedMode && countConditions() > 0" class="text-xs text-gray-500 bg-gray-100 px-1.5 py-0.5 rounded-full">
                    <span x-text="countConditions()"></span> conditions
                </span>
                <span x-show="!advancedMode && (selectedTypes.length > 0 || selectedRegions.length > 0 || snapshot || search)"
                      class="text-xs text-blue-600 bg-blue-50 px-1.5 py-0.5 rounded-full">
                    Active
                </span>
            </div>
            <span class="text-xs text-gray-400" x-text="filtersCollapsed ? 'expand' : 'collapse'"></span>
        </div>

        <!-- Collapsible Content -->
        <div x-show="!filtersCollapsed" x-collapse class="p-4">
            <!-- Filter Mode Toggle -->
            <div class="flex items-center justify-between mb-4">
                <div class="flex items-center space-x-4">
                    <span class="text-sm font-medium text-gray-700">Filter Mode:</span>
                    <div class="flex rounded-md shadow-sm">
                        <button @click.stop="advancedMode = false"
                                :class="!advancedMode ? 'bg-blue-600 text-white' : 'bg-white text-gray-700 hover:bg-gray-50'"
                                class="px-4 py-2 text-sm font-medium rounded-l-md border border-gray-300">
                            Simple
                        </button>
                        <button @click.stop="advancedMode = true; if (filterRoot.items.length === 0) addCondition();"
                                :class="advancedMode ? 'bg-blue-600 text-white' : 'bg-white text-gray-700 hover:bg-gray-50'"
                                class="px-4 py-2 text-sm font-medium rounded-r-md border border-l-0 border-gray-300">
                            Advanced
                        </button>
                    </div>
                </div>
            </div>

        <!-- Simple Mode Filters -->
        <div x-show="!advancedMode" x-transition>
            <div class="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-6">
                <!-- Search -->
                <div class="lg:col-span-1">
                    <label for="search" class="block text-sm font-medium text-gray-700">Search</label>
                    <input type="text" name="search" id="search" x-model="search"
                           placeholder="Search by name or ARN..."
                           class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm">
                </div>

                <!-- Type Filter (Multi-select) -->
                <div class="relative" @click.away="showTypeDropdown = false">
                    <label class="block text-sm font-medium text-gray-700">Type</label>
                    <button type="button" @click="showTypeDropdown = !showTypeDropdown"
                            class="mt-1 relative w-full bg-white border border-gray-300 rounded-md shadow-sm pl-3 pr-10 py-2 text-left cursor-pointer focus:outline-none focus:ring-1 focus:ring-blue-500 focus:border-blue-500 sm:text-sm">
                        <span class="block truncate" x-text="selectedTypes.length === 0 ? 'All Types' : selectedTypes.length + ' selected'"></span>
                        <span class="absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none">
                            <svg class="h-5 w-5 text-gray-400" viewBox="0 0 20 20" fill="currentColor">
                                <path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd"/>
                            </svg>
                        </span>
                    </button>
                    <div x-show="showTypeDropdown" x-cloak
                         class="absolute z-20 mt-1 w-full bg-white shadow-lg max-h-60 rounded-md py-1 text-base ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none sm:text-sm">
                        <div class="px-3 py-2 border-b border-gray-200 flex justify-between items-center">
                            <span class="text-xs text-gray-500" x-text="selectedTypes.length + ' selected'"></span>
                            <button type="button" @click="selectedTypes = []" class="text-xs text-blue-600 hover:text-blue-800">Clear</button>
                        </div>
                        {% for t in resource_types %}
                        <label class="flex items-center px-3 py-2 hover:bg-gray-100 cursor-pointer">
                            <input type="checkbox" :checked="selectedTypes.includes('{{ t }}')" @change="toggleType('{{ t }}')"
                                   class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded">
                            <span class="ml-2 text-sm text-gray-700 truncate">{{ t }}</span>
                        </label>
                        {% endfor %}
                    </div>
                </div>

                <!-- Region Filter (Multi-select) -->
                <div class="relative" @click.away="showRegionDropdown = false">
                    <label class="block text-sm font-medium text-gray-700">Region</label>
                    <button type="button" @click="showRegionDropdown = !showRegionDropdown"
                            class="mt-1 relative w-full bg-white border border-gray-300 rounded-md shadow-sm pl-3 pr-10 py-2 text-left cursor-pointer focus:outline-none focus:ring-1 focus:ring-blue-500 focus:border-blue-500 sm:text-sm">
                        <span class="block truncate" x-text="selectedRegions.length === 0 ? 'All Regions' : selectedRegions.length + ' selected'"></span>
                        <span class="absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none">
                            <svg class="h-5 w-5 text-gray-400" viewBox="0 0 20 20" fill="currentColor">
                                <path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd"/>
                            </svg>
                        </span>
                    </button>
                    <div x-show="showRegionDropdown" x-cloak
                         class="absolute z-20 mt-1 w-full bg-white shadow-lg max-h-60 rounded-md py-1 text-base ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none sm:text-sm">
                        <div class="px-3 py-2 border-b border-gray-200 flex justify-between items-center">
                            <span class="text-xs text-gray-500" x-text="selectedRegions.length + ' selected'"></span>
                            <button type="button" @click="selectedRegions = []" class="text-xs text-blue-600 hover:text-blue-800">Clear</button>
                        </div>
                        {% for r in regions %}
                        <label class="flex items-center px-3 py-2 hover:bg-gray-100 cursor-pointer">
                            <input type="checkbox" :checked="selectedRegions.includes('{{ r }}')" @change="toggleRegion('{{ r }}')"
                                   class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded">
                            <span class="ml-2 text-sm text-gray-700">{{ r }}</span>
                        </label>
                        {% endfor %}
                    </div>
                </div>

                <!-- Snapshot Filter -->
                <div>
                    <label for="snapshot" class="block text-sm font-medium text-gray-700">Snapshot</label>
                    <select id="snapshot" name="snapshot" x-model="snapshot"
                            class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm">
                        <option value="">All Snapshots</option>
                        {% for s in snapshots %}
                        <option value="{{ s.name }}">{{ s.name }}</option>
                        {% endfor %}
                    </select>
                </div>

                <!-- Group Filter -->
                <div class="relative" @click.away="showGroupFilterDropdown = false" x-init="loadGroups()">
                    <label class="block text-sm font-medium text-gray-700">Group Filter</label>
                    <button type="button" @click="showGroupFilterDropdown = !showGroupFilterDropdown"
                            class="mt-1 relative w-full bg-white border border-gray-300 rounded-md shadow-sm pl-3 pr-10 py-2 text-left cursor-pointer focus:outline-none focus:ring-1 focus:ring-blue-500 focus:border-blue-500 sm:text-sm"
                            :class="groupFilterMode !== 'none' ? 'border-green-500 ring-1 ring-green-500' : ''">
                        <span class="block truncate">
                            <template x-if="groupFilterMode === 'none'">
                                <span class="text-gray-500">No Group Filter</span>
                            </template>
                            <template x-if="groupFilterMode === 'in_group'">
                                <span class="text-green-700">In: <span x-text="selectedGroupFilter"></span></span>
                            </template>
                            <template x-if="groupFilterMode === 'not_in_group'">
                                <span class="text-amber-700">Not In: <span x-text="selectedGroupFilter"></span></span>
                            </template>
                        </span>
                        <span class="absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none">
                            <svg class="h-5 w-5 text-gray-400" viewBox="0 0 20 20" fill="currentColor">
                                <path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd"/>
                            </svg>
                        </span>
                    </button>
                    <div x-show="showGroupFilterDropdown" x-cloak
                         class="absolute z-20 mt-1 w-64 bg-white shadow-lg rounded-md py-1 text-base ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none sm:text-sm max-h-80">
                        <!-- Clear option -->
                        <button type="button" @click="clearGroupFilter(); showGroupFilterDropdown = false; searchResources();"
                                class="w-full text-left px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 border-b border-gray-200">
                            <span class="font-medium">No Group Filter</span>
                        </button>

                        <!-- Groups list -->
                        <template x-if="availableGroups.length === 0">
                            <div class="px-3 py-4 text-center text-gray-500 text-sm">
                                <p>No groups available.</p>
                                <a href="/groups" class="text-blue-600 hover:text-blue-800 text-xs">Create a group</a>
                            </div>
                        </template>

                        <template x-for="group in availableGroups" :key="group.name">
                            <div class="border-b border-gray-100 last:border-0">
                                <div class="px-3 py-2 bg-gray-50">
                                    <span class="text-xs font-semibold text-gray-600" x-text="group.name"></span>
                                    <span class="text-xs text-gray-400 ml-1">(<span x-text="group.resource_count"></span> resources)</span>
                                </div>
                                <button type="button"
                                        @click="setGroupFilter('in_group', group.name); $nextTick(() => searchResources());"
                                        class="w-full text-left px-3 py-2 text-sm hover:bg-green-50 flex items-center"
                                        :class="groupFilterMode === 'in_group' && selectedGroupFilter === group.name ? 'bg-green-100 text-green-800' : 'text-gray-700'">
                                    <svg class="w-4 h-4 mr-2 text-green-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/>
                                    </svg>
                                    Show resources IN this group
                                </button>
                                <button type="button"
                                        @click="setGroupFilter('not_in_group', group.name); $nextTick(() => searchResources());"
                                        class="w-full text-left px-3 py-2 text-sm hover:bg-amber-50 flex items-center"
                                        :class="groupFilterMode === 'not_in_group' && selectedGroupFilter === group.name ? 'bg-amber-100 text-amber-800' : 'text-gray-700'">
                                    <svg class="w-4 h-4 mr-2 text-amber-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
                                    </svg>
                                    Show resources NOT in this group
                                </button>
                            </div>
                        </template>
                    </div>
                </div>
            </div>
        </div>

        <!-- Advanced Mode Filters with Nested Groups -->
        <div x-show="advancedMode" x-transition>
            <!-- Root Group -->
            <div class="border-2 border-gray-200 rounded-lg p-4 bg-gray-50">
                <!-- Root Logic Selector -->
                <div class="flex items-center justify-between mb-4">
                    <div class="flex items-center space-x-3">
                        <span class="text-sm font-medium text-gray-700">Match</span>
                        <select x-model="filterRoot.logic"
                                class="rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm font-medium"
                                :class="filterRoot.logic === 'AND' ? 'text-blue-700 bg-blue-50' : 'text-purple-700 bg-purple-50'">
                            <option value="AND">ALL of the following (AND)</option>
                            <option value="OR">ANY of the following (OR)</option>
                        </select>
                    </div>
                    <div class="flex space-x-2">
                        <button @click="addCondition(filterRoot)"
                                class="inline-flex items-center px-2 py-1 text-xs font-medium rounded bg-white border border-gray-300 text-gray-700 hover:bg-gray-50">
                            <svg class="h-3 w-3 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"/>
                            </svg>
                            Condition
                        </button>
                        <button @click="addGroup(filterRoot)"
                                class="inline-flex items-center px-2 py-1 text-xs font-medium rounded bg-white border border-gray-300 text-gray-700 hover:bg-gray-50">
                            <svg class="h-3 w-3 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10"/>
                            </svg>
                            Group
                        </button>
                    </div>
                </div>

                <!-- Items (conditions and nested groups) -->
                <div class="space-y-2">
                    <template x-for="(item, index) in filterRoot.items" :key="item.id || index">
                        <div>
                            <!-- Logic connector between items -->
                            <div x-show="index > 0" class="flex justify-center -my-1 relative z-10">
                                <span class="px-2 py-0.5 text-xs font-bold rounded-full"
                                      :class="filterRoot.logic === 'AND' ? 'bg-blue-100 text-blue-700' : 'bg-purple-100 text-purple-700'"
                                      x-text="filterRoot.logic"></span>
                            </div>

                            <!-- Nested Group -->
                            <template x-if="item.type === 'group'">
                                <div class="border-2 rounded-lg p-3 ml-4"
                                     :class="item.logic === 'AND' ? 'border-blue-200 bg-blue-50/50' : 'border-purple-200 bg-purple-50/50'">
                                    <div class="flex items-center justify-between mb-3">
                                        <div class="flex items-center space-x-2">
                                            <select x-model="item.logic"
                                                    class="rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 text-xs font-medium"
                                                    :class="item.logic === 'AND' ? 'text-blue-700 bg-blue-50' : 'text-purple-700 bg-purple-50'">
                                                <option value="AND">ALL (AND)</option>
                                                <option value="OR">ANY (OR)</option>
                                            </select>
                                        </div>
                                        <div class="flex space-x-1">
                                            <button @click="addCondition(item)"
                                                    class="p-1 text-gray-500 hover:text-gray-700 hover:bg-white rounded">
                                                <svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                                                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"/>
                                                </svg>
                                            </button>
                                            <button @click="addGroup(item)"
                                                    class="p-1 text-gray-500 hover:text-gray-700 hover:bg-white rounded">
                                                <svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                                                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10"/>
                                                </svg>
                                            </button>
                                            <button @click="removeItem(filterRoot, index)"
                                                    class="p-1 text-red-500 hover:text-red-700 hover:bg-red-50 rounded">
                                                <svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                                                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
                                                </svg>
                                            </button>
                                        </div>
                                    </div>
                                    <!-- Nested items -->
                                    <div class="space-y-2">
                                        <template x-for="(subItem, subIndex) in item.items" :key="subItem.id || subIndex">
                                            <div>
                                                <div x-show="subIndex > 0" class="flex justify-center -my-1 relative z-10">
                                                    <span class="px-1.5 py-0.5 text-xs font-bold rounded-full"
                                                          :class="item.logic === 'AND' ? 'bg-blue-100 text-blue-700' : 'bg-purple-100 text-purple-700'"
                                                          x-text="item.logic"></span>
                                                </div>
                                                <!-- Sub-condition row -->
                                                <template x-if="subItem.type === 'condition'">
                                                    <div class="flex items-center space-x-2 p-2 bg-white rounded-lg border border-gray-200">
                                                        <select x-model="subItem.field" @change="loadFieldValues(subItem.field)"
                                                                class="rounded border-gray-300 text-xs">
                                                            <template x-for="field in filterFields" :key="field.value">
                                                                <option :value="field.value" x-text="field.label"></option>
                                                            </template>
                                                        </select>
                                                        <select x-model="subItem.operator"
                                                                @change="if(getFieldType(subItem.field) === 'group') { subItem.values = []; }"
                                                                class="rounded border-gray-300 text-xs">
                                                            <template x-for="op in getOperatorsForField(subItem.field)" :key="op.value">
                                                                <option :value="op.value" x-text="op.label"></option>
                                                            </template>
                                                        </select>
                                                        <!-- Group selector for group_membership field -->
                                                        <template x-if="getFieldType(subItem.field) === 'group'">
                                                            <select x-model="subItem.values[0]"
                                                                    @change="if(!subItem.values[0]) subItem.values = []; else subItem.values = [subItem.values[0]]"
                                                                    class="flex-1 rounded border-gray-300 text-xs">
                                                                <option value="">Select group...</option>
                                                                <template x-for="g in availableGroups" :key="g.name">
                                                                    <option :value="g.name" x-text="g.name + ' (' + g.resource_count + ' resources)'"></option>
                                                                </template>
                                                            </select>
                                                        </template>
                                                        <!-- Multi-select for multi operators -->
                                                        <template x-if="needsValue(subItem.operator) && isMultiOperator(subItem.operator) && getFieldType(subItem.field) === 'select' && fieldValues[subItem.field]?.length > 0">
                                                            <div class="flex-1 relative" x-data="{ open: false }">
                                                                <button @click="open = !open" type="button"
                                                                        class="w-full text-left rounded border border-gray-300 px-2 py-1 text-xs bg-white flex items-center justify-between">
                                                                    <span x-text="subItem.values.length ? subItem.values.join(', ') : 'Select values...'"></span>
                                                                    <svg class="h-4 w-4 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                                                                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
                                                                    </svg>
                                                                </button>
                                                                <div x-show="open" @click.away="open = false"
                                                                     class="absolute z-20 mt-1 w-full bg-white border border-gray-300 rounded shadow-lg max-h-48 overflow-y-auto">
                                                                    <template x-for="val in fieldValues[subItem.field]" :key="val">
                                                                        <label class="flex items-center px-2 py-1 hover:bg-gray-50 cursor-pointer">
                                                                            <input type="checkbox" :checked="subItem.values.includes(val)"
                                                                                   @change="toggleValue(subItem, val)"
                                                                                   class="h-3 w-3 text-blue-600 rounded">
                                                                            <span class="ml-2 text-xs" x-text="val"></span>
                                                                        </label>
                                                                    </template>
                                                                </div>
                                                            </div>
                                                        </template>
                                                        <!-- Single select dropdown -->
                                                        <template x-if="needsValue(subItem.operator) && !isMultiOperator(subItem.operator) && getFieldType(subItem.field) === 'select' && fieldValues[subItem.field]?.length > 0">
                                                            <select x-model="subItem.values[0]" @change="if(!subItem.values[0]) subItem.values = []; else subItem.values = [subItem.values[0]]"
                                                                    class="flex-1 rounded border-gray-300 text-xs">
                                                                <option value="">Select...</option>
                                                                <template x-for="val in fieldValues[subItem.field]" :key="val">
                                                                    <option :value="val" x-text="val"></option>
                                                                </template>
                                                            </select>
                                                        </template>
                                                        <!-- Text input (exclude group type) -->
                                                        <template x-if="needsValue(subItem.operator) && getFieldType(subItem.field) !== 'group' && (getFieldType(subItem.field) !== 'select' || !fieldValues[subItem.field]?.length)">
                                                            <input type="text" x-model="subItem.values[0]"
                                                                   @input="subItem.values = subItem.values[0] ? [subItem.values[0]] : []"
                                                                   placeholder="Value..." class="flex-1 rounded border-gray-300 text-xs">
                                                        </template>
                                                        <button @click="removeItem(item, subIndex)"
                                                                class="p-1 text-red-500 hover:text-red-700 hover:bg-red-50 rounded">
                                                            <svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                                                                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
                                                            </svg>
                                                        </button>
                                                    </div>
                                                </template>
                                            </div>
                                        </template>
                                        <div x-show="item.items.length === 0" class="text-xs text-gray-400 text-center py-2">
                                            Empty group - add conditions
                                        </div>
                                    </div>
                                </div>
                            </template>

                            <!-- Condition Row -->
                            <template x-if="item.type === 'condition'">
                                <div class="flex items-center space-x-2 p-3 bg-white rounded-lg border border-gray-200">
                                    <!-- Field -->
                                    <select x-model="item.field"
                                            @change="loadFieldValues(item.field)"
                                            class="rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm">
                                        <template x-for="field in filterFields" :key="field.value">
                                            <option :value="field.value" x-text="field.label"></option>
                                        </template>
                                    </select>

                                    <!-- Operator -->
                                    <select x-model="item.operator"
                                            @change="if(getFieldType(item.field) === 'group') { item.values = []; }"
                                            class="rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm">
                                        <template x-for="op in getOperatorsForField(item.field)" :key="op.value">
                                            <option :value="op.value" x-text="op.label"></option>
                                        </template>
                                    </select>

                                    <!-- Group selector for group_membership field -->
                                    <template x-if="getFieldType(item.field) === 'group'">
                                        <select x-model="item.values[0]"
                                                @change="if(!item.values[0]) item.values = []; else item.values = [item.values[0]]"
                                                class="flex-1 rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm">
                                            <option value="">Select group...</option>
                                            <template x-for="g in availableGroups" :key="g.name">
                                                <option :value="g.name" x-text="g.name + ' (' + g.resource_count + ' resources)'"></option>
                                            </template>
                                        </select>
                                    </template>

                                    <!-- Multi-select dropdown for multi operators -->
                                    <template x-if="needsValue(item.operator) && isMultiOperator(item.operator) && getFieldType(item.field) === 'select' && fieldValues[item.field]?.length > 0">
                                        <div class="flex-1 relative" x-data="{ open: false }">
                                            <button @click="open = !open" type="button"
                                                    class="w-full text-left rounded-md border border-gray-300 shadow-sm px-3 py-2 bg-white text-sm flex items-center justify-between">
                                                <span class="truncate" x-text="item.values.length ? item.values.slice(0,3).join(', ') + (item.values.length > 3 ? ' +' + (item.values.length - 3) : '') : 'Select values...'"></span>
                                                <svg class="h-5 w-5 text-gray-400 flex-shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                                                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
                                                </svg>
                                            </button>
                                            <div x-show="open" @click.away="open = false"
                                                 class="absolute z-20 mt-1 w-full bg-white border border-gray-300 rounded-md shadow-lg max-h-60 overflow-y-auto">
                                                <template x-for="val in fieldValues[item.field]" :key="val">
                                                    <label class="flex items-center px-3 py-2 hover:bg-gray-50 cursor-pointer">
                                                        <input type="checkbox" :checked="item.values.includes(val)"
                                                               @change="toggleValue(item, val)"
                                                               class="h-4 w-4 text-blue-600 rounded border-gray-300">
                                                        <span class="ml-2 text-sm" x-text="val"></span>
                                                    </label>
                                                </template>
                                            </div>
                                        </div>
                                    </template>

                                    <!-- Single select dropdown -->
                                    <template x-if="needsValue(item.operator) && !isMultiOperator(item.operator) && getFieldType(item.field) === 'select' && fieldValues[item.field]?.length > 0">
                                        <select x-model="item.values[0]"
                                                @change="if(!item.values[0]) item.values = []; else item.values = [item.values[0]]"
                                                class="flex-1 rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm">
                                            <option value="">Select value...</option>
                                            <template x-for="val in fieldValues[item.field]" :key="val">
                                                <option :value="val" x-text="val"></option>
                                            </template>
                                        </select>
                                    </template>

                                    <!-- Text input for other fields (exclude group type) -->
                                    <template x-if="needsValue(item.operator) && getFieldType(item.field) !== 'group' && (getFieldType(item.field) !== 'select' || !fieldValues[item.field]?.length)">
                                        <input type="text"
                                               x-model="item.values[0]"
                                               @input="item.values = item.values[0] ? [item.values[0]] : []"
                                               placeholder="Enter value..."
                                               class="flex-1 rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm">
                                    </template>

                                    <!-- Loading indicator -->
                                    <span x-show="loadingValues[item.field]" class="text-gray-400">
                                        <svg class="animate-spin h-4 w-4" fill="none" viewBox="0 0 24 24">
                                            <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
                                            <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
                                        </svg>
                                    </span>

                                    <!-- Remove button -->
                                    <button @click="removeItem(filterRoot, index)"
                                            class="p-2 text-red-600 hover:text-red-800 hover:bg-red-50 rounded-md">
                                        <svg class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                                            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
                                        </svg>
                                    </button>
                                </div>
                            </template>
                        </div>
                    </template>

                    <!-- Empty state -->
                    <div x-show="filterRoot.items.length === 0" class="text-center py-8 text-gray-500">
                        <svg class="mx-auto h-12 w-12 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.293A1 1 0 013 6.586V4z"/>
                        </svg>
                        <p class="mt-2 text-sm">No filter conditions yet</p>
                        <p class="text-xs text-gray-400">Click "Condition" or "Group" above to start building your filter</p>
                    </div>
                </div>
            </div>
        </div>

            <div class="mt-4 flex items-center space-x-3">
                <button @click.stop="searchResources()" class="btn btn-primary">
                    <svg class="-ml-0.5 mr-2 h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/>
                    </svg>
                    Search
                </button>
                <button @click.stop="if (advancedMode) { clearFilters(); applyAdvancedFilter(); } else { selectedTypes = []; selectedRegions = []; snapshot = ''; search = ''; } clearGroupFilter(); searchResources();"
                        class="btn btn-secondary">
                    Clear
                </button>
            </div>
        </div>
    </div>

    <!-- Selection Toolbar -->
    <div x-show="selectedResources.length > 0" x-transition
         class="bg-blue-50 border border-blue-200 rounded-lg p-3 flex items-center justify-between flex-shrink-0">
        <div class="flex items-center space-x-3">
            <span class="inline-flex items-center justify-center w-8 h-8 rounded-full bg-blue-600 text-white font-bold text-sm" x-text="selectedResources.length"></span>
            <span class="text-blue-800 font-medium">resource(s) selected</span>
        </div>
        <div class="flex items-center space-x-2">
            <button @click="openAddToGroupModal()" class="btn btn-primary btn-sm">
                <svg class="-ml-0.5 mr-1.5 h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z"/>
                </svg>
                Add to Group
            </button>
            <button @click="selectedResources = []; if(window.resourceTable) window.resourceTable.deselectRow();" class="btn btn-secondary btn-sm">
                Clear Selection
            </button>
        </div>
    </div>

    <!-- Results -->
    <div class="card flex-1 min-h-0 flex flex-col overflow-hidden">
        <div id="resource-table" class="flex-1 min-h-0 overflow-auto">
            <div class="p-12 text-center text-gray-500">
                <div class="animate-spin rounded-full h-10 w-10 border-b-2 border-blue-600 mx-auto"></div>
                <p class="mt-4 font-medium">Loading resources...</p>
            </div>
        </div>
    </div>

    <!-- Column Customization Modal -->
    <div x-show="showColumnModal" x-cloak class="fixed z-10 inset-0 overflow-y-auto">
        <div class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
            <div class="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" @click="showColumnModal = false"></div>
            <div class="inline-block align-bottom bg-white rounded-xl px-4 pt-5 pb-4 text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-2xl sm:w-full sm:p-6">
                <div class="flex items-center justify-between mb-4">
                    <h3 class="text-lg font-semibold text-gray-900">Customize Columns</h3>
                    <button @click="showColumnModal = false" class="text-gray-400 hover:text-gray-600">
                        <svg class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
                        </svg>
                    </button>
                </div>

                <!-- Legend -->
                <div class="flex items-center gap-6 text-xs text-gray-500 mb-4 pb-3 border-b">
                    <div class="flex items-center gap-1.5">
                        <div class="w-3 h-3 rounded border-2 border-blue-500 bg-blue-50"></div>
                        <span>Visible</span>
                    </div>
                    <div class="flex items-center gap-1.5">
                        <svg class="w-3.5 h-3.5 text-amber-500" fill="currentColor" viewBox="0 0 20 20">
                            <path d="M5 4a2 2 0 012-2h6a2 2 0 012 2v14l-5-2.5L5 18V4z"/>
                        </svg>
                        <span>Frozen (sticky when scrolling)</span>
                    </div>
                </div>

                <div class="space-y-4 max-h-80 overflow-y-auto pr-2">
                    <!-- Base Columns -->
                    <div>
                        <h4 class="text-xs font-semibold text-gray-500 uppercase tracking-wider mb-3">Resource Fields</h4>
                        <div class="grid grid-cols-2 gap-2">
                            <template x-for="col in baseColumns" :key="col.field">
                                <div class="flex items-center justify-between p-2.5 rounded-lg border transition-all"
                                     :class="col.visible ? 'bg-blue-50 border-blue-200' : 'bg-gray-50 border-gray-200'">
                                    <label class="flex items-center flex-1 cursor-pointer">
                                        <input type="checkbox" :checked="col.visible" @change="toggleColumn(col.field)"
                                               class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded">
                                        <span class="ml-2.5 text-sm font-medium" :class="col.visible ? 'text-gray-900' : 'text-gray-500'" x-text="col.label"></span>
                                    </label>
                                    <button @click="toggleFrozen(col.field)" x-show="col.visible"
                                            class="p-1 rounded hover:bg-white/50 transition-colors"
                                            :class="col.frozen ? 'text-amber-500' : 'text-gray-300 hover:text-gray-400'"
                                            :title="col.frozen ? 'Unfreeze column' : 'Freeze column'">
                                        <svg class="w-4 h-4" fill="currentColor" viewBox="0 0 20 20">
                                            <path d="M5 4a2 2 0 012-2h6a2 2 0 012 2v14l-5-2.5L5 18V4z"/>
                                        </svg>
                                    </button>
                                </div>
                            </template>
                        </div>
                    </div>

                    <!-- Tag Columns -->
                    <div x-show="tagColumns.length > 0">
                        <h4 class="text-xs font-semibold text-gray-500 uppercase tracking-wider mb-2">Tag Columns</h4>
                        <p class="text-xs text-gray-400 mb-3">Show individual tag values as separate columns</p>
                        <div class="grid grid-cols-2 gap-2">
                            <template x-for="col in tagColumns" :key="col.field">
                                <div class="flex items-center justify-between p-2.5 rounded-lg border transition-all"
                                     :class="col.visible ? 'bg-indigo-50 border-indigo-200' : 'bg-gray-50 border-gray-200'">
                                    <label class="flex items-center flex-1 cursor-pointer">
                                        <input type="checkbox" :checked="col.visible" @change="toggleColumn(col.field)"
                                               class="h-4 w-4 text-indigo-600 focus:ring-indigo-500 border-gray-300 rounded">
                                        <span class="ml-2.5 text-sm" :class="col.visible ? 'text-indigo-700 font-medium' : 'text-gray-500'" x-text="col.tagKey"></span>
                                    </label>
                                    <button @click="toggleFrozen(col.field)" x-show="col.visible"
                                            class="p-1 rounded hover:bg-white/50 transition-colors"
                                            :class="col.frozen ? 'text-amber-500' : 'text-gray-300 hover:text-gray-400'"
                                            :title="col.frozen ? 'Unfreeze column' : 'Freeze column'">
                                        <svg class="w-4 h-4" fill="currentColor" viewBox="0 0 20 20">
                                            <path d="M5 4a2 2 0 012-2h6a2 2 0 012 2v14l-5-2.5L5 18V4z"/>
                                        </svg>
                                    </button>
                                </div>
                            </template>
                        </div>
                        <p x-show="tagColumns.length === 0" class="text-xs text-gray-400 italic">No tags found in inventory</p>
                    </div>
                </div>

                <div class="mt-5 pt-4 border-t flex justify-end gap-3">
                    <button @click="showColumnModal = false" class="btn btn-secondary">Cancel</button>
                    <button @click="showColumnModal = false; rebuildTable()" class="btn btn-primary">Apply Changes</button>
                </div>
            </div>
        </div>
    </div>

    <!-- Save Filter Modal -->
    <div x-show="showSaveFilterModal" x-cloak class="fixed z-10 inset-0 overflow-y-auto">
        <div class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
            <div class="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" @click="showSaveFilterModal = false"></div>
            <div class="inline-block align-bottom bg-white rounded-lg px-4 pt-5 pb-4 text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full sm:p-6">
                <h3 class="text-lg font-medium text-gray-900 mb-4">Save Filter</h3>
                <div class="space-y-4">
                    <div>
                        <label class="block text-sm font-medium text-gray-700">Name</label>
                        <input type="text" x-model="filterName" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm">
                    </div>
                    <div>
                        <label class="block text-sm font-medium text-gray-700">Description (optional)</label>
                        <textarea x-model="filterDescription" rows="2" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm"></textarea>
                    </div>
                    <div class="bg-gray-50 rounded-md p-3">
                        <p class="text-xs text-gray-500 uppercase tracking-wide mb-2">Filter Configuration</p>
                        <div x-show="advancedMode">
                            <span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-green-100 text-green-800">
                                Advanced Filter
                            </span>
                            <p class="text-sm text-gray-700 mt-1">
                                <span class="font-medium" x-text="filterRoot.logic"></span> logic with
                                <span x-text="countConditions()"></span> condition(s)
                            </p>
                            <p class="text-xs text-gray-500 mt-1" x-show="filterRoot.items.some(i => i.type === 'group')">
                                Includes nested groups
                            </p>
                        </div>
                        <div x-show="!advancedMode">
                            <span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-blue-100 text-blue-800">
                                Simple Filter
                            </span>
                            <ul class="mt-2 text-xs text-gray-600 space-y-1">
                                <li x-show="selectedTypes.length > 0"><span class="font-medium">Types:</span> <span x-text="selectedTypes.join(', ')"></span></li>
                                <li x-show="selectedRegions.length > 0"><span class="font-medium">Regions:</span> <span x-text="selectedRegions.join(', ')"></span></li>
                                <li x-show="snapshot"><span class="font-medium">Snapshot:</span> <span x-text="snapshot"></span></li>
                                <li x-show="search"><span class="font-medium">Search:</span> <span x-text="search"></span></li>
                                <li x-show="selectedTypes.length === 0 && selectedRegions.length === 0 && !snapshot && !search" class="text-gray-400">No filters applied</li>
                            </ul>
                        </div>
                    </div>
                </div>
                <div class="mt-5 pt-4 border-t sm:flex sm:flex-row-reverse gap-3">
                    <button @click="saveFilter()" :disabled="!filterName.trim()" class="btn btn-primary disabled:opacity-50 w-full sm:w-auto">
                        Save Filter
                    </button>
                    <button @click="showSaveFilterModal = false" class="btn btn-secondary mt-3 sm:mt-0 w-full sm:w-auto">
                        Cancel
                    </button>
                </div>
            </div>
        </div>
    </div>

    <!-- Save View Modal -->
    <div x-show="showSaveViewModal" x-cloak class="fixed z-10 inset-0 overflow-y-auto">
        <div class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
            <div class="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" @click="showSaveViewModal = false"></div>
            <div class="inline-block align-bottom bg-white rounded-lg px-4 pt-5 pb-4 text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full sm:p-6">
                <h3 class="text-lg font-medium text-gray-900 mb-4">Save View</h3>
                <p class="text-sm text-gray-500 mb-4">Save the current column selection, sorting, and filters as a reusable view.</p>
                <div class="space-y-4">
                    <div>
                        <label class="block text-sm font-medium text-gray-700">Name</label>
                        <input type="text" x-model="viewName" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm">
                    </div>
                    <div>
                        <label class="block text-sm font-medium text-gray-700">Description (optional)</label>
                        <textarea x-model="viewDescription" rows="2" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm"></textarea>
                    </div>
                    <div class="bg-gray-50 rounded-md p-3">
                        <p class="text-xs text-gray-500 uppercase tracking-wide mb-2">View Configuration</p>
                        <div class="text-sm text-gray-700 space-y-1">
                            <p><span class="font-medium">Columns:</span> <span x-text="visibleColumns.map(c => c.label).join(', ')"></span></p>
                            <p><span class="font-medium">Sort:</span> <span x-text="sortBy + ' (' + sortOrder + ')'"></span></p>
                            <div class="mt-2 pt-2 border-t border-gray-200">
                                <p class="font-medium mb-1">Filters:</p>
                                <div x-show="advancedMode">
                                    <span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-green-100 text-green-800">
                                        Advanced (<span x-text="countConditions()"></span> conditions, <span x-text="filterRoot.logic"></span>)
                                    </span>
                                </div>
                                <div x-show="!advancedMode">
                                    <span x-show="selectedTypes.length > 0 || selectedRegions.length > 0 || snapshot || search" class="text-xs text-gray-600">
                                        <span x-show="selectedTypes.length > 0">Types: <span x-text="selectedTypes.join(', ')"></span></span>
                                        <span x-show="selectedTypes.length > 0 && (selectedRegions.length > 0 || snapshot || search)">, </span>
                                        <span x-show="selectedRegions.length > 0">Regions: <span x-text="selectedRegions.join(', ')"></span></span>
                                        <span x-show="selectedRegions.length > 0 && (snapshot || search)">, </span>
                                        <span x-show="snapshot">Snapshot: <span x-text="snapshot"></span></span>
                                        <span x-show="snapshot && search">, </span>
                                        <span x-show="search">Search: <span x-text="search"></span></span>
                                    </span>
                                    <span x-show="selectedTypes.length === 0 && selectedRegions.length === 0 && !snapshot && !search" class="text-xs text-gray-400">No filters</span>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
                <div class="mt-5 pt-4 border-t sm:flex sm:flex-row-reverse gap-3">
                    <button @click="saveView()" :disabled="!viewName.trim()" class="btn btn-primary disabled:opacity-50 w-full sm:w-auto">
                        Save View
                    </button>
                    <button @click="showSaveViewModal = false" class="btn btn-secondary mt-3 sm:mt-0 w-full sm:w-auto">
                        Cancel
                    </button>
                </div>
            </div>
        </div>
    </div>

    <!-- Add to Group Modal -->
    <div x-show="showAddToGroupModal" x-cloak class="fixed z-10 inset-0 overflow-y-auto">
        <div class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
            <div class="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" @click="showAddToGroupModal = false"></div>
            <div class="inline-block align-bottom bg-white rounded-lg px-4 pt-5 pb-4 text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full sm:p-6">
                <div class="flex items-center mb-4">
                    <div class="flex-shrink-0 h-10 w-10 rounded-full bg-blue-100 flex items-center justify-center">
                        <svg class="h-6 w-6 text-blue-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z"/>
                        </svg>
                    </div>
                    <div class="ml-3">
                        <h3 class="text-lg font-medium text-gray-900">Add to Resource Group</h3>
                        <p class="text-sm text-gray-500">Add <span x-text="selectedResources.length" class="font-semibold"></span> resource(s) to a group</p>
                    </div>
                </div>

                <div class="space-y-4">
                    <!-- Select Group -->
                    <div>
                        <label class="block text-sm font-medium text-gray-700 mb-2">Select Group</label>
                        <template x-if="availableGroups.length === 0">
                            <div class="bg-gray-50 rounded-lg p-4 text-center">
                                <svg class="mx-auto h-8 w-8 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z"/>
                                </svg>
                                <p class="mt-2 text-sm text-gray-500">No groups available</p>
                                <a href="/groups" class="mt-2 inline-block text-sm text-blue-600 hover:text-blue-800">Create a group first</a>
                            </div>
                        </template>
                        <template x-if="availableGroups.length > 0">
                            <div class="space-y-2 max-h-60 overflow-y-auto">
                                <template x-for="group in availableGroups" :key="group.name">
                                    <label class="flex items-center p-3 rounded-lg border cursor-pointer transition-colors"
                                           :class="targetGroupName === group.name ? 'border-blue-500 bg-blue-50' : 'border-gray-200 hover:bg-gray-50'">
                                        <input type="radio" name="targetGroup" :value="group.name" x-model="targetGroupName"
                                               class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300">
                                        <div class="ml-3 flex-1">
                                            <div class="flex items-center justify-between">
                                                <span class="text-sm font-medium text-gray-900" x-text="group.name"></span>
                                                <span class="text-xs text-gray-500"><span x-text="group.resource_count"></span> resources</span>
                                            </div>
                                            <p class="text-xs text-gray-500 mt-0.5" x-show="group.description" x-text="group.description"></p>
                                        </div>
                                    </label>
                                </template>
                            </div>
                        </template>
                    </div>

                    <!-- Selected Resources Preview -->
                    <div class="bg-gray-50 rounded-lg p-3">
                        <p class="text-xs text-gray-500 uppercase tracking-wide mb-2">Selected Resources</p>
                        <div class="max-h-32 overflow-y-auto space-y-1">
                            <template x-for="(resource, idx) in selectedResources.slice(0, 5)" :key="resource.arn">
                                <div class="text-sm text-gray-700 flex items-center">
                                    <span class="w-4 h-4 flex items-center justify-center bg-blue-100 text-blue-600 rounded text-xs font-bold mr-2" x-text="idx + 1"></span>
                                    <span class="truncate" x-text="resource.name || resource.arn"></span>
                                </div>
                            </template>
                            <p x-show="selectedResources.length > 5" class="text-xs text-gray-400 pl-6">
                                ... and <span x-text="selectedResources.length - 5"></span> more
                            </p>
                        </div>
                    </div>

                    <p class="text-xs text-gray-500">
                        Resources are matched by Name + Type. Duplicates will be skipped.
                    </p>
                </div>

                <div class="mt-5 pt-4 border-t sm:flex sm:flex-row-reverse gap-3">
                    <button @click="addSelectedToGroup()" :disabled="!targetGroupName || addToGroupLoading"
                            class="btn btn-primary disabled:opacity-50 w-full sm:w-auto">
                        <span x-show="addToGroupLoading" class="mr-2">
                            <svg class="animate-spin h-4 w-4 text-white inline" fill="none" viewBox="0 0 24 24">
                                <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
                                <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
                            </svg>
                        </span>
                        Add to Group
                    </button>
                    <button @click="showAddToGroupModal = false" class="btn btn-secondary mt-3 sm:mt-0 w-full sm:w-auto">
                        Cancel
                    </button>
                </div>
            </div>
        </div>
    </div>
</div>
{% endblock %}

{% block scripts %}
<script>
    // Tabulator instance
    let resourceTable = null;

    // Wait for Alpine to be ready before initializing
    document.addEventListener('DOMContentLoaded', function() {
        requestAnimationFrame(function() {
            requestAnimationFrame(function() {
                searchResources();
                loadTagKeys();
            });
        });
    });

    document.body.addEventListener('htmx:afterSwap', function(evt) {
        if (evt.detail.target.id === 'saved-views-list') {
            const data = JSON.parse(evt.detail.xhr.responseText);
            renderSavedViewsChips(data.views || [], evt.detail.target);
        }
        if (evt.detail.target.id === 'saved-filters-list') {
            const data = JSON.parse(evt.detail.xhr.responseText);
            renderSavedFiltersChips(data.filters || [], evt.detail.target);
        }
    });

    // Check if filter tree has any tag conditions
    function hasTagConditionsInGroup(group) {
        if (!group || !group.items) return false;
        return group.items.some(item => {
            if (item.type === 'group') {
                return hasTagConditionsInGroup(item);
            } else {
                return item.field === 'tag_key' || item.field === 'tag_value' || item.field.startsWith('tag:');
            }
        });
    }

    function searchResources() {
        const data = Alpine.$data(document.querySelector('[x-data]'));

        // Clear selected resources when searching
        data.selectedResources = [];

        // Check if using group filter
        if (data.groupFilterMode !== 'none' && data.selectedGroupFilter) {
            searchResourcesWithGroupFilter(data);
            return;
        }

        const params = new URLSearchParams();

        const tagsColumnVisible = data.columns.find(c => c.field === 'tags')?.visible;
        const anyTagColumnVisible = data.columns.some(c => (c.field.startsWith('tag:') || c.isTagField) && c.visible);
        const hasTagConditions = data.advancedMode && hasTagConditionsInGroup(data.filterRoot);

        const useClientSideFilter = data.advancedMode ||
            data.selectedTypes.length > 1 ||
            data.selectedRegions.length > 1;

        if (!useClientSideFilter) {
            if (data.search) params.append('q', data.search);
            if (data.selectedTypes.length === 1) params.append('type', data.selectedTypes[0]);
            if (data.selectedRegions.length === 1) params.append('region', data.selectedRegions[0]);
            if (data.snapshot) params.append('snapshot', data.snapshot);
        } else if (!data.advancedMode) {
            if (data.snapshot) params.append('snapshot', data.snapshot);
        }

        if (tagsColumnVisible || anyTagColumnVisible || hasTagConditions) {
            params.append('include_tags', 'true');
        }

        params.append('limit', '500');

        fetch('/api/resources?' + params.toString())
            .then(r => r.json())
            .then(result => {
                data.allResources = result;

                if (data.advancedMode) {
                    data.applyAdvancedFilter();
                } else if (useClientSideFilter) {
                    data.applySimpleFilter();
                } else {
                    data.resourceData = result;
                    data.applySort();
                }
                renderTable();
            });
    }

    function searchResourcesWithGroupFilter(data) {
        const groupName = encodeURIComponent(data.selectedGroupFilter);
        const endpoint = data.groupFilterMode === 'in_group'
            ? `/api/groups/${groupName}/resources/in`
            : `/api/groups/${groupName}/resources/not-in`;

        const params = new URLSearchParams();
        if (data.snapshot) {
            params.append('snapshot', data.snapshot);
        }
        params.append('limit', '500');

        const tagsColumnVisible = data.columns.find(c => c.field === 'tags')?.visible;
        const anyTagColumnVisible = data.columns.some(c => (c.field.startsWith('tag:') || c.isTagField) && c.visible);
        if (tagsColumnVisible || anyTagColumnVisible) {
            params.append('include_tags', 'true');
        }

        fetch(`${endpoint}?${params.toString()}`)
            .then(r => r.json())
            .then(result => {
                // Apply additional client-side filters if needed
                let resources = result.resources || [];

                // Apply search filter
                if (data.search) {
                    const searchLower = data.search.toLowerCase();
                    resources = resources.filter(r =>
                        (r.name && r.name.toLowerCase().includes(searchLower)) ||
                        (r.arn && r.arn.toLowerCase().includes(searchLower))
                    );
                }

                // Apply type filter
                if (data.selectedTypes.length > 0) {
                    resources = resources.filter(r => data.selectedTypes.includes(r.resource_type));
                }

                // Apply region filter
                if (data.selectedRegions.length > 0) {
                    resources = resources.filter(r => data.selectedRegions.includes(r.region));
                }

                data.allResources = { resources: resources, count: resources.length };
                data.resourceData = { resources: resources, count: resources.length };
                data.applySort();
                renderTable();
            });
    }

    // Build Tabulator column definitions from Alpine data
    function buildColumns() {
        const data = Alpine.$data(document.querySelector('[x-data]'));
        const columns = [];

        data.visibleColumns.forEach(col => {
            const colDef = {
                title: col.label,
                field: col.field,
                minWidth: col.width || 100,
                resizable: true,
                frozen: col.frozen || false,
                headerSort: true,
                tooltip: true
            };

            // Custom formatters for different field types
            if (col.field === 'name') {
                colDef.formatter = function(cell) {
                    const value = cell.getValue() || 'N/A';
                    const initial = (value || 'N').charAt(0).toUpperCase();
                    return `<div class="flex items-center">
                        <div class="flex-shrink-0 h-7 w-7 bg-gradient-to-br from-blue-400 to-blue-600 rounded-lg flex items-center justify-center">
                            <span class="text-white text-xs font-bold">${initial}</span>
                        </div>
                        <span class="ml-2.5 font-medium text-gray-900 truncate">${value}</span>
                    </div>`;
                };
                colDef.cssClass = "tabulator-cell-name";
            } else if (col.field === 'arn') {
                colDef.formatter = function(cell) {
                    const value = cell.getValue() || 'N/A';
                    const escaped = value.replace(/'/g, "\\'");
                    return `<div class="flex items-center gap-2">
                        <code class="text-xs text-gray-500 truncate font-mono bg-gray-100/80 px-1.5 py-0.5 rounded flex-1">${value}</code>
                        <button onclick="copyToClipboard('${escaped}')" class="flex-shrink-0 p-1 text-gray-400 hover:text-blue-600 hover:bg-blue-50 rounded transition-colors" title="Copy ARN">
                            <svg class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"/>
                            </svg>
                        </button>
                    </div>`;
                };
            } else if (col.field === 'resource_type') {
                colDef.formatter = function(cell) {
                    const value = cell.getValue() || 'N/A';
                    const colorClass = getTypeBadgeClass(value);
                    return `<span class="badge ${colorClass}">${value}</span>`;
                };
            } else if (col.field === 'region') {
                colDef.formatter = function(cell) {
                    const value = cell.getValue() || 'N/A';
                    return `<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-slate-100 text-slate-700">
                        <svg class="w-3 h-3 mr-1 text-slate-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3.055 11H5a2 2 0 012 2v1a2 2 0 002 2 2 2 0 012 2v2.945M8 3.935V5.5A2.5 2.5 0 0010.5 8h.5a2 2 0 012 2 2 2 0 104 0 2 2 0 012-2h1.064M15 20.488V18a2 2 0 012-2h3.064M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
                        </svg>
                        ${value}
                    </span>`;
                };
            } else if (col.field === 'tags') {
                colDef.formatter = function(cell) {
                    const row = cell.getRow().getData();
                    const tags = row.tags || {};
                    const entries = Object.entries(tags);
                    if (entries.length === 0) return '<span class="text-gray-400 text-xs italic">No tags</span>';

                    let html = '<div class="flex flex-wrap gap-1">';
                    entries.slice(0, 3).forEach(([key, val]) => {
                        const k = key.length > 8 ? key.substring(0, 8) + '…' : key;
                        const v = String(val).length > 10 ? String(val).substring(0, 10) + '…' : val;
                        html += `<span class="inline-flex items-center px-1.5 py-0.5 rounded text-xs bg-emerald-50 text-emerald-700 border border-emerald-200" title="${key}=${val}">
                            <span class="font-medium">${k}:</span><span class="ml-0.5">${v}</span>
                        </span>`;
                    });
                    if (entries.length > 3) {
                        html += `<span class="inline-flex items-center px-1.5 py-0.5 rounded text-xs bg-gray-100 text-gray-500">+${entries.length - 3}</span>`;
                    }
                    html += '</div>';
                    return html;
                };
            } else if (col.field === '_created_by') {
                // Created By column - reads from tags._created_by
                colDef.formatter = function(cell) {
                    const row = cell.getRow().getData();
                    const tags = row.tags || {};
                    const value = tags['_created_by'];
                    if (!value) return '<span class="text-gray-300">—</span>';
                    // Extract role/user name from ARN for display
                    let display = value;
                    if (value.includes(':role/')) {
                        display = value.split(':role/')[1] || value;
                    } else if (value.includes(':user/')) {
                        display = value.split(':user/')[1] || value;
                    } else if (value.startsWith('service:')) {
                        display = value.replace('service:', '');
                    }
                    const truncated = display.length > 30 ? display.substring(0, 30) + '…' : display;
                    return `<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-purple-50 text-purple-700 border border-purple-200" title="${value}">${truncated}</span>`;
                };
            } else if (col.field === '_created_by_type') {
                // Creator Type column - reads from tags._created_by_type
                colDef.formatter = function(cell) {
                    const row = cell.getRow().getData();
                    const tags = row.tags || {};
                    const value = tags['_created_by_type'];
                    if (!value) return '<span class="text-gray-300">—</span>';
                    const colors = {
                        'AssumedRole': 'bg-blue-50 text-blue-700 border-blue-200',
                        'IAMUser': 'bg-green-50 text-green-700 border-green-200',
                        'Root': 'bg-red-50 text-red-700 border-red-200',
                        'AWSService': 'bg-orange-50 text-orange-700 border-orange-200'
                    };
                    const colorClass = colors[value] || 'bg-gray-50 text-gray-700 border-gray-200';
                    return `<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium ${colorClass} border">${value}</span>`;
                };
            } else if (col.field === '_created_at') {
                // Creation Time column - reads from tags._created_at
                colDef.formatter = function(cell) {
                    const row = cell.getRow().getData();
                    const tags = row.tags || {};
                    const value = tags['_created_at'];
                    if (!value) return '<span class="text-gray-300">—</span>';
                    try {
                        const date = new Date(value);
                        const formatted = date.toLocaleString();
                        return `<span class="text-xs text-gray-600" title="${value}">${formatted}</span>`;
                    } catch (e) {
                        return `<span class="text-xs text-gray-600">${value}</span>`;
                    }
                };
            } else if (col.field.startsWith('tag:')) {
                const tagKey = col.field.substring(4);
                colDef.formatter = function(cell) {
                    const row = cell.getRow().getData();
                    const tags = row.tags || {};
                    const value = tags[tagKey];
                    if (!value) return '<span class="text-gray-300">—</span>';
                    const display = String(value).length > 20 ? String(value).substring(0, 20) + '…' : value;
                    return `<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-indigo-50 text-indigo-700 border border-indigo-200" title="${value}">${display}</span>`;
                };
            }

            columns.push(colDef);
        });

        return columns;
    }

    // Get badge class based on resource type
    function getTypeBadgeClass(type) {
        if (!type) return 'badge-default';
        const t = type.toLowerCase();
        if (t.includes('s3')) return 'badge-s3';
        if (t.includes('ec2') || t.includes('instance')) return 'badge-ec2';
        if (t.includes('lambda')) return 'badge-lambda';
        if (t.includes('iam')) return 'badge-iam';
        if (t.includes('rds') || t.includes('database')) return 'badge-rds';
        if (t.includes('dynamodb')) return 'badge-dynamodb';
        return 'badge-default';
    }

    function renderTable() {
        const data = Alpine.$data(document.querySelector('[x-data]'));
        const target = document.getElementById('resource-table');

        if (!data.resourceData || !data.resourceData.resources || data.resourceData.resources.length === 0) {
            if (resourceTable) {
                resourceTable.destroy();
                resourceTable = null;
            }
            target.innerHTML = `
                <div class="p-12 text-center text-gray-500">
                    <svg class="mx-auto h-16 w-16 text-gray-300" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2-2v-5m16 0h-2.586a1 1 0 00-.707.293l-2.414 2.414a1 1 0 01-.707.293h-3.172a1 1 0 01-.707-.293l-2.414-2.414A1 1 0 006.586 13H4"/>
                    </svg>
                    <p class="mt-4 text-lg font-medium">No resources found</p>
                    <p class="mt-1 text-sm text-gray-400">Try adjusting your search or filter criteria</p>
                </div>
            `;
            return;
        }

        // Clear container for Tabulator
        target.innerHTML = '';

        const columns = buildColumns();

        // Add row selection column at the beginning
        const selectColumn = {
            formatter: "rowSelection",
            titleFormatter: "rowSelection",
            hozAlign: "center",
            headerSort: false,
            width: 50,
            minWidth: 50,
            maxWidth: 50,
            frozen: true,
            resizable: false,
            cellClick: function(e, cell) {
                cell.getRow().toggleSelect();
            }
        };

        // Create or update Tabulator
        resourceTable = new Tabulator(target, {
            data: data.resourceData.resources,
            columns: [selectColumn, ...columns],
            layout: "fitData",
            height: "100%",
            movableColumns: true,
            resizableColumns: true,
            placeholder: "No resources to display",
            initialSort: [{ column: data.sortBy, dir: data.sortOrder }],
            selectableRows: true,
            selectableRowsRangeMode: "click",

            // Row selection changed
            rowSelectionChanged: function(data, rows) {
                const alpineData = Alpine.$data(document.querySelector('[x-data]'));
                alpineData.updateSelectedResources(data);
            },

            // Column events
            columnMoved: function(column, columns) {
                // Update Alpine column order when user drags columns
                // Filter out the selection column
                const newOrder = columns.filter(c => c.getField()).map(c => c.getField());
                reorderAlpineColumns(newOrder);
            },

            columnResized: function(column) {
                // Update Alpine column width
                const field = column.getField();
                if (!field) return;  // Skip selection column
                const width = column.getWidth();
                const alpineData = Alpine.$data(document.querySelector('[x-data]'));
                alpineData.setColumnWidth(field, width);
            },

            // Sorting
            dataSorted: function(sorters, rows) {
                if (sorters.length > 0) {
                    const alpineData = Alpine.$data(document.querySelector('[x-data]'));
                    alpineData.sortBy = sorters[0].field;
                    alpineData.sortOrder = sorters[0].dir;
                }
            }
        });

        // Make table globally accessible
        window.resourceTable = resourceTable;

        // Add footer with count
        const footer = document.createElement('div');
        footer.className = 'bg-gradient-to-r from-slate-50 to-slate-100 px-4 py-3 flex items-center justify-between border-t border-slate-200 rounded-b-xl';
        footer.innerHTML = `
            <div class="flex items-center gap-4">
                <p class="text-sm text-slate-600">
                    Showing <span class="font-semibold text-slate-900">${data.resourceData.resources.length}</span>
                    of <span class="font-semibold text-slate-900">${data.resourceData.count}</span> resources
                </p>
            </div>
            <div class="flex items-center gap-3 text-xs text-slate-400">
                <span class="flex items-center gap-1">
                    <svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/>
                    </svg>
                    Click to select
                </span>
                <span>•</span>
                <span class="flex items-center gap-1">
                    <svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 9l4-4 4 4m0 6l-4 4-4-4"/>
                    </svg>
                    Click headers to sort
                </span>
                <span>•</span>
                <span class="flex items-center gap-1">
                    <svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5l-5-5m5 5v-4m0 4h-4"/>
                    </svg>
                    Drag to resize
                </span>
            </div>
        `;
        target.appendChild(footer);
    }

    // Reorder Alpine columns to match Tabulator drag order
    function reorderAlpineColumns(newOrder) {
        const data = Alpine.$data(document.querySelector('[x-data]'));

        // Create new ordered arrays
        const newBaseColumns = [];
        const newTagColumns = [];

        newOrder.forEach(field => {
            const baseCol = data.baseColumns.find(c => c.field === field);
            if (baseCol) {
                newBaseColumns.push(baseCol);
            } else {
                const tagCol = data.tagColumns.find(c => c.field === field);
                if (tagCol) newTagColumns.push(tagCol);
            }
        });

        // Add non-visible columns at the end
        data.baseColumns.forEach(col => {
            if (!col.visible && !newBaseColumns.find(c => c.field === col.field)) {
                newBaseColumns.push(col);
            }
        });
        data.tagColumns.forEach(col => {
            if (!col.visible && !newTagColumns.find(c => c.field === col.field)) {
                newTagColumns.push(col);
            }
        });

        data.baseColumns = newBaseColumns;
        data.tagColumns = newTagColumns;
    }

    // Rebuild table when columns change (from modal)
    function rebuildTable() {
        searchResources();
    }

    // Copy to clipboard helper
    function copyToClipboard(text) {
        navigator.clipboard.writeText(text).then(() => {
            // Brief toast feedback would go here
        });
    }

    function renderSavedViewsChips(views, target) {
        if (views.length === 0) {
            target.innerHTML = '<span class="text-gray-400 text-sm">No saved views yet</span>';
            return;
        }

        let html = '';
        views.forEach(v => {
            html += `
                <button onclick="loadView(${v.id})"
                        class="inline-flex items-center px-3 py-1.5 rounded-full text-sm font-medium bg-gradient-to-r from-purple-100 to-purple-50 text-purple-800 hover:from-purple-200 hover:to-purple-100 transition-all shadow-sm group">
                    ${v.is_default ? '<svg class="w-3 h-3 mr-1 text-purple-600" fill="currentColor" viewBox="0 0 20 20"><path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/></svg>' : ''}
                    ${v.name}
                    <span onclick="event.stopPropagation(); deleteView(${v.id})" class="ml-1.5 opacity-0 group-hover:opacity-100 text-purple-600 hover:text-purple-900">
                        <svg class="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/></svg>
                    </span>
                </button>
            `;
        });
        target.innerHTML = html;
    }

    function countFilterConditions(config) {
        if (config.version === 2 || config.items) {
            function countInGroup(group) {
                let count = 0;
                for (const item of group.items || []) {
                    if (item.type === 'group') count += countInGroup(item);
                    else count++;
                }
                return count;
            }
            return countInGroup(config);
        } else if (config.conditions) {
            return config.conditions.length;
        }
        return 0;
    }

    function renderSavedFiltersChips(filters, target) {
        if (filters.length === 0) {
            target.innerHTML = '<span class="text-gray-400 text-sm">No saved filters yet</span>';
            return;
        }

        let html = '';
        filters.forEach(f => {
            const config = f.filter_config || {};
            const isAdvanced = config.version === 2 || config.items || (config.conditions && config.conditions.length > 0);
            const conditionCount = countFilterConditions(config);

            html += `
                <button onclick="loadFilter(${f.id}, ${JSON.stringify(config).replace(/"/g, '&quot;')})"
                        class="inline-flex items-center px-3 py-1.5 rounded-full text-sm font-medium ${isAdvanced ? 'bg-gradient-to-r from-emerald-100 to-emerald-50 text-emerald-800 hover:from-emerald-200 hover:to-emerald-100' : 'bg-gradient-to-r from-blue-100 to-blue-50 text-blue-800 hover:from-blue-200 hover:to-blue-100'} transition-all shadow-sm group"
                        title="${isAdvanced ? (config.logic || 'AND') + ' - ' + conditionCount + ' condition(s)' : 'Simple filter'}">
                    ${isAdvanced ? '<svg class="w-3 h-3 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10"/></svg>' : ''}
                    ${f.name}
                    ${isAdvanced ? '<span class="ml-1 text-xs opacity-75">(' + conditionCount + ')</span>' : ''}
                    <span onclick="event.stopPropagation(); deleteFilter(${f.id})" class="ml-1.5 opacity-0 group-hover:opacity-100 ${isAdvanced ? 'text-emerald-600 hover:text-emerald-900' : 'text-blue-600 hover:text-blue-900'}">
                        <svg class="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/></svg>
                    </span>
                </button>
            `;
        });
        target.innerHTML = html;
    }

    function loadView(id) {
        fetch(`/api/views/${id}`)
            .then(r => r.json())
            .then(view => {
                const data = Alpine.$data(document.querySelector('[x-data]'));
                const config = view.view_config;

                if (config.columns) {
                    data.baseColumns.forEach(col => {
                        const saved = config.columns.find(c => c.field === col.field);
                        if (saved) {
                            col.visible = saved.visible;
                            if (saved.width) col.width = saved.width;
                            if (saved.frozen !== undefined) col.frozen = saved.frozen;
                        } else {
                            col.visible = false;
                        }
                    });
                    data.tagColumns.forEach(col => {
                        const saved = config.columns.find(c => c.field === col.field);
                        if (saved) {
                            col.visible = saved.visible;
                            if (saved.width) col.width = saved.width;
                            if (saved.frozen !== undefined) col.frozen = saved.frozen;
                        } else {
                            col.visible = false;
                        }
                    });
                }

                if (config.sort_by) data.sortBy = config.sort_by;
                if (config.sort_order) data.sortOrder = config.sort_order;
                if (config.filters) data.loadFilterConfig(config.filters);

                data.currentViewId = id;
                fetch(`/api/views/${id}/use`, { method: 'POST' });
                searchResources();
            });
    }

    function loadFilter(id, config) {
        const data = Alpine.$data(document.querySelector('[x-data]'));
        data.loadFilterConfig(config);
        fetch(`/api/filters/${id}/use`, { method: 'POST' });
        searchResources();
    }

    function saveFilter() {
        const data = Alpine.$data(document.querySelector('[x-data]'));
        const filterConfig = data.getFilterConfig();

        fetch('/api/filters', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({
                name: data.filterName,
                description: data.filterDescription,
                filter_config: filterConfig
            })
        })
        .then(r => r.json())
        .then(() => {
            data.showSaveFilterModal = false;
            htmx.trigger('#saved-filters-list', 'load');
        });
    }

    function saveView() {
        const data = Alpine.$data(document.querySelector('[x-data]'));
        const filters = data.getFilterConfig();

        fetch('/api/views', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({
                name: data.viewName,
                description: data.viewDescription,
                view_config: {
                    columns: data.columns.map(c => ({
                        field: c.field,
                        label: c.label,
                        visible: c.visible,
                        width: c.width || 150,
                        frozen: c.frozen || false
                    })),
                    sort_by: data.sortBy,
                    sort_order: data.sortOrder,
                    filters: filters
                }
            })
        })
        .then(r => r.json())
        .then(() => {
            data.showSaveViewModal = false;
            data.viewName = '';
            data.viewDescription = '';
            htmx.trigger('#saved-views-list', 'load');
        });
    }

    function deleteFilter(id) {
        if (!confirm('Delete this saved filter?')) return;
        fetch(`/api/filters/${id}`, { method: 'DELETE' })
            .then(() => htmx.trigger('#saved-filters-list', 'load'));
    }

    function deleteView(id) {
        if (!confirm('Delete this saved view?')) return;
        fetch(`/api/views/${id}`, { method: 'DELETE' })
            .then(() => htmx.trigger('#saved-views-list', 'load'));
    }

    function exportCSV() {
        const data = Alpine.$data(document.querySelector('[x-data]'));
        const params = new URLSearchParams();
        if (data.search) params.append('q', data.search);
        if (data.selectedTypes.length === 1) params.append('type', data.selectedTypes[0]);
        if (data.selectedRegions.length === 1) params.append('region', data.selectedRegions[0]);
        if (data.snapshot) params.append('snapshot', data.snapshot);

        const visibleFields = data.visibleColumns.map(c => c.field);
        params.append('columns', visibleFields.join(','));
        params.append('sort_by', data.sortBy);
        params.append('sort_order', data.sortOrder);

        window.location.href = '/api/resources/export/csv?' + params.toString();
    }

    function exportYAML() {
        const data = Alpine.$data(document.querySelector('[x-data]'));
        const params = new URLSearchParams();
        if (data.search) params.append('q', data.search);
        if (data.selectedTypes.length === 1) params.append('type', data.selectedTypes[0]);
        if (data.selectedRegions.length === 1) params.append('region', data.selectedRegions[0]);
        if (data.snapshot) params.append('snapshot', data.snapshot);
        params.append('include_config', 'true');
        params.append('include_tags', 'true');

        window.location.href = '/api/resources/export/yaml?' + params.toString();
    }

    function loadTagKeys() {
        fetch('/api/resources/tags/keys')
            .then(r => r.json())
            .then(result => {
                const data = Alpine.$data(document.querySelector('[x-data]'));
                data.availableTagKeys = result.keys || [];
                data.initTagColumns();
            });
    }
</script>
{% endblock %}
