import { r as registerInstance, c as createEvent, h, H as Host } from './index-BIwHMk6j.js';
import { n as nt, L as Le } from './index.esm-CMeGYws2.js';
import { g as getPropertyFromPath } from './property-resolution-CQUZjrU4.js';

/**
 * Get the subheading text for a filter group based on its operator and expression count
 *
 * @param operator - The group's operator (AND or OR)
 * @param expressionCount - Number of child expressions
 * @returns Subheading text, or empty string if 0 or 1 expressions
 */
function getFilterGroupSubheading(operator, expressionCount) {
    if (expressionCount <= 1) {
        return '';
    }
    return operator === nt.AND
        ? 'All of these conditions are met'
        : 'Any of these conditions are met';
}
/**
 * Create a new empty comparison expression
 *
 * @returns A new comparison expression with empty key and value
 */
function createEmptyComparison() {
    return {
        key: '',
        op: nt.EQUALS,
        exp: '',
    };
}
/**
 * Create a new nested group with the opposite operator from the parent
 *
 * @param parentOperator - The parent group's operator
 * @returns A new group with the opposite operator and one empty comparison
 */
function createNestedGroup(parentOperator) {
    const oppositeOp = parentOperator === nt.AND ? nt.OR : nt.AND;
    return {
        op: oppositeOp,
        exp: [createEmptyComparison()],
    };
}
/**
 * Add a new expression to a group immutably
 *
 * @param group - The existing group
 * @param newExpression - The expression to add
 * @returns A new group with the expression added to the end
 */
function addExpressionToGroup(group, newExpression) {
    return {
        op: group.op,
        exp: [...group.exp, newExpression],
    };
}
/**
 * Toggle a group's operator between AND and OR
 *
 * @param group - The group to toggle
 * @returns A new group with the toggled operator
 */
function toggleGroupOperator(group) {
    const newOperator = group.op === nt.AND ? nt.OR : nt.AND;
    return {
        op: newOperator,
        exp: [...group.exp],
    };
}
/**
 * Update a child expression in a group, handling deletion and unwrapping
 *
 * This function handles three scenarios:
 * 1. Update: Replace a child expression with a new one
 * 2. Delete: Remove a child (when updatedChild is undefined)
 *    - If last child is deleted, return 'removed' (group should be deleted)
 *    - If deletion leaves one child, return 'unwrapped' (unwrap to that child)
 *    - Otherwise, return 'updated' with the remaining children
 *
 * @param group - The group containing the child
 * @param childIndex - Index of the child to update
 * @param updatedChild - The new child expression, or undefined to delete
 * @returns Result object with type and resulting expression
 */
function updateChildExpression(group, childIndex, updatedChild) {
    const expressions = [...group.exp];
    if (!updatedChild) {
        // Deletion - remove the child
        expressions.splice(childIndex, 1);
        if (expressions.length === 0) {
            // No children left - remove the entire group
            return {
                type: 'removed',
                expression: undefined,
            };
        }
        if (expressions.length === 1) {
            // One child left - unwrap to that child
            return {
                type: 'unwrapped',
                expression: expressions[0],
            };
        }
        // Multiple children remain - return updated group
        return {
            type: 'updated',
            expression: {
                op: group.op,
                exp: expressions,
            },
        };
    }
    // Update - replace the child
    expressions[childIndex] = updatedChild;
    return {
        type: 'updated',
        expression: {
            op: group.op,
            exp: expressions,
        },
    };
}

const limeQueryFilterGroupCss = () => `@charset "UTF-8";*,*::before,*::after{box-sizing:border-box}limebb-lime-query-filter-expression{position:relative;isolation:isolate}limebb-lime-query-filter-expression:not(:first-of-type):after{content:"";position:absolute;top:-0.5rem;left:0.75rem;display:block;border-radius:1rem;height:2rem;width:0.125rem;background-color:var(--limebb-lime-query-builder-group-color)}limebb-lime-query-filter-expression:not(:first-of-type):before{position:relative;z-index:1;display:flex;justify-content:center;align-items:center;height:1rem;content:var(--limebb-lime-query-filter-group-operator);display:inline-block;margin:0 auto 0.5rem auto;transform:translateY(-50%);font-size:0.625rem;padding:0 0.5rem;color:rgb(var(--color-blue-dark));background-color:var(--limebb-lime-query-builder-group-color);border-radius:2rem}.expression{display:flex;flex-direction:column;margin-bottom:1rem;gap:0;background-color:rgb(var(--contrast-100));border-radius:0.75rem;border:1px solid var(--limebb-lime-query-builder-group-color)}.expression ul{list-style:none;margin:0;padding:0.5rem;display:flex;flex-direction:column;align-items:center;gap:1rem}.expression ul [role=listitem]{list-style:none;width:100%}limel-button.add-group{width:fit-content;margin:0.5rem}limel-icon-button.delete-group{margin-left:0.5rem}limel-select.operator-select{min-width:8rem}`;

const LimeQueryFilterGroupComponent = class {
    constructor(hostRef) {
        registerInstance(this, hostRef);
        this.expressionChange = createEvent(this, "expressionChange");
        this.options = [
            {
                text: 'All',
                secondaryText: 'AND operator',
                value: 'and',
            },
            {
                text: 'Any',
                secondaryText: 'OR operator',
                value: 'or',
            },
        ];
        this.renderChildExpression = (expression, childIndex) => (h("limebb-lime-query-filter-expression", { role: "listitem", platform: this.platform, context: this.context, limetype: this.limetype, activeLimetype: this.activeLimetype, expression: expression, onExpressionChange: this.handleExpressionChange(childIndex) }));
        this.handleDeleteGroup = () => {
            this.expressionChange.emit();
        };
        this.handleToggleOperator = (event) => {
            const selectedOption = Array.isArray(event.detail)
                ? event.detail[0]
                : event.detail;
            this.value = selectedOption;
            const newOp = selectedOption.value === 'and' ? nt.AND : nt.OR;
            if (newOp !== this.expression.op) {
                const newGroup = toggleGroupOperator(this.expression);
                this.expressionChange.emit(newGroup);
            }
        };
        this.handleAddChildExpression = () => {
            const newChild = createEmptyComparison();
            const newGroup = addExpressionToGroup(this.expression, newChild);
            this.expressionChange.emit(newGroup);
        };
        this.handleAddChildGroup = () => {
            const newChild = createNestedGroup(this.expression.op);
            const newGroup = addExpressionToGroup(this.expression, newChild);
            this.expressionChange.emit(newGroup);
        };
        this.handleExpressionChange = (updatedChildIndex) => (event) => {
            event.stopPropagation();
            const updatedExpression = event.detail;
            const result = updateChildExpression(this.expression, updatedChildIndex, updatedExpression);
            this.expressionChange.emit(result.expression);
        };
    }
    // Initialize value to match current operator
    componentWillLoad() {
        this.value =
            this.options.find((option) => option.value ===
                (this.expression.op === nt.AND ? 'and' : 'or')) || this.options[0];
    }
    render() {
        return (h(Host, { key: '4b1647c741b78253b4ce4ed1bd347800da394563', style: {
                '--limebb-lime-query-filter-group-operator': `"${this.expression.op === nt.AND ? 'AND' : 'OR'}"`,
            } }, h("div", { key: '47fd3000275e17ef70d86af5e6abcb492806ffba', class: "expression" }, this.renderHeader(), h("ul", { key: '224249a4b305eb2b20c1aedad98d2c3191d47e83' }, this.expression.exp.map(this.renderChildExpression), this.renderAddButton()), this.renderAddGroupButton())));
    }
    renderHeader() {
        const subheading = this.getSubheading();
        if (!subheading) {
            return null;
        }
        return (h("limel-header", { subheading: subheading }, this.renderOperators(), this.renderDeleteGroupButton()));
    }
    renderOperators() {
        return (h("limel-select", { class: "operator-select", slot: "actions", value: this.value, options: this.options, onChange: this.handleToggleOperator }));
    }
    renderDeleteGroupButton() {
        return (h("limel-icon-button", { class: "delete-group", slot: "actions", icon: "trash", label: "Delete This Group", onClick: this.handleDeleteGroup }));
    }
    getSubheading() {
        return getFilterGroupSubheading(this.expression.op, this.expression.exp.length);
    }
    renderAddButton() {
        return (h("limel-button", { role: "listitem", label: "Condition", icon: {
                name: 'plus_math',
                title: 'Add',
            }, onClick: this.handleAddChildExpression }));
    }
    renderAddGroupButton() {
        return (h("limel-button", { class: "add-group", label: "Group", icon: {
                name: 'plus_math',
                title: 'Add',
            }, onClick: this.handleAddChildGroup }));
    }
};
LimeQueryFilterGroupComponent.style = limeQueryFilterGroupCss();

const limeQueryFilterNotCss = () => `@charset "UTF-8";.expression{display:flex;flex-direction:column;margin-bottom:1rem;gap:1rem;padding:1rem;border-left:0.25rem solid rgb(var(--contrast-400));background-color:rgb(var(--contrast-100))}`;

const LimeQueryFilterNotComponent = class {
    constructor(hostRef) {
        registerInstance(this, hostRef);
        this.expressionChange = createEvent(this, "expressionChange");
        this.handleExpressionChange = (event) => {
            var _a;
            event.stopPropagation();
            const updatedExpression = (_a = event.detail) !== null && _a !== void 0 ? _a : undefined;
            if (updatedExpression === undefined) {
                this.expressionChange.emit(undefined);
                return;
            }
            this.expressionChange.emit({
                op: nt.NOT,
                exp: updatedExpression,
            });
        };
    }
    render() {
        return (h("div", { key: '16246e10be820ad18713cb097146040d30e242bf', class: "expression" }, this.label && h("limel-header", { key: '539d60a4567727282463dec2a90e06a3630501aa', heading: this.label }), h("limebb-lime-query-filter-expression", { key: '67f892704ea3e5a061acdcb8f3ffe22271971569', platform: this.platform, context: this.context, label: "Not", limetype: this.limetype, activeLimetype: this.activeLimetype, expression: this.expression.exp, onExpressionChange: this.handleExpressionChange })));
    }
};
LimeQueryFilterNotComponent.style = limeQueryFilterNotCss();

/**
 * System property name to actual type mapping.
 *
 * Maps system property names (with or without underscore prefix) to their actual data types.
 * This mapping is necessary because system properties have `type='system'` in the metadata
 * (for historical reasons - database schema fieldtype 255), but we need to know their
 * actual data types to render appropriate inputs.
 */
const SYSTEM_TYPE_MAP = {
    timestamp: 'time',
    createdtime: 'time',
    updatedtime: 'time',
    id: 'integer',
    createduser: 'integer',
    updateduser: 'integer',
    descriptive: 'string',
};
/**
 * Lime CRM date/time property type to Lime Elements date picker type mapping.
 *
 * Maps Lime CRM property types to the corresponding Lime Elements date picker types,
 * as they use different naming conventions.
 */
const DATE_TIME_TYPE_MAP = {
    date: 'date',
    time: 'datetime',
    timeofday: 'time',
    month: 'month',
    quarter: 'quarter',
    year: 'year',
};
/**
 * Get the actual type of a property, resolving 'system' type to the underlying type.
 *
 * System properties in Lime CRM have `type: 'system'` in the metadata (a categorical marker
 * from the database schema fieldtype 255), but we need to know their actual data types
 * to render appropriate input controls.
 *
 * @param property - The property to get the type for
 * @param property.type
 * @param property.name
 * @returns The actual property type (resolves 'system' to the underlying type)
 *
 * @example
 * ```typescript
 * const property = { name: '_timestamp', type: 'system' };
 * getActualPropertyType(property); // Returns 'time'
 * ```
 */
function getActualPropertyType(property) {
    if (property.type === 'system') {
        return resolveSystemPropertyType(property.name);
    }
    return property.type;
}
/**
 * Map system property names to their actual data types.
 *
 * This mapping is necessary because system properties have `type='system'` in the metadata
 * (for historical reasons - database schema fieldtype 255), but we need to know their
 * actual data types to render appropriate inputs.
 *
 * The mapping is based on the Lime CRM database schema:
 * - System datetime fields: `timestamp`, `createdtime`, `updatedtime`
 * - System integer fields: `id`, `createduser`, `updateduser`
 * - System string fields: `descriptive`
 *
 * @param propertyName - The system property name (with or without underscore prefix)
 * @returns The actual property type
 *
 * @example
 * ```typescript
 * resolveSystemPropertyType('_timestamp');  // Returns 'time'
 * resolveSystemPropertyType('timestamp');   // Returns 'time'
 * resolveSystemPropertyType('_id');         // Returns 'integer'
 * resolveSystemPropertyType('unknown');     // Returns 'string' (default)
 * ```
 */
function resolveSystemPropertyType(propertyName) {
    const name = propertyName.replace(/^_/, '');
    return SYSTEM_TYPE_MAP[name] || 'string';
}
/**
 * Map Lime CRM property types to Lime Elements date picker types.
 *
 * Lime CRM and Lime Elements use different naming conventions for date/time types,
 * so we need to translate between them:
 *
 * - `'date'` → `'date'` - Date only
 * - `'time'` → `'datetime'` - Full datetime (date + time) in Lime CRM
 * - `'timeofday'` → `'time'` - Time only (hh:mm)
 * - `'month'` → `'month'` - Month picker (YYYY-MM)
 * - `'quarter'` → `'quarter'` - Quarter picker
 * - `'year'` → `'year'` - Year picker
 *
 * @param propertyType - The Lime CRM date/time property type
 * @returns The corresponding Lime Elements date picker type
 *
 * @example
 * ```typescript
 * mapPropertyTypeToPickerType('time');      // Returns 'datetime'
 * mapPropertyTypeToPickerType('timeofday'); // Returns 'time'
 * mapPropertyTypeToPickerType('date');      // Returns 'date'
 * ```
 */
function mapPropertyTypeToPickerType(propertyType) {
    return DATE_TIME_TYPE_MAP[propertyType] || 'date';
}

const limeQueryValueInputCss = () => `:host{display:flex;gap:0.5rem}:host>*{flex-grow:1}*{box-sizing:border-box}.value-input-container{display:flex;flex-direction:row;align-items:flex-start;gap:0.5rem;width:100%}.mode-toggle{flex-shrink:0;flex-grow:0}.placeholder-input{flex-grow:1;display:flex;flex-direction:column;gap:0.5rem}.placeholder-preview{display:flex;align-items:center;gap:0.5rem;padding:0.5rem;background-color:rgba(var(--color-blue-light), 0.1);border-radius:var(--border-radius-small);font-size:0.875rem;color:rgb(var(--color-blue-default));border-left:3px solid rgb(var(--color-blue-default))}.placeholder-preview limel-icon{flex-shrink:0;color:rgb(var(--color-blue-default))}.placeholder-preview span{font-family:var(--font-monospace);word-break:break-all}`;

var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
        r = Reflect.decorate(decorators, target, key, desc);
    else
        for (var i = decorators.length - 1; i >= 0; i--)
            if (d = decorators[i])
                r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
const LimeQueryValueInput = class {
    constructor(hostRef) {
        registerInstance(this, hostRef);
        this.change = createEvent(this, "change");
        /**
         * Optional label for the input
         */
        this.label = 'Value';
        this.inputMode = 'value';
        this.handleTextChange = (event) => {
            event.stopPropagation();
            // Try to parse as number for number inputs
            const value = event.detail;
            const numValue = Number(value);
            if (!Number.isNaN(numValue) && value !== '') {
                this.change.emit(numValue);
            }
            else {
                this.change.emit(value);
            }
        };
        this.handleSelectChange = (event) => {
            event.stopPropagation();
            const detail = event.detail;
            if (Array.isArray(detail)) {
                this.change.emit(detail.map((o) => o.value));
            }
            else {
                this.change.emit(detail === null || detail === void 0 ? void 0 : detail.value);
            }
        };
        this.handleBooleanChange = (event) => {
            event.stopPropagation();
            const detail = event.detail;
            if (!Array.isArray(detail)) {
                // Convert string back to boolean
                this.change.emit((detail === null || detail === void 0 ? void 0 : detail.value) === 'true');
            }
        };
        this.handleDateChange = (event) => {
            event.stopPropagation();
            // Convert Date to ISO string for storage
            const date = event.detail;
            this.change.emit(date ? date.toISOString() : null);
        };
        this.handleMultiValueChange = (event) => {
            event.stopPropagation();
            // Split by comma and trim whitespace
            const values = event.detail
                .split(',')
                .map((v) => v.trim())
                .filter((v) => v.length > 0);
            this.change.emit(values);
        };
        this.handleModeToggle = () => {
            if (this.inputMode === 'value') {
                // Switching to placeholder mode
                this.inputMode = 'placeholder';
                // Emit placeholder value (empty initially)
                this.change.emit('%activeObject%');
            }
            else {
                // Switching to value mode
                this.inputMode = 'value';
                // Emit empty value
                this.change.emit('');
            }
        };
        this.handlePlaceholderPropertyChange = (event) => {
            event.stopPropagation();
            const propertyPath = event.detail;
            const placeholderValue = this.buildPlaceholderValue(propertyPath);
            this.change.emit(placeholderValue);
        };
    }
    componentWillLoad() {
        // Detect if the current value is a placeholder
        if (this.isPlaceholder(this.value)) {
            this.inputMode = 'placeholder';
        }
    }
    componentWillUpdate() {
        // Update mode if value changes externally
        if (this.isPlaceholder(this.value) &&
            this.inputMode !== 'placeholder') {
            this.inputMode = 'placeholder';
        }
        else if (!this.isPlaceholder(this.value) &&
            this.inputMode === 'placeholder') {
            this.inputMode = 'value';
        }
    }
    isPlaceholder(value) {
        return typeof value === 'string' && value.startsWith('%activeObject%');
    }
    parsePlaceholderPath(value) {
        if (!this.isPlaceholder(value)) {
            return '';
        }
        // Extract path after %activeObject%. (e.g., "%activeObject%.company.name" → "company.name")
        return value.replace(/^%activeObject%\.?/, '');
    }
    buildPlaceholderValue(propertyPath) {
        if (!propertyPath) {
            return '%activeObject%';
        }
        return `%activeObject%.${propertyPath}`;
    }
    render() {
        if (!this.operator) {
            return null;
        }
        return (h(Host, null, this.renderModeToggle(), this.renderInputByMode()));
    }
    renderInputByMode() {
        if (this.inputMode === 'placeholder') {
            return this.renderPlaceholderInput();
        }
        return this.renderValueInputByType();
    }
    renderModeToggle() {
        // Only show toggle if activeLimetype is set
        if (!this.activeLimetype) {
            return null;
        }
        const isPlaceholderMode = this.inputMode === 'placeholder';
        const buttonLabel = isPlaceholderMode ? 'Use Value' : 'Use Placeholder';
        const buttonIcon = isPlaceholderMode ? 'text' : 'link';
        return (h("limel-icon-button", { class: "mode-toggle", icon: buttonIcon, label: buttonLabel, onClick: this.handleModeToggle }));
    }
    renderPlaceholderInput() {
        const propertyPath = this.parsePlaceholderPath(this.value);
        return (h("div", { class: "placeholder-input" }, h("limebb-property-selector", { platform: this.platform, context: this.context, limetype: this.activeLimetype, label: "Active Object Property", value: propertyPath, required: false, helperText: "Select property from the active object", onChange: this.handlePlaceholderPropertyChange }), this.renderPlaceholderPreview()));
    }
    renderPlaceholderPreview() {
        if (!this.isPlaceholder(this.value)) {
            return;
        }
        return (h("div", { class: "placeholder-preview" }, h("limel-icon", { name: "info", size: "small" }), h("span", null, "Placeholder: ", this.value)));
    }
    renderValueInputByType() {
        // Special handling for IN operator - always use chip set for arrays
        if (this.operator === nt.IN) {
            return this.renderMultiValueInput();
        }
        const property = this.getProperty();
        if (!property) {
            return this.renderTextInput();
        }
        // Resolve 'system' type to actual type
        const actualType = getActualPropertyType(property);
        switch (actualType) {
            case 'integer':
            case 'decimal': {
                return this.renderNumberInput(actualType);
            }
            case 'yesno': {
                return this.renderBooleanInput();
            }
            case 'option': {
                return this.renderOptionInput(property);
            }
            case 'date':
            case 'time':
            case 'timeofday':
            case 'year':
            case 'month':
            case 'quarter': {
                return this.renderDateTimeInput(actualType);
            }
            default: {
                return this.renderTextInput();
            }
        }
    }
    renderTextInput() {
        var _a;
        return (h("limel-input-field", { label: this.label, value: ((_a = this.value) === null || _a === void 0 ? void 0 : _a.toString()) || '', placeholder: "Enter value", onChange: this.handleTextChange }));
    }
    renderNumberInput(type) {
        var _a;
        const step = type === 'integer' ? 1 : 0.01;
        return (h("limel-input-field", { label: this.label, type: "number", value: ((_a = this.value) === null || _a === void 0 ? void 0 : _a.toString()) || '', step: step, onChange: this.handleTextChange }));
    }
    renderBooleanInput() {
        const options = [
            { text: 'True', value: 'true' },
            { text: 'False', value: 'false' },
        ];
        const valueAsString = this.value === true || this.value === 'true' ? 'true' : 'false';
        const selectedOption = options.find((o) => o.value === valueAsString);
        return (h("limel-select", { label: this.label, options: options, value: selectedOption, onChange: this.handleBooleanChange }));
    }
    renderOptionInput(property) {
        if (!property.options || property.options.length === 0) {
            return this.renderTextInput();
        }
        const options = property.options.map((opt) => ({
            text: opt.text || opt.key,
            value: opt.key,
        }));
        const selectedOption = options.find((o) => o.value === this.value);
        return (h("limel-select", { label: this.label, options: options, value: selectedOption, onChange: this.handleSelectChange }));
    }
    renderDateTimeInput(type) {
        // Convert string to Date if needed
        const dateValue = typeof this.value === 'string' ? new Date(this.value) : this.value;
        const pickerType = mapPropertyTypeToPickerType(type);
        return (h("limel-date-picker", { label: this.label, value: dateValue, type: pickerType, onChange: this.handleDateChange }));
    }
    renderMultiValueInput() {
        // For IN operator, allow comma-separated values
        const displayValue = Array.isArray(this.value)
            ? this.value.join(', ')
            : this.value || '';
        return (h("limel-input-field", { label: this.label + ' (comma-separated)', value: displayValue, placeholder: "e.g., won, lost, tender", onChange: this.handleMultiValueChange }));
    }
    getProperty() {
        if (!this.limetypes || !this.limetype || !this.propertyPath) {
            return;
        }
        return getPropertyFromPath(this.limetypes, this.limetype, this.propertyPath);
    }
};
__decorate([
    Le()
], LimeQueryValueInput.prototype, "limetypes", void 0);
LimeQueryValueInput.style = limeQueryValueInputCss();

export { LimeQueryFilterGroupComponent as limebb_lime_query_filter_group, LimeQueryFilterNotComponent as limebb_lime_query_filter_not, LimeQueryValueInput as limebb_lime_query_value_input };
