import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useEffect, useRef, useState } from "react";
import { CheckCircle2, ChevronDown, ChevronRight, ChevronUp, CircleDashed, Copy, GripVertical, Pencil, } from "lucide-react";
import { DeleteIcon } from "../../components/ui/delete-icon";
import { Button } from "../../components/ui/button";
const DRAG_MIME = "application/x-personalization-rule-uid";
export function RuleList({ rules, selectedRuleId, appliedRuleId, disabled, onToggle, onApply, onDuplicate, onDelete, onMove, onRename, onReorder, renderRuleBody, }) {
    const [draggingUid, setDraggingUid] = useState(null);
    const [dropIndex, setDropIndex] = useState(null);
    if (rules.length === 0)
        return null;
    const sourceIndex = draggingUid
        ? rules.findIndex((rule) => rule.uid === draggingUid)
        : -1;
    const handleDragStart = (uid) => setDraggingUid(uid);
    const handleDragEnd = () => {
        setDraggingUid(null);
        setDropIndex(null);
    };
    const handleZoneDrop = (index) => {
        if (sourceIndex < 0) {
            handleDragEnd();
            return;
        }
        let toIndex = index;
        if (toIndex > sourceIndex)
            toIndex -= 1;
        if (toIndex !== sourceIndex) {
            onReorder(sourceIndex, toIndex);
        }
        handleDragEnd();
    };
    return (_jsxs("div", { className: "space-y-0", children: [rules.map((rule, index) => {
                const expanded = rule.uid === selectedRuleId;
                const isDragSource = draggingUid === rule.uid;
                return (_jsxs("div", { children: [_jsx(DropZone, { index: index, active: draggingUid !== null, hovered: dropIndex === index, isNoOp: sourceIndex >= 0 &&
                                (index === sourceIndex || index === sourceIndex + 1), onEnter: () => setDropIndex(index), onLeave: () => setDropIndex((n) => (n === index ? null : n)), onDrop: () => handleZoneDrop(index) }), _jsx(RuleAccordionItem, { rule: rule, expanded: expanded, applied: rule.uid === appliedRuleId, disabled: disabled, isFirst: index === 0, isLast: index === rules.length - 1, isDragSource: isDragSource, onToggle: () => onToggle(rule.uid), onApply: () => onApply(rule.uid), onRename: (name) => onRename(rule.uid, name), onMove: (direction) => onMove(rule.uid, direction), onDuplicate: () => onDuplicate(rule.uid), onDelete: () => onDelete(rule.uid), onDragStart: (event) => {
                                event.dataTransfer.effectAllowed = "move";
                                event.dataTransfer.setData(DRAG_MIME, rule.uid);
                                event.dataTransfer.setData("text/plain", rule.uid);
                                handleDragStart(rule.uid);
                            }, onDragEnd: handleDragEnd, children: expanded ? renderRuleBody(rule) : null })] }, rule.uid));
            }), _jsx(DropZone, { index: rules.length, active: draggingUid !== null, hovered: dropIndex === rules.length, isNoOp: sourceIndex === rules.length - 1, onEnter: () => setDropIndex(rules.length), onLeave: () => setDropIndex((n) => (n === rules.length ? null : n)), onDrop: () => handleZoneDrop(rules.length) })] }));
}
function DropZone({ active, hovered, isNoOp, onEnter, onLeave, onDrop, }) {
    const showHighlight = active && hovered && !isNoOp;
    return (_jsx("div", { onDragEnter: (event) => {
            if (!active)
                return;
            event.preventDefault();
            onEnter();
        }, onDragOver: (event) => {
            if (!active)
                return;
            event.preventDefault();
            event.dataTransfer.dropEffect = isNoOp ? "none" : "move";
            onEnter();
        }, onDragLeave: onLeave, onDrop: (event) => {
            if (!active)
                return;
            event.preventDefault();
            onDrop();
        }, className: `relative transition-[height,margin] duration-150 ${active ? "my-0.5 h-3" : "h-1.5"}`, children: active && (_jsx("div", { className: `pointer-events-none absolute inset-x-0 top-1/2 -translate-y-1/2 rounded transition-all ${showHighlight
                ? "bg-component-default h-1 shadow-[0_0_0_3px_color-mix(in_srgb,var(--color-component-default)_15%,transparent)]"
                : isNoOp
                    ? "h-px bg-transparent"
                    : "bg-neutral-grey-10 h-0.5"}` })) }));
}
function RuleAccordionItem({ rule, expanded, applied, disabled, isFirst, isLast, isDragSource, onToggle, onApply, onRename, onMove, onDuplicate, onDelete, onDragStart, onDragEnd, children, }) {
    const [editing, setEditing] = useState(false);
    const [draftName, setDraftName] = useState(rule.name || "");
    const inputRef = useRef(null);
    useEffect(() => {
        setDraftName(rule.name || "");
    }, [rule.name]);
    useEffect(() => {
        if (!editing)
            return;
        const id = window.setTimeout(() => {
            inputRef.current?.focus();
            inputRef.current?.select();
        }, 0);
        return () => window.clearTimeout(id);
    }, [editing]);
    const commitRename = () => {
        const next = draftName.trim();
        if (next && next !== rule.name) {
            onRename(next);
        }
        else {
            setDraftName(rule.name || "");
        }
        setEditing(false);
    };
    const cancelRename = () => {
        setDraftName(rule.name || "");
        setEditing(false);
    };
    const headerDraggable = !disabled && !editing;
    const handleHeaderDragStart = (event) => {
        if (!headerDraggable) {
            event.preventDefault();
            return;
        }
        // Don't drag when the gesture starts on a button or other exempt area
        // (action cluster, name edit input). Letting the user click these without
        // accidentally initiating a drag.
        const target = event.target;
        if (target?.closest("[data-drag-exempt]")) {
            event.preventDefault();
            return;
        }
        onDragStart(event);
    };
    return (_jsxs("div", { className: `overflow-hidden rounded border transition-colors ${expanded
            ? "border-component-default bg-feedback-blue-light/40"
            : "border-border-default bg-white"} ${isDragSource ? "opacity-40" : ""}`, children: [_jsxs("div", { draggable: headerDraggable, onDragStart: handleHeaderDragStart, onDragEnd: onDragEnd, className: `flex items-center gap-1 px-1.5 py-1.5 ${headerDraggable ? "cursor-grab active:cursor-grabbing" : ""}`, children: [_jsx("span", { "aria-hidden": true, className: "text-neutral-grey-50 flex size-5 shrink-0 items-center justify-center", children: _jsx(GripVertical, { className: "size-3.5" }) }), _jsx("button", { type: "button", onClick: onToggle, "aria-label": expanded ? "Collapse rule" : "Expand rule", "data-drag-exempt": true, className: "text-neutral-grey-50 hover:bg-neutral-grey-5 hover:text-neutral-grey-100 flex size-5 shrink-0 cursor-pointer items-center justify-center rounded", children: expanded ? (_jsx(ChevronDown, { className: "size-3.5" })) : (_jsx(ChevronRight, { className: "size-3.5" })) }), _jsx("button", { type: "button", onClick: onApply, disabled: disabled || applied, "data-drag-exempt": true, "aria-label": applied ? "Currently applied" : "Apply this rule", "aria-pressed": applied, title: applied ? "Currently applied" : "Apply this rule", className: `flex size-5 shrink-0 items-center justify-center rounded ${applied
                            ? "cursor-default"
                            : "hover:bg-neutral-grey-5 cursor-pointer disabled:cursor-not-allowed"}`, children: applied ? (_jsx(CheckCircle2, { className: "text-component-default size-3.5" })) : (_jsx(CircleDashed, { className: "text-neutral-grey-50 hover:text-neutral-grey-50 size-3.5" })) }), editing ? (_jsx("input", { ref: inputRef, type: "text", "data-drag-exempt": true, className: "border-border-default badge-pad-sm focus:border-component-default min-w-0 flex-1 rounded border text-xs outline-none", value: draftName, disabled: disabled, onChange: (event) => setDraftName(event.target.value), onBlur: commitRename, onKeyDown: (event) => {
                            if (event.key === "Enter") {
                                event.preventDefault();
                                commitRename();
                            }
                            else if (event.key === "Escape") {
                                event.preventDefault();
                                cancelRename();
                            }
                        } })) : (_jsxs("button", { type: "button", "data-drag-exempt": true, className: "text-neutral-grey-100 flex min-w-0 flex-1 items-center gap-2 truncate text-left text-xs font-medium", onClick: onToggle, onDoubleClick: () => !disabled && setEditing(true), title: rule.name || "Unnamed rule", children: [_jsx("span", { className: "truncate", children: rule.name || "Unnamed rule" }), rule.unsupported && (_jsx("span", { className: "bg-feedback-orange-light badge-pad-sm text-2xs text-feedback-orange shrink-0 rounded", children: "limited" }))] })), _jsxs("div", { "data-drag-exempt": true, className: "flex shrink-0 items-center", children: [_jsx(IconActionButton, { label: "Rename", disabled: disabled || editing, onClick: () => setEditing(true), children: _jsx(Pencil, { className: "size-3" }) }), _jsx(IconActionButton, { label: "Move up", disabled: disabled || isFirst, onClick: () => onMove(-1), children: _jsx(ChevronUp, { className: "size-3" }) }), _jsx(IconActionButton, { label: "Move down", disabled: disabled || isLast, onClick: () => onMove(1), children: _jsx(ChevronDown, { className: "size-3" }) }), _jsx(IconActionButton, { label: "Duplicate", disabled: disabled, onClick: onDuplicate, children: _jsx(Copy, { className: "size-3" }) }), _jsx(IconActionButton, { label: "Delete", disabled: disabled, danger: true, onClick: onDelete, children: _jsx(DeleteIcon, { size: "sm" }) })] })] }), expanded && children ? (_jsx("div", { className: "border-border-default border-t bg-white p-3", children: children })) : null] }));
}
function IconActionButton({ label, disabled, danger, onClick, children, }) {
    return (_jsx(Button, { type: "button", size: "xxs", variant: "ghost", disabled: disabled, onClick: onClick, "aria-label": label, title: label, className: `size-6 rounded-md p-0 ${danger
            ? "text-neutral-grey-50 hover:bg-neutral-grey-5 hover:text-neutral-grey-50"
            : ""}`, children: children }));
}
//# sourceMappingURL=RuleList.js.map