import { jsxs, jsx } from 'react/jsx-runtime';
import React__default, { useId, useState, useEffect, useMemo, useCallback } from 'react';
import { cronInputTheme } from './CronInput.theme.js';
import { parseCron, validateCron, cronToDescription, getNextRuns, CRON_PRESETS, getMinuteOptions, getHourOptions, getDayOfMonthOptions, getMonthOptions, getDayOfWeekOptions, formatNextRun, fieldsToCron } from './CronInput.utils.js';
import { FormLabel } from '../FormLabel/FormLabel.js';
import { cn } from '../../../utils/cn.js';
import { CalendarIcon, ClockIcon } from '@heroicons/react/24/outline';

const FieldSelect = ({ label, value, options, onChange, disabled, size = "md", className, }) => {
    const theme = cronInputTheme;
    return (jsxs("div", { className: theme.fieldGroupStyle, children: [jsx("label", { className: theme.fieldLabelStyle, children: label }), jsx("select", { value: value, onChange: (e) => onChange(e.target.value), disabled: disabled, className: cn(theme.fieldSelectStyle, theme.fieldSelectSizes[size], className), "aria-label": `Cron ${label.toLowerCase()} field`, children: options.map((option) => (jsx("option", { value: option.value, children: option.label }, option.value))) })] }));
};
// ============================================================================
// Main CronInput Component
// ============================================================================
const CronInput = React__default.forwardRef(({ value: controlledValue, defaultValue = "* * * * *", onChange, showPresets = true, showDescription = true, showNextRuns = true, nextRunCount = 3, size = "md", mode = "both", className, theme: themeOverrides, disabled = false, label, ...props }, ref) => {
    // Unique ID for accessibility
    const generatedId = useId();
    // Controlled vs uncontrolled state
    const isControlled = controlledValue !== undefined;
    const [internalValue, setInternalValue] = useState(defaultValue);
    const cronValue = isControlled ? controlledValue : internalValue;
    // Active mode when mode="both"
    const [activeMode, setActiveMode] = useState(mode === "both" ? "visual" : mode);
    // Raw input state (tracks what user is typing, may be invalid temporarily)
    const [rawInput, setRawInput] = useState(cronValue);
    // Sync raw input when controlled value changes
    useEffect(() => {
        if (isControlled) {
            setRawInput(controlledValue);
        }
    }, [controlledValue, isControlled]);
    // Merge theme with overrides
    const theme = useMemo(() => ({
        ...cronInputTheme,
        ...themeOverrides,
    }), [themeOverrides]);
    // Parse current cron value into fields
    const fields = useMemo(() => parseCron(cronValue), [cronValue]);
    // Validation state
    const isValid = useMemo(() => validateCron(cronValue), [cronValue]);
    // Human-readable description
    const description = useMemo(() => (isValid ? cronToDescription(cronValue) : ""), [cronValue, isValid]);
    // Next run times
    const nextRuns = useMemo(() => (isValid && showNextRuns ? getNextRuns(cronValue, nextRunCount) : []), [cronValue, isValid, showNextRuns, nextRunCount]);
    // Active preset detection
    const activePreset = useMemo(() => { var _a, _b; return (_b = (_a = CRON_PRESETS.find((p) => p.value === cronValue)) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : null; }, [cronValue]);
    // Memoized options
    const minuteOptions = useMemo(() => getMinuteOptions(), []);
    const hourOptions = useMemo(() => getHourOptions(), []);
    const dayOfMonthOptions = useMemo(() => getDayOfMonthOptions(), []);
    const monthOptions = useMemo(() => getMonthOptions(), []);
    const dayOfWeekOptions = useMemo(() => getDayOfWeekOptions(), []);
    // Update the cron value
    const updateValue = useCallback((newCron) => {
        if (!isControlled) {
            setInternalValue(newCron);
        }
        setRawInput(newCron);
        onChange === null || onChange === void 0 ? void 0 : onChange(newCron);
    }, [isControlled, onChange]);
    // Handle field change from visual builder
    const handleFieldChange = useCallback((field, newFieldValue) => {
        const newFields = { ...fields, [field]: newFieldValue };
        const newCron = fieldsToCron(newFields);
        updateValue(newCron);
    }, [fields, updateValue]);
    // Handle raw input change
    const handleRawInputChange = useCallback((e) => {
        const newRaw = e.target.value;
        setRawInput(newRaw);
        if (validateCron(newRaw)) {
            if (!isControlled) {
                setInternalValue(newRaw);
            }
            onChange === null || onChange === void 0 ? void 0 : onChange(newRaw);
        }
    }, [isControlled, onChange]);
    // Handle raw input blur - commit value if valid
    const handleRawInputBlur = useCallback(() => {
        if (validateCron(rawInput)) {
            updateValue(rawInput);
        }
        else {
            // Reset to last valid value
            setRawInput(cronValue);
        }
    }, [rawInput, cronValue, updateValue]);
    // Handle preset click
    const handlePresetClick = useCallback((presetValue) => {
        if (disabled)
            return;
        updateValue(presetValue);
    }, [disabled, updateValue]);
    // Handle Enter key in raw input
    const handleRawKeyDown = useCallback((e) => {
        if (e.key === "Enter") {
            handleRawInputBlur();
        }
    }, [handleRawInputBlur]);
    const showVisual = mode === "visual" || (mode === "both" && activeMode === "visual");
    const showRaw = mode === "raw" || (mode === "both" && activeMode === "raw");
    return (jsxs("div", { ref: ref, className: cn(theme.baseStyle, className), role: "group", "aria-label": label || "Cron expression builder", ...props, children: [label && (jsx(FormLabel, { htmlFor: `${generatedId}-cron`, state: disabled ? "disabled" : "default", children: label })), mode === "both" && (jsxs("div", { className: "flex items-center gap-1.5", children: [jsxs("button", { type: "button", onClick: () => setActiveMode("visual"), disabled: disabled, className: cn(theme.modeToggleStyle, activeMode === "visual" && theme.modeToggleActiveStyle), "aria-pressed": activeMode === "visual", children: [jsx(CalendarIcon, { className: "w-3.5 h-3.5 mr-1", "aria-hidden": "true" }), "Visual"] }), jsxs("button", { type: "button", onClick: () => setActiveMode("raw"), disabled: disabled, className: cn(theme.modeToggleStyle, activeMode === "raw" && theme.modeToggleActiveStyle), "aria-pressed": activeMode === "raw", children: [jsx(ClockIcon, { className: "w-3.5 h-3.5 mr-1", "aria-hidden": "true" }), "Cron"] })] })), showPresets && (jsxs("div", { children: [jsx("div", { className: cn(theme.sectionHeadingStyle, "mb-1.5"), children: "Presets" }), jsx("div", { className: "flex flex-wrap gap-1.5", children: CRON_PRESETS.map((preset) => (jsx("button", { type: "button", onClick: () => handlePresetClick(preset.value), disabled: disabled, className: cn(theme.presetButtonStyle, activePreset === preset.value && theme.presetButtonActiveStyle), title: preset.description, "aria-pressed": activePreset === preset.value, children: preset.label }, preset.value))) })] })), showVisual && (jsxs("div", { className: theme.builderStyle, children: [jsx(FieldSelect, { label: "Minute", value: fields.minute, options: minuteOptions, onChange: (v) => handleFieldChange("minute", v), disabled: disabled, size: size }), jsx(FieldSelect, { label: "Hour", value: fields.hour, options: hourOptions, onChange: (v) => handleFieldChange("hour", v), disabled: disabled, size: size }), jsx(FieldSelect, { label: "Day of Month", value: fields.dayOfMonth, options: dayOfMonthOptions, onChange: (v) => handleFieldChange("dayOfMonth", v), disabled: disabled, size: size }), jsx(FieldSelect, { label: "Month", value: fields.month, options: monthOptions, onChange: (v) => handleFieldChange("month", v), disabled: disabled, size: size }), jsx(FieldSelect, { label: "Day of Week", value: fields.dayOfWeek, options: dayOfWeekOptions, onChange: (v) => handleFieldChange("dayOfWeek", v), disabled: disabled, size: size })] })), showRaw && (jsxs("div", { children: [jsx("div", { className: cn(theme.sectionHeadingStyle, "mb-1.5"), children: "Cron Expression" }), jsx("input", { type: "text", value: rawInput, onChange: handleRawInputChange, onBlur: handleRawInputBlur, onKeyDown: handleRawKeyDown, disabled: disabled, placeholder: "* * * * *", className: cn(theme.rawInputStyle, theme.rawInputSizes[size]), id: `${generatedId}-cron`, "aria-label": "Cron expression", "aria-invalid": !validateCron(rawInput), spellCheck: false, autoComplete: "off" }), !validateCron(rawInput) && rawInput !== cronValue && (jsx("div", { className: cn(theme.errorStyle, "mt-1"), children: "Invalid cron expression. Format: minute hour day month weekday" }))] })), showVisual && !showRaw && (jsxs("div", { className: "flex items-center gap-2", children: [jsx("span", { className: cn(theme.fieldLabelStyle, "shrink-0"), children: "Expression:" }), jsx("code", { className: cn("font-mono text-sm px-2 py-1 rounded-[var(--form-radius)]", "bg-[var(--color-background-secondary)] text-[var(--color-text-primary)]", "dark:bg-[var(--color-neutral-800)] dark:text-[var(--color-neutral-200)]"), children: cronValue })] })), showDescription && isValid && (jsxs("div", { className: theme.descriptionStyle, children: [jsx(ClockIcon, { className: "w-4 h-4 shrink-0", "aria-hidden": "true" }), jsx("span", { children: description })] })), showNextRuns && isValid && nextRuns.length > 0 && (jsxs("div", { className: theme.nextRunsStyle, children: [jsx("div", { className: cn(theme.sectionHeadingStyle, "mb-1"), children: "Next runs" }), nextRuns.map((date, index) => (jsxs("div", { className: theme.nextRunItemStyle, children: [jsx(CalendarIcon, { className: "w-3.5 h-3.5 shrink-0", "aria-hidden": "true" }), jsx("span", { children: formatNextRun(date) })] }, index)))] }))] }));
});
CronInput.displayName = "CronInput";

export { CronInput };
