import * as Icons from '@/Components/Icons'
import { cn } from '@/lib/utils'

/**
 * Chooser for the `menu.Icon` column.
 *
 * A grid rather than a text box on purpose. The sidebar resolves the stored string with
 * `Icons[name]` (resolveIcon() in Components/Sidebar/Sidebar.jsx) and renders NOTHING when
 * the barrel does not export that name — so a plausible lucide name like `Building2` or
 * `List` is not an error anywhere, just a permanently empty slot in the nav. Showing the
 * real glyph next to every option makes that failure impossible to reach by typing.
 *
 * `options` is the server's allowlist (App\Support\MenuIcons::NAMES), which is what the
 * FormRequest validates against, so the grid can never offer something the save rejects.
 */
export default function IconPicker({ value, onChange, options, error = null, isChild = false }) {
    const current = value ?? ''

    // Rows written before this field existed carry names the barrel never exported. Offer
    // the row's own value as a tile rather than dropping it out of the grid: the server
    // grandfathers it (MenuIcons::allowedFor), so re-saving the menu untouched works, and
    // an admin who never opens this field should not have their icon silently rewritten.
    const unknown = current !== '' && !options.includes(current)

    return (
        <div>
            <label className="block text-sm font-medium text-gray-700 mb-1">Icon</label>
            <p className="mb-1 text-xs text-text-muted">
                {isChild
                    ? 'Only top-level menus show an icon in the sidebar. This one sits under a parent, so the choice is saved but not displayed.'
                    : 'Shown beside this menu in the sidebar.'}
            </p>
            <div
                role="radiogroup"
                aria-label="Icon"
                className="grid max-h-56 grid-cols-4 gap-1.5 overflow-y-auto rounded border border-gray-300 bg-input-bg p-2 sm:grid-cols-6"
            >
                <IconTile name="" label="No icon" selected={current === ''} onSelect={onChange} />
                {options.map((name) => (
                    <IconTile key={name} name={name} selected={current === name} onSelect={onChange} />
                ))}
                {unknown && <IconTile name={current} selected unknown onSelect={onChange} />}
            </div>
            {unknown && (
                <p className="mt-1 text-xs text-warning-text">
                    &lsquo;{current}&rsquo; is not one of the app&rsquo;s icons, so the sidebar renders
                    nothing for it. It is kept so saving this menu does not change it — pick another
                    tile to replace it.
                </p>
            )}
            {error && <p className="mt-1 text-xs text-danger">{error}</p>}
        </div>
    )
}

function IconTile({ name, label, selected, unknown = false, onSelect }) {
    const Glyph = name ? Icons[name] : null
    const caption = label ?? name

    return (
        <button
            type="button"
            role="radio"
            aria-checked={selected}
            title={caption}
            onClick={() => onSelect(name)}
            className={cn(
                'flex flex-col items-center gap-1 rounded border px-1 py-2 text-[10px] leading-tight transition-colors',
                selected
                    ? 'border-primary bg-accent text-primary'
                    : 'border-transparent text-gray-600 hover:border-gray-300 hover:bg-gray-50',
                unknown && 'border-dashed border-warning text-warning-text',
            )}
        >
            {/* Fixed height so tiles line up whether the glyph is 14px or 22px. */}
            <span className="flex h-5.5 items-center justify-center">
                {Glyph ? <Glyph size={18} /> : <span aria-hidden="true">&mdash;</span>}
            </span>
            <span className="w-full truncate">{caption}</span>
        </button>
    )
}
