import { useRef, useState } from 'react';
import {
    IconBorderRadius, IconRadiusTopLeft, IconRadiusTopRight,
    IconRadiusBottomLeft, IconRadiusBottomRight, IconBoxPadding,
    IconAdjustmentsHorizontal, IconBorderCorners,
    IconEye, IconEyeOff, IconMinus, IconDropletHalf2, IconCheck,
} from '@tabler/icons-react';
import { Popover, PopoverTrigger, PopoverContent } from '@/components/ui/popover';
import {
    NumInput, Row, RowLabel, IconBtn, IconSegment, FigSlider, FigSelect, FigCheck, T,
} from '../../ui/figma';
import FloatingPanel from '../../ui/FloatingPanel';
import { ColorRow } from '../../ui/ColorControl';
import {
    COLOR_ADJUST_DEFAULTS, BLEND_MODE_GROUPS, BLEND_MODE_OPTIONS, GRADIENT_ANGLE_DEFAULT,
} from '../propertyControls';

/* ------------------------------------------------------------------ *
 *  Fill controls — solid / linear / radial (Figma fill editor lite)
 * ------------------------------------------------------------------ */

export function FillControls({
    styles,
    setStyle,
    // Optional: write several keys as ONE edit. Callers that rebuild a whole
    // paint from the styles they were handed (the per-character text fill) must
    // pass it, or a two-call edit loses the first half.
    setStyles = null,
    // Rendered beside the Angle field — the canvas gizmo's show/hide button.
    angleAction = null,
    gate = () => true,
    typeKey = 'backgroundType',
    solidKey = 'backgroundColor',
    solidDefault = 'transparent',
    allowEmptySolid = true,
    // Namespaces the gradient keys so a second fill on the same element (the
    // border) can be edited by these very controls without colliding with the
    // element's own gradient — 'border' → borderGradientColor1, and so on.
    gradientPrefix = '',
}) {
    const gk = (name) => (gradientPrefix
        ? `${gradientPrefix}${name[0].toUpperCase()}${name.slice(1)}`
        : name);
    const fillType = styles[typeKey] || 'solid';
    return (
        <div className="flex flex-col gap-2">
            {gate(typeKey) && (
                <IconSegment
                    value={fillType}
                    onChange={(v) => {
                        // Turning a fill INTO a linear gradient stamps the house angle,
                        // whatever stale angle the styles were carrying — picking
                        // Linear is a fresh choice, and the number in the field should
                        // be the number in the file for the canvas gizmo to aim from.
                        // Re-picking Linear while already linear leaves the user's own
                        // aim alone. One patch where the caller can take one: a
                        // per-character paint is rebuilt whole on every write, so two
                        // calls would drop the first.
                        const patch = { [typeKey]: v };
                        if (v === 'linear' && fillType !== 'linear') {
                            patch[gk('gradientAngle')] = GRADIENT_ANGLE_DEFAULT;
                        }
                        // The stops go in too, on a fill that has never had any: the
                        // renderers fall back to the SOLID colour for both ends, which
                        // paints a flat block while the panel shows white → grey. The
                        // gradient starts from the colour the layer already wears, so
                        // switching to it is a nudge rather than a jump.
                        if (v !== 'solid' && styles[gk('gradientColor1')] == null) {
                            const solid = styles[solidKey];
                            patch[gk('gradientColor1')] = (solid && solid !== 'transparent') ? solid : '#ffffff';
                        }
                        if (v !== 'solid' && styles[gk('gradientColor2')] == null) {
                            patch[gk('gradientColor2')] = '#e4e4e7';
                        }
                        if (setStyles) {
                            setStyles(patch);
                            return;
                        }
                        // One key at a time, type first so the rest lands on a fill
                        // that already knows it is a gradient.
                        setStyle(typeKey, v);
                        Object.entries(patch).forEach(([k, val]) => {
                            if (k !== typeKey) setStyle(k, val);
                        });
                    }}
                    options={[
                        { value: 'solid', label: 'Solid', render: () => <span className="text-[11px]">Solid</span> },
                        { value: 'linear', label: 'Linear gradient', render: () => <span className="text-[11px]">Linear</span> },
                        { value: 'radial', label: 'Radial gradient', render: () => <span className="text-[11px]">Radial</span> },
                    ]}
                />
            )}
            {fillType === 'solid' && gate(solidKey) && (
                <ColorRow
                    label="Fill"
                    value={styles[solidKey] || solidDefault}
                    allowEmpty={allowEmptySolid}
                    onChange={(v) => setStyle(solidKey, v)}
                />
            )}
            {fillType !== 'solid' && gate(gk('gradientColor1')) && (
                <>
                    <ColorRow
                        label="Gradient start"
                        value={styles[gk('gradientColor1')] || '#ffffff'}
                        onChange={(v) => setStyle(gk('gradientColor1'), v)}
                    />
                    <ColorRow
                        label="Gradient end"
                        value={styles[gk('gradientColor2')] || '#e4e4e7'}
                        onChange={(v) => setStyle(gk('gradientColor2'), v)}
                    />
                    {fillType === 'linear' && (
                        <Row>
                            <div className="flex items-center gap-1">
                                <NumInput
                                    label="Angle"
                                    title="Gradient angle"
                                    value={styles[gk('gradientAngle')] ?? GRADIENT_ANGLE_DEFAULT}
                                    min={0}
                                    max={360}
                                    suffix="°"
                                    onChange={(v) => setStyle(gk('gradientAngle'), v)}
                                    className="flex-1"
                                />
                                {/* Shows/hides the canvas gizmo — only the fill that
                                    HAS one passes this in (see RightPanel). */}
                                {angleAction}
                            </div>
                            <span />
                        </Row>
                    )}
                    {fillType === 'radial' && (
                        <Row>
                            <NumInput
                                label="X"
                                title="Gradient center X"
                                value={styles[gk('gradientCenterX')] ?? 50}
                                min={0}
                                max={100}
                                suffix="%"
                                onChange={(v) => setStyle(gk('gradientCenterX'), v)}
                            />
                            <NumInput
                                label="Y"
                                title="Gradient center Y"
                                value={styles[gk('gradientCenterY')] ?? 50}
                                min={0}
                                max={100}
                                suffix="%"
                                onChange={(v) => setStyle(gk('gradientCenterY'), v)}
                            />
                        </Row>
                    )}
                </>
            )}
        </div>
    );
}

/* ------------------------------------------------------------------ *
 *  Corner radius — single input + expand to independent corners
 * ------------------------------------------------------------------ */

/** The four corner values, each falling back to the shared `borderRadius`. */
export function cornerRadii(styles = {}) {
    const base = Number(styles.borderRadius) || 0;
    return {
        base,
        tl: styles.borderTopLeftRadius ?? base,
        tr: styles.borderTopRightRadius ?? base,
        br: styles.borderBottomRightRadius ?? base,
        bl: styles.borderBottomLeftRadius ?? base,
    };
}

/** True when the corners disagree — the panel opens the per-corner row for it. */
export function hasMixedRadii(styles = {}) {
    const { base, ...c } = cornerRadii(styles);
    return new Set(Object.values(c).map(Number)).size > 1;
}

/**
 * The shared radius field plus the expander. `expanded` is owned by the caller
 * so the per-corner inputs can be laid out where they fit — the section renders
 * them full width below this row, not squeezed into this half column.
 */
export function CornerRadiusControl({
    styles, setStyle, setStyles, max = 400, disabled = false,
    // Path shapes round every corner of an arbitrary outline by one value — there
    // is no "top left" corner to set on a star, so the expander is hidden.
    allowIndependent = true,
    expanded = false,
    onToggleExpanded,
}) {
    const { base, ...corners } = cornerRadii(styles);
    const mixed = hasMixedRadii(styles);

    const setAll = (v) => {
        const patch = {
            borderRadius: v,
            borderTopLeftRadius: v,
            borderTopRightRadius: v,
            borderBottomRightRadius: v,
            borderBottomLeftRadius: v,
        };
        if (setStyles) setStyles(patch);
        else Object.entries(patch).forEach(([k, val]) => setStyle(k, val));
    };

    return (
        <div className="flex items-center gap-1">
            <NumInput
                icon={IconBorderRadius}
                title="Corner radius"
                value={mixed && !expanded ? base : (expanded ? base : corners.tl)}
                min={0}
                max={max}
                disabled={disabled}
                onChange={setAll}
                className="flex-1"
            />
            {allowIndependent && (
                <IconBtn
                    icon={IconBorderCorners}
                    label="Independent corners"
                    active={expanded}
                    disabled={disabled}
                    onClick={() => onToggleExpanded?.(!expanded)}
                />
            )}
        </div>
    );
}

/**
 * The four corners as a 2×2 block — TL/TR over BR/BL — laid out like the
 * padding sides above it, so the two expanders read as the same control.
 */
export function CornerRadiusRow({ styles, setStyle, max = 400, disabled = false, className = '' }) {
    const c = cornerRadii(styles);
    const fields = [
        { key: 'borderTopLeftRadius', icon: IconRadiusTopLeft, title: 'Top left', value: c.tl },
        { key: 'borderTopRightRadius', icon: IconRadiusTopRight, title: 'Top right', value: c.tr },
        { key: 'borderBottomRightRadius', icon: IconRadiusBottomRight, title: 'Bottom right', value: c.br },
        { key: 'borderBottomLeftRadius', icon: IconRadiusBottomLeft, title: 'Bottom left', value: c.bl },
    ];
    return (
        <Row cols={2} className={className}>
            {fields.map((f) => (
                <NumInput
                    key={f.key}
                    icon={f.icon}
                    title={f.title}
                    value={f.value}
                    min={0}
                    max={max}
                    disabled={disabled}
                    onChange={(v) => setStyle(f.key, v)}
                />
            ))}
        </Row>
    );
}

/* ------------------------------------------------------------------ *
 *  Padding — single input + expand to per-side (Figma auto-layout style)
 * ------------------------------------------------------------------ */

export function PaddingControl({ styles, setStyle, setStyles, disabled = false }) {
    const base = Number(styles.padding) || 0;
    const sides = {
        t: styles.paddingTop ?? base,
        r: styles.paddingRight ?? base,
        b: styles.paddingBottom ?? base,
        l: styles.paddingLeft ?? base,
    };
    const mixed = new Set(Object.values(sides).map(Number)).size > 1;
    const [expanded, setExpanded] = useState(mixed);

    const setAll = (v) => {
        const patch = { padding: v, paddingTop: v, paddingRight: v, paddingBottom: v, paddingLeft: v };
        if (setStyles) setStyles(patch);
        else Object.entries(patch).forEach(([k, val]) => setStyle(k, val));
    };

    return (
        <>
            <div className="flex items-center gap-1">
                <NumInput
                    icon={IconBoxPadding}
                    title="Padding"
                    value={mixed && !expanded ? base : (expanded ? base : sides.t)}
                    min={0}
                    max={400}
                    disabled={disabled}
                    onChange={setAll}
                    className="flex-1"
                />
                <IconBtn
                    icon={IconBorderCorners}
                    label="Independent padding"
                    active={expanded}
                    disabled={disabled}
                    onClick={() => setExpanded(!expanded)}
                />
            </div>
            {expanded && (
                <Row cols={2} className="mt-2">
                    <NumInput label="T" title="Padding top" value={sides.t} min={0} max={400} disabled={disabled} onChange={(v) => setStyle('paddingTop', v)} />
                    <NumInput label="R" title="Padding right" value={sides.r} min={0} max={400} disabled={disabled} onChange={(v) => setStyle('paddingRight', v)} />
                    <NumInput label="B" title="Padding bottom" value={sides.b} min={0} max={400} disabled={disabled} onChange={(v) => setStyle('paddingBottom', v)} />
                    <NumInput label="L" title="Padding left" value={sides.l} min={0} max={400} disabled={disabled} onChange={(v) => setStyle('paddingLeft', v)} />
                </Row>
            )}
        </>
    );
}

/* ------------------------------------------------------------------ *
 *  Effect row — label + on-dot + settings popover (Figma effects list)
 * ------------------------------------------------------------------ */

/**
 * `open`/`onToggle`/`onClose` optional — when supplied the row is controlled by
 * the parent, so only ONE effect popover is ever open (opening another closes the
 * previous). Falls back to local state if omitted.
 */
export function EffectRow({ label, active, children, onClear, anchorRef, open: openProp, onToggle, onClose }) {
    const [openLocal, setOpenLocal] = useState(false);
    const controlled = openProp !== undefined;
    const open = controlled ? openProp : openLocal;
    const toggle = () => (controlled ? onToggle?.() : setOpenLocal((v) => !v));
    const close = () => (controlled ? onClose?.() : setOpenLocal(false));
    const btnRef = useRef(null);
    // Prefer the section-level anchor so every effect panel opens in the same spot,
    // rather than each one stepping down the panel with its own row.
    const positionFrom = anchorRef || btnRef;
    return (
        <div className="flex items-center gap-1.5 h-7">
            <span className={`h-1.5 w-1.5 rounded-full shrink-0 ${active ? 'bg-[#0d99ff]' : 'bg-black/15 dark:bg-white/20'}`} />
            <span className={`flex-1 text-[11px] truncate ${active ? T.text : T.textSoft}`}>{label}</span>
            {active && onClear && (
                <button
                    type="button"
                    onClick={onClear}
                    className={`text-[10px] px-1 rounded ${T.textSoft} hover:text-black dark:hover:text-white`}
                    title={`Remove ${label.toLowerCase()}`}
                >
                    Remove
                </button>
            )}
            <span ref={btnRef}>
                <IconBtn
                    icon={IconAdjustmentsHorizontal}
                    label={`${label} settings`}
                    size={13}
                    active={open}
                    onClick={toggle}
                />
            </span>
            <FloatingPanel
                open={open}
                onClose={close}
                title={label}
                anchorRef={positionFrom}
                width={240}
            >
                {children}
            </FloatingPanel>
        </div>
    );
}

/* ------------------------------------------------------------------ *
 *  Repeatable list rows — strokes and effects, Figma style: every entry
 *  carries its own show/hide eye and its own remove button.
 * ------------------------------------------------------------------ */

/** The eye + minus pair that ends every stroke / effect row. */
export function ListRowActions({ visible = true, onToggleVisible, onRemove, label = 'item' }) {
    return (
        <>
            <IconBtn
                icon={visible ? IconEye : IconEyeOff}
                label={visible ? `Hide ${label}` : `Show ${label}`}
                size={13}
                onClick={onToggleVisible}
            />
            <IconBtn icon={IconMinus} label={`Remove ${label}`} size={13} onClick={onRemove} />
        </>
    );
}

/** One stroke: colour + opacity (from the swatch's alpha), eye, remove. */
export function StrokeEntryRow({ stroke, onChange, onToggleVisible, onRemove }) {
    return (
        <div className={`mb-1 ${stroke.visible === false ? 'opacity-40' : ''}`}>
            <ColorRow
                value={stroke.color || '#000000'}
                onChange={(v) => onChange({ color: v })}
                trailing={(
                    <ListRowActions
                        visible={stroke.visible !== false}
                        onToggleVisible={onToggleVisible}
                        onRemove={onRemove}
                        label="stroke"
                    />
                )}
            />
        </div>
    );
}

/** One effect entry: label + settings popover + eye + remove. */
export function EffectEntryRow({
    label, fx, children, anchorRef, open, onToggleOpen, onClose, onToggleVisible, onRemove,
}) {
    const btnRef = useRef(null);
    const visible = fx.visible !== false;
    return (
        <div className={`flex items-center gap-1.5 h-7 ${visible ? '' : 'opacity-40'}`}>
            <span className="h-1.5 w-1.5 rounded-full shrink-0 bg-[#0d99ff]" />
            <span className={`flex-1 text-[11px] truncate ${T.text}`}>{label}</span>
            <span ref={btnRef}>
                <IconBtn
                    icon={IconAdjustmentsHorizontal}
                    label={`${label} settings`}
                    size={13}
                    active={open}
                    onClick={onToggleOpen}
                />
            </span>
            <ListRowActions
                visible={visible}
                onToggleVisible={onToggleVisible}
                onRemove={onRemove}
                label={label.toLowerCase()}
            />
            <FloatingPanel
                open={open}
                onClose={onClose}
                title={label}
                anchorRef={anchorRef || btnRef}
                width={240}
            >
                {children}
            </FloatingPanel>
        </div>
    );
}

/** X / Y / Blur / Spread / Color for ONE entry in an effects list. */
export function ShadowEntrySettings({ fx, onChange, spread = true }) {
    return (
        <>
            <Row>
                <NumInput label="X" value={fx.offsetX ?? 0} min={-200} max={200} onChange={(v) => onChange({ offsetX: v })} />
                <NumInput label="Y" value={fx.offsetY ?? 0} min={-200} max={200} onChange={(v) => onChange({ offsetY: v })} />
            </Row>
            <Row>
                <NumInput label="Blur" value={fx.blur ?? 0} min={0} max={200} onChange={(v) => onChange({ blur: v })} />
                {spread
                    ? <NumInput label="Spread" value={fx.spread ?? 0} min={-100} max={100} onChange={(v) => onChange({ spread: v })} />
                    : <span />}
            </Row>
            <div className="mt-1.5">
                <ColorRow value={fx.color || '#00000040'} onChange={(v) => onChange({ color: v })} />
            </div>
        </>
    );
}

/** X / Y / Blur / Spread / Color — the standard shadow settings body.
 *  `spread` off for text-shadow (CSS text-shadow has no spread). */
export function ShadowSettings({ prefix, styles, setStyle, colorKey, colorDefault, spread = true }) {
    return (
        <>
            <Row>
                <NumInput label="X" value={styles[`${prefix}OffsetX`] ?? 0} min={-200} max={200} onChange={(v) => setStyle(`${prefix}OffsetX`, v)} />
                <NumInput label="Y" value={styles[`${prefix}OffsetY`] ?? 0} min={-200} max={200} onChange={(v) => setStyle(`${prefix}OffsetY`, v)} />
            </Row>
            <Row>
                <NumInput label="Blur" value={styles[`${prefix}Blur`] ?? 0} min={0} max={200} onChange={(v) => setStyle(`${prefix}Blur`, v)} className={spread ? '' : 'col-span-2'} />
                {spread && (
                    <NumInput label="Spread" value={styles[`${prefix}Spread`] ?? 0} min={-100} max={200} onChange={(v) => setStyle(`${prefix}Spread`, v)} />
                )}
            </Row>
            <ColorRow
                value={styles[colorKey] || colorDefault}
                onChange={(v) => setStyle(colorKey, v)}
            />
        </>
    );
}

/* ------------------------------------------------------------------ *
 *  Settings bodies for the new Figma effects (blur / noise / texture /
 *  shader / glass). Each is the popover content for its EffectRow.
 * ------------------------------------------------------------------ */

const BLEND_OPTIONS = [
    { value: 'normal', label: 'Normal' },
    { value: 'multiply', label: 'Multiply' },
    { value: 'screen', label: 'Screen' },
    { value: 'overlay', label: 'Overlay' },
    { value: 'soft-light', label: 'Soft light' },
    { value: 'hard-light', label: 'Hard light' },
    { value: 'color-dodge', label: 'Color dodge' },
    { value: 'color-burn', label: 'Color burn' },
    { value: 'difference', label: 'Difference' },
    { value: 'luminosity', label: 'Luminosity' },
];

/** Single-radius blur (Layer blur / Background blur) */
export function BlurSettings({ styleKey, value, setStyle, max = 100 }) {
    return (
        <FigSlider label="Blur" min={0} max={max} value={value ?? 0} defaultValue={0} onChange={(v) => setStyle(styleKey, v)} />
    );
}

export function NoiseSettings({ styles, setStyle }) {
    return (
        <>
            <FigSlider label="Amount" min={0} max={100} value={styles.noiseAmount ?? 0} onChange={(v) => setStyle('noiseAmount', v)} />
            <FigSlider label="Density" min={2} max={100} value={styles.noiseDensity ?? 100} onChange={(v) => setStyle('noiseDensity', v)} />
            <FigSlider label="Size" min={1} max={16} value={styles.noiseSize ?? 2} onChange={(v) => setStyle('noiseSize', v)} />
            <div className="mt-2">
                <RowLabel>Type</RowLabel>
                <IconSegment
                    value={styles.noiseType || 'mono'}
                    onChange={(v) => setStyle('noiseType', v)}
                    options={[
                        { value: 'mono', label: 'Monochrome', render: () => <span className="text-[11px]">Mono</span> },
                        { value: 'color', label: 'Colour', render: () => <span className="text-[11px]">Colour</span> },
                    ]}
                />
            </div>
            <div className="mt-2">
                <RowLabel>Blend</RowLabel>
                <FigSelect value={styles.noiseBlend || 'overlay'} options={BLEND_OPTIONS} onChange={(v) => setStyle('noiseBlend', v)} />
            </div>
        </>
    );
}

const TEXTURE_OPTIONS = [
    { value: 'paper', label: 'Paper' },
    { value: 'grain', label: 'Grain' },
    { value: 'lines', label: 'Lines' },
    { value: 'cross', label: 'Cross-hatch' },
    { value: 'dots', label: 'Dots' },
    { value: 'grid', label: 'Grid' },
];

export function TextureSettings({ styles, setStyle }) {
    return (
        <>
            <RowLabel>Pattern</RowLabel>
            <div className="mb-2">
                <FigSelect
                    value={styles.textureType && styles.textureType !== 'none' ? styles.textureType : 'paper'}
                    options={TEXTURE_OPTIONS}
                    onChange={(v) => setStyle('textureType', v)}
                />
            </div>
            <FigSlider label="Opacity" min={0} max={100} value={styles.textureOpacity ?? 40} onChange={(v) => setStyle('textureOpacity', v)} />
            <FigSlider label="Scale" min={2} max={64} value={styles.textureScale ?? 6} onChange={(v) => setStyle('textureScale', v)} />
            <div className="my-2">
                <ColorRow label="Colour" value={styles.textureColor || '#000000'} onChange={(v) => setStyle('textureColor', v)} />
            </div>
            <RowLabel>Blend</RowLabel>
            <FigSelect value={styles.textureBlend || 'multiply'} options={BLEND_OPTIONS} onChange={(v) => setStyle('textureBlend', v)} />
        </>
    );
}

const SHADER_OPTIONS = [
    { value: 'mesh', label: 'Gradient mesh' },
    { value: 'aurora', label: 'Aurora' },
    { value: 'holographic', label: 'Holographic' },
    { value: 'sunset', label: 'Sunset' },
];

export function ShaderSettings({ styles, setStyle }) {
    return (
        <>
            <RowLabel>Preset</RowLabel>
            <div className="mb-2">
                <FigSelect
                    value={styles.shaderType && styles.shaderType !== 'none' ? styles.shaderType : 'mesh'}
                    options={SHADER_OPTIONS}
                    onChange={(v) => setStyle('shaderType', v)}
                />
            </div>
            <div className="flex flex-col gap-2 mb-2">
                <ColorRow label="Colour 1" value={styles.shaderColor1 || '#ff5d8f'} onChange={(v) => setStyle('shaderColor1', v)} />
                <ColorRow label="Colour 2" value={styles.shaderColor2 || '#4d7cff'} onChange={(v) => setStyle('shaderColor2', v)} />
                <ColorRow label="Colour 3" value={styles.shaderColor3 || '#9d4dff'} onChange={(v) => setStyle('shaderColor3', v)} />
            </div>
            <FigSlider label="Opacity" min={0} max={100} value={styles.shaderOpacity ?? 100} onChange={(v) => setStyle('shaderOpacity', v)} />
            <FigSlider label="Angle" min={0} max={360} value={styles.shaderAngle ?? 45} onChange={(v) => setStyle('shaderAngle', v)} />
            <div className="mt-1">
                <RowLabel>Blend</RowLabel>
                <FigSelect value={styles.shaderBlend || 'normal'} options={BLEND_OPTIONS} onChange={(v) => setStyle('shaderBlend', v)} />
            </div>
        </>
    );
}

export function GlassSettings({ styles, setStyle }) {
    return (
        <>
            <FigSlider label="Blur" min={0} max={60} value={styles.glassBlur ?? 0} defaultValue={0} onChange={(v) => setStyle('glassBlur', v)} />
            <FigSlider label="Tint" min={0} max={100} value={styles.glassOpacity ?? 12} onChange={(v) => setStyle('glassOpacity', v)} />
            <div className="my-2">
                <ColorRow label="Tint colour" value={styles.glassTint || '#ffffff'} onChange={(v) => setStyle('glassTint', v)} />
            </div>
            <FigCheck
                label="Edge highlight"
                checked={styles.glassHighlight !== false}
                onChange={(v) => setStyle('glassHighlight', v)}
            />
        </>
    );
}

/* ------------------------------------------------------------------ *
 *  Blend mode popover — Figma's Appearance blend menu
 * ------------------------------------------------------------------ */

/**
 * Figma puts blend mode in the Appearance header, left of the adjust button: a
 * droplet that opens a grouped menu with a tick on the active mode. Radix flips
 * and shifts the menu against the viewport, so it stays on screen whether the
 * section sits at the top or the bottom of a scrolled panel.
 */
export function BlendModePopoverButton({ styles, setStyle }) {
    const [open, setOpen] = useState(false);
    const value = styles.mixBlendMode || 'normal';
    const current = BLEND_MODE_OPTIONS.find((o) => o.value === value);

    return (
        <Popover open={open} onOpenChange={setOpen}>
            <PopoverTrigger asChild>
                <span>
                    <IconBtn
                        icon={IconDropletHalf2}
                        label={`Blend mode${current ? ` — ${current.label}` : ''}`}
                        active={value !== 'normal'}
                    />
                </span>
            </PopoverTrigger>
            <PopoverContent
                side="left"
                align="start"
                sideOffset={12}
                collisionPadding={8}
                className={`w-[168px] p-1 rounded-[13px] ${T.border} dark:bg-[#2c2c2c] shadow-xl
                    max-h-[var(--radix-popover-content-available-height)] overflow-y-auto`}
            >
                {BLEND_MODE_GROUPS.map((group, i) => (
                    <div key={group[0].value} className={i ? `mt-1 pt-1 border-t ${T.border}` : ''}>
                        {group.map((o) => {
                            const active = o.value === value;
                            return (
                                <button
                                    key={o.value}
                                    type="button"
                                    onClick={() => { setStyle('mixBlendMode', o.value); setOpen(false); }}
                                    className={`w-full h-7 pl-6 pr-2 flex items-center rounded-[5px] text-[11px] text-left
                                        ${T.text} ${T.hoverBg} relative`}
                                >
                                    {active && (
                                        <IconCheck size={12} className="absolute left-1.5 text-[#0d99ff]" />
                                    )}
                                    {o.label}
                                </button>
                            );
                        })}
                    </div>
                ))}
            </PopoverContent>
        </Popover>
    );
}

/* ------------------------------------------------------------------ *
 *  Color adjust popover — hue / saturation / brightness / … sliders
 * ------------------------------------------------------------------ */

export function AdjustPopoverButton({ styles, setStyle, gate = () => true }) {
    const keys = Object.keys(COLOR_ADJUST_DEFAULTS);
    const isDefault = keys.every((k) => {
        const def = COLOR_ADJUST_DEFAULTS[k];
        return (styles[k] == null ? def : Number(styles[k])) === def;
    });
    const resetAll = () => keys.forEach((k) => setStyle(k, COLOR_ADJUST_DEFAULTS[k]));

    const sliders = [
        { key: 'hueRotate', label: 'Hue', min: 0, max: 360 },
        { key: 'saturate', label: 'Saturation', min: 0, max: 200 },
        { key: 'brightness', label: 'Brightness', min: 0, max: 200 },
        { key: 'contrast', label: 'Contrast', min: 0, max: 200 },
        { key: 'grayscale', label: 'Grayscale', min: 0, max: 100 },
        { key: 'sepia', label: 'Sepia', min: 0, max: 100 },
        { key: 'invert', label: 'Invert', min: 0, max: 100 },
    ].filter((s) => gate(s.key));

    if (!sliders.length) return null;

    return (
        <Popover>
            <PopoverTrigger asChild>
                <span>
                    <IconBtn icon={IconAdjustmentsHorizontal} label="Adjust colors" active={!isDefault} />
                </span>
            </PopoverTrigger>
            <PopoverContent side="left" align="start" sideOffset={12} className="w-[268px] p-3 rounded-[13px] border-[#e6e6e6] dark:border-[#444444] dark:bg-[#2c2c2c] shadow-xl">
                <div className="flex items-center justify-between mb-2">
                    <span className={`text-[11px] font-semibold ${T.text}`}>Adjust</span>
                    <button
                        type="button"
                        disabled={isDefault}
                        onClick={resetAll}
                        className={`text-[11px] ${T.textSoft} hover:text-black dark:hover:text-white disabled:opacity-30`}
                    >
                        Reset
                    </button>
                </div>
                <div className="flex flex-col gap-1">
                    {sliders.map(({ key, label, min, max }) => (
                        <FigSlider
                            key={key}
                            label={label}
                            min={min}
                            max={max}
                            value={styles[key] ?? COLOR_ADJUST_DEFAULTS[key]}
                            defaultValue={COLOR_ADJUST_DEFAULTS[key]}
                            onChange={(v) => setStyle(key, v)}
                        />
                    ))}
                </div>
            </PopoverContent>
        </Popover>
    );
}
