/**
 * Settings Schema System
 * Consolidated settings system with all features from both implementations
 */
/**
 * Built-in validation functions
 */
export const Validators = {
    required: (message = "This field is required") => (value) => {
        if (!value || (typeof value === "string" && !value.trim())) {
            return message;
        }
        return null;
    },
    email: (message = "Invalid email address") => (value) => {
        if (value && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) {
            return message;
        }
        return null;
    },
    url: (message = "Invalid URL") => (value) => {
        if (value) {
            try {
                new URL(value);
            }
            catch {
                return message;
            }
        }
        return null;
    },
    ipAddress: (message = "Invalid IP address") => (value) => {
        if (value) {
            const parts = value.split(".");
            if (parts.length !== 4)
                return message;
            for (const part of parts) {
                const num = parseInt(part, 10);
                if (isNaN(num) || num < 0 || num > 255)
                    return message;
            }
        }
        return null;
    },
    port: (message = "Invalid port number") => (value) => {
        if (value < 1 || value > 65535) {
            return message;
        }
        return null;
    },
    range: (min, max, message) => (value) => {
        if (value < min || value > max) {
            return message || `Value must be between ${min} and ${max}`;
        }
        return null;
    },
    pattern: (pattern, message = "Invalid format") => (value) => {
        if (value && !pattern.test(value)) {
            return message;
        }
        return null;
    },
    minLength: (min, message) => (value) => {
        if (value && value.length < min) {
            return message || `Must be at least ${min} characters`;
        }
        return null;
    },
    maxLength: (max, message) => (value) => {
        if (value && value.length > max) {
            return message || `Must be at most ${max} characters`;
        }
        return null;
    },
};
/**
 * Helper to create a settings schema
 */
export function createSettingsSchema(schema) {
    // Sort categories by order
    schema.categories.sort((a, b) => (a.order || 0) - (b.order || 0));
    return schema;
}
/**
 * Get setting by key from categories
 */
export function getSettingByKey(categories, key) {
    for (const category of categories) {
        const setting = category.settings.find((s) => s.key === key);
        if (setting)
            return setting;
    }
    return undefined;
}
/**
 * Validate a single setting
 */
export function validateSetting(setting, value) {
    // Check required
    if (setting.required &&
        (!value || (typeof value === "string" && !value.trim()))) {
        return setting.validationMessage || "This field is required";
    }
    // Type-specific validation
    switch (setting.type) {
        case "string":
        case "password":
        case "textarea":
            if (value && typeof value !== "string") {
                return setting.validationMessage || "Must be a string";
            }
            if (setting.validation) {
                if (setting.validation.minLength !== undefined &&
                    value.length < setting.validation.minLength) {
                    return (setting.validationMessage ||
                        `Must be at least ${setting.validation.minLength} characters`);
                }
                if (setting.validation.maxLength !== undefined &&
                    value.length > setting.validation.maxLength) {
                    return (setting.validationMessage ||
                        `Must be at most ${setting.validation.maxLength} characters`);
                }
                if (setting.validation.pattern &&
                    !new RegExp(setting.validation.pattern).test(value)) {
                    return setting.validationMessage || "Invalid format";
                }
            }
            break;
        case "email":
            if (value && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) {
                return setting.validationMessage || "Invalid email address";
            }
            break;
        case "url":
            try {
                if (value)
                    new URL(value);
            }
            catch {
                return setting.validationMessage || "Invalid URL";
            }
            break;
        case "ipaddress":
            if (value) {
                const parts = value.split(".");
                if (parts.length !== 4) {
                    return setting.validationMessage || "Invalid IP address";
                }
                for (const part of parts) {
                    const num = parseInt(part, 10);
                    if (isNaN(num) || num < 0 || num > 255) {
                        return setting.validationMessage || "Invalid IP address";
                    }
                }
            }
            break;
        case "number":
            if (typeof value !== "number" || isNaN(value)) {
                return setting.validationMessage || "Must be a valid number";
            }
            if (setting.validation) {
                if (setting.validation.min !== undefined &&
                    value < setting.validation.min) {
                    return (setting.validationMessage ||
                        `Must be at least ${setting.validation.min}`);
                }
                if (setting.validation.max !== undefined &&
                    value > setting.validation.max) {
                    return (setting.validationMessage ||
                        `Must be at most ${setting.validation.max}`);
                }
            }
            // Also check min/max at root level for backward compatibility
            if (setting.min !== undefined && value < setting.min) {
                return setting.validationMessage || `Must be at least ${setting.min}`;
            }
            if (setting.max !== undefined && value > setting.max) {
                return setting.validationMessage || `Must be at most ${setting.max}`;
            }
            break;
        case "boolean":
            if (typeof value !== "boolean") {
                return setting.validationMessage || "Must be true or false";
            }
            break;
        case "select":
        case "multiselect":
            if (setting.options) {
                if (setting.type === "select" &&
                    !setting.options.some((opt) => opt.value === value)) {
                    return setting.validationMessage || "Must select a valid option";
                }
                if (setting.type === "multiselect" && Array.isArray(value)) {
                    const validValues = setting.options.map((opt) => opt.value);
                    if (!value.every((v) => validValues.includes(v))) {
                        return setting.validationMessage || "Invalid selection";
                    }
                }
            }
            break;
        case "date":
        case "time":
        case "datetime":
            if (value && !Date.parse(value)) {
                return setting.validationMessage || "Invalid date/time";
            }
            break;
        case "color":
            if (value && !/^#[0-9A-Fa-f]{6}$/.test(value)) {
                return (setting.validationMessage || "Invalid color (must be hex format)");
            }
            break;
    }
    // Custom validation
    if (setting.validation?.custom) {
        const error = setting.validation.custom(value);
        if (error)
            return error;
    }
    return null;
}
/**
 * Validate all settings against schema
 */
export function validateSettings(schema, settings) {
    const errors = {};
    for (const category of schema.categories) {
        for (const setting of category.settings) {
            if (setting.hidden)
                continue;
            const value = settings[setting.key];
            const error = validateSetting(setting, value);
            if (error) {
                errors[setting.key] = error;
            }
        }
    }
    // Run custom validation
    if (schema.onValidate) {
        const customErrors = schema.onValidate(settings);
        if (customErrors) {
            Object.assign(errors, customErrors);
        }
    }
    return errors;
}
/**
 * Validate all settings (returns result object)
 */
export function validateAllSettings(categories, values) {
    const errors = {};
    for (const category of categories) {
        for (const setting of category.settings) {
            if (setting.hidden)
                continue;
            const value = values[setting.key];
            const error = validateSetting(setting, value);
            if (error) {
                errors[setting.key] = error;
            }
        }
    }
    return {
        isValid: Object.keys(errors).length === 0,
        errors,
    };
}
/**
 * Helper to flatten nested settings for storage
 */
export function flattenSettings(settings, prefix = "") {
    const flattened = {};
    for (const [key, value] of Object.entries(settings)) {
        const fullKey = prefix ? `${prefix}.${key}` : key;
        if (value &&
            typeof value === "object" &&
            !Array.isArray(value) &&
            !(value instanceof Date)) {
            Object.assign(flattened, flattenSettings(value, fullKey));
        }
        else {
            flattened[fullKey] = value;
        }
    }
    return flattened;
}
// Alias for consistency
export const flattenSettingsValues = flattenSettings;
/**
 * Helper to unflatten settings from storage
 */
export function unflattenSettings(flattened) {
    const settings = {};
    for (const [key, value] of Object.entries(flattened)) {
        const parts = key.split(".");
        let current = settings;
        for (let i = 0; i < parts.length - 1; i++) {
            const part = parts[i];
            if (!part)
                continue;
            if (!current[part]) {
                current[part] = {};
            }
            current = current[part];
        }
        const lastPart = parts[parts.length - 1];
        if (lastPart) {
            current[lastPart] = value;
        }
    }
    return settings;
}
// Alias for consistency
export const unflattenSettingsValues = unflattenSettings;
/**
 * Get all settings that require restart
 */
export function getRestartRequiredSettings(schema, changedSettings) {
    const restartRequired = [];
    // Handle both schema and categories array
    const categories = Array.isArray(schema) ? schema : schema.categories;
    // Handle both changed settings object and array of keys
    const changedKeys = Array.isArray(changedSettings)
        ? changedSettings
        : Object.keys(changedSettings);
    for (const category of categories) {
        for (const setting of category.settings) {
            if (setting.requiresRestart && changedKeys.includes(setting.key)) {
                restartRequired.push(setting.key);
            }
        }
    }
    return restartRequired;
}
/**
 * Get default values from settings
 */
export function getDefaultSettingsValues(categories) {
    const defaults = {};
    for (const category of categories) {
        for (const setting of category.settings) {
            if (!setting.hidden && setting.defaultValue !== undefined) {
                defaults[setting.key] = setting.defaultValue;
            }
        }
    }
    return defaults;
}
/**
 * Evaluate conditional visibility for a field
 */
export function evaluateFieldVisibility(field, currentValues) {
    if (!field.showIf) {
        return true;
    }
    try {
        return field.showIf(currentValues);
    }
    catch (_error) {
        console.error(`Error evaluating showIf for field ${field.key}:`, _error);
        return true; // Show field if evaluation fails
    }
}
/**
 * Group fields by their group property
 */
export function groupFields(fields) {
    const groups = new Map();
    // First, add ungrouped fields
    const ungrouped = fields.filter((f) => !f.group);
    if (ungrouped.length > 0) {
        groups.set("_default", ungrouped);
    }
    // Then, group the rest
    fields
        .filter((f) => f.group)
        .forEach((field) => {
        const group = field.group;
        if (!groups.has(group)) {
            groups.set(group, []);
        }
        groups.get(group).push(field);
    });
    // Sort fields within each group by order
    groups.forEach((groupFields) => {
        groupFields.sort((a, b) => (a.order || 999) - (b.order || 999));
    });
    return groups;
}
/**
 * Apply toStorage transform
 */
export function applyToStorageTransform(field, value) {
    if (field.transform?.toStorage) {
        return field.transform.toStorage(value);
    }
    return value;
}
/**
 * Apply fromStorage transform
 */
export function applyFromStorageTransform(field, value) {
    if (field.transform?.fromStorage) {
        return field.transform.fromStorage(value);
    }
    return value;
}
/**
 * Create settings form state
 */
export function createSettingsFormState(categories, initialValues) {
    const defaults = getDefaultSettingsValues(categories);
    const values = { ...defaults, ...initialValues };
    const validation = validateAllSettings(categories, values);
    return {
        values,
        errors: validation.errors,
        touched: {},
        dirty: {},
        isValid: validation.isValid,
        isSubmitting: false,
    };
}
//# sourceMappingURL=SettingsSchema.js.map