// Settings → Site Galleries (0066) — the photo sets a tenant's website
// displays. A gallery is a named bucket with an address (slug) the site
// fetches; WHERE it renders is the site's concern. The tenant swaps photos
// here and the site follows within minutes — no developer in the loop.
//
// Admin-only card (settings-mutation rule). Photos ride PhotoGallery with
// entity_type 'gallery' and the strict ingest: every upload is re-encoded
// (EXIF/GPS stripped) to webp ≤1600px before it leaves the browser.
// No window.confirm/alert (ConfirmDialog rule) — errors are inline.

const SiteGalleriesSection = () => {
    const [galleries, setGalleries] = React.useState([]);
    const [tenant, setTenant]       = React.useState(null);
    const [open, setOpen]           = React.useState(null);   // gallery id whose photos are shown
    const [newName, setNewName]     = React.useState('');
    const [saving, setSaving]       = React.useState(false);
    const [error, setError]         = React.useState(null);
    const [loadErr, setLoadErr]     = React.useState(false);
    const [editing, setEditing]     = React.useState(null);   // { id, name }
    const [copied, setCopied]       = React.useState(null);

    const refresh = () => api.getSiteGalleries()
        .then(rows => { setGalleries(rows); setLoadErr(false); if (open == null && rows[0]) setOpen(rows[0].id); })
        .catch(() => setLoadErr(true));
    React.useEffect(() => { refresh(); api.getTenant().then(setTenant).catch(() => {}); }, []);

    // Mirrors the server's slugify so the preview under the input is truthful.
    const slugOf = (s) => String(s || '').toLowerCase().normalize('NFKD').replace(/[^\w\s-]/g, '')
        .trim().replace(/[\s_]+/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, '').slice(0, 60);
    const manifestUrl = (g) => tenant ? `${window.location.origin}/api/public/${tenant.slug}/galleries/${g.slug}` : '';

    const handleCreate = async (e) => {
        e.preventDefault();
        if (!newName.trim()) return;
        setSaving(true); setError(null);
        try {
            const g = await api.createSiteGallery({ name: newName.trim() });
            setNewName(''); setOpen(g.id); await refresh();
        } catch (err) { setError(err.message); }
        finally { setSaving(false); }
    };
    const toggleVisible = async (g) => {
        setError(null);
        try { await api.updateSiteGallery(g.id, { visible: !g.visible }); refresh(); }
        catch (err) { setError(err.message); }
    };
    const handleSaveEdit = async (e) => {
        e.preventDefault();
        if (!editing.name.trim()) return;
        try { await api.updateSiteGallery(editing.id, { name: editing.name.trim() }); setEditing(null); refresh(); }
        catch (err) { setError(err.message); }
    };
    const handleDelete = async (g) => {
        if (!await confirmAction(`Delete gallery "${g.name}" and its ${g.photo_count} photo${g.photo_count === 1 ? '' : 's'}? Your website will stop showing it on its next refresh.`)) return;
        try { await api.deleteSiteGallery(g.id); if (open === g.id) setOpen(null); refresh(); }
        catch (err) { setError(err.message); }
    };
    const move = async (i, dir) => {
        const j = i + dir; if (j < 0 || j >= galleries.length) return;
        const next = [...galleries]; [next[i], next[j]] = [next[j], next[i]];
        setGalleries(next);
        try { await api.orderSiteGalleries(next.map(g => g.id)); }
        catch (err) { setError(err.message); refresh(); }
    };
    const copy = async (g) => {
        try { await navigator.clipboard.writeText(manifestUrl(g)); setCopied(g.id); setTimeout(() => setCopied(null), 2000); }
        catch (_) { /* clipboard refused — the address is visible to select by hand */ }
    };

    return (
        <div className="settings-form">
            <p style={{ fontSize: '0.875rem', color: 'var(--text-3)', marginBottom: '1rem' }}>
                Each gallery is a set of photos your website can display — a slideshow, a banner, an
                "about us" strip. Upload, drag to reorder, add captions, and switch a gallery off when
                you don't want it shown. Your site reads each gallery by its address below; changes appear
                within a few minutes. Photos are resized and stripped of location data before upload.
            </p>

            {loadErr && <LoadErrorBanner what="galleries" onRetry={refresh} hasData={galleries.length > 0} />}
            {error && <p style={{ color: 'var(--danger)', fontSize: '0.875rem' }}>{error}</p>}

            <form onSubmit={handleCreate} style={{ display: 'flex', gap: '0.5rem', alignItems: 'flex-start', marginBottom: '1.25rem' }}>
                <div style={{ flex: 1 }}>
                    <input className="form-input" type="text" value={newName} onChange={e => setNewName(e.target.value)}
                           placeholder="New gallery name (e.g. Hot from the oven)" maxLength={100} style={{ width: '100%' }} />
                    {newName.trim() && <div style={{ fontSize: '0.75rem', color: 'var(--text-3)', marginTop: '0.25rem' }}>
                        Address will end in <code>/galleries/{slugOf(newName)}</code> — this can't change later.
                    </div>}
                </div>
                <button type="submit" className="btn btn-primary" disabled={saving || !newName.trim()}>
                    <i className="fas fa-plus"></i> Add gallery
                </button>
            </form>

            {galleries.length === 0 && !loadErr && (
                <p style={{ fontSize: '0.875rem', color: 'var(--text-3)' }}>No galleries yet. Add one above, then drop photos in.</p>
            )}

            {galleries.map((g, i) => (
                <div key={g.id} className="card" style={{ marginBottom: '0.75rem', padding: '0.75rem 1rem' }}>
                    <div style={{ display: 'flex', alignItems: 'center', gap: '0.5rem', flexWrap: 'wrap' }}>
                        <button type="button" className="btn btn-secondary btn-small" title="Show or hide photos"
                                onClick={() => setOpen(open === g.id ? null : g.id)}>
                            <i className={`fas ${open === g.id ? 'fa-chevron-down' : 'fa-chevron-right'}`}></i>
                        </button>
                        {editing && editing.id === g.id ? (
                            <form onSubmit={handleSaveEdit} style={{ display: 'flex', gap: '0.5rem', flex: 1 }}>
                                <input className="form-input" type="text" value={editing.name} autoFocus maxLength={100}
                                       onChange={e => setEditing({ ...editing, name: e.target.value })} />
                                <button type="submit" className="btn btn-primary btn-small">Save</button>
                                <button type="button" className="btn btn-secondary btn-small" onClick={() => setEditing(null)}>Cancel</button>
                            </form>
                        ) : (
                            <strong style={{ flex: 1, cursor: 'text' }} onClick={() => setEditing({ id: g.id, name: g.name })} title="Click to rename">
                                {g.name}
                            </strong>
                        )}
                        <span style={{ fontSize: '0.75rem', color: 'var(--text-3)' }}>{g.photo_count} photo{g.photo_count === 1 ? '' : 's'}</span>
                        {/* Chip pair, not a state-labelled toggle (toggle-buttons-read-as-actions lesson). */}
                        <div className="seg-control" role="group" aria-label="Visibility">
                            <button type="button" className={`seg-btn${g.visible ? ' on' : ''}`} onClick={() => !g.visible && toggleVisible(g)}>On site</button>
                            <button type="button" className={`seg-btn${!g.visible ? ' on' : ''}`} onClick={() => g.visible && toggleVisible(g)}>Hidden</button>
                        </div>
                        <button type="button" className="btn btn-secondary btn-small" onClick={() => move(i, -1)} disabled={i === 0} title="Move up">↑</button>
                        <button type="button" className="btn btn-secondary btn-small" onClick={() => move(i, 1)} disabled={i === galleries.length - 1} title="Move down">↓</button>
                        <button type="button" className="btn btn-secondary btn-small" onClick={() => handleDelete(g)} title="Delete gallery"><i className="fas fa-trash"></i></button>
                    </div>
                    <div style={{ display: 'flex', gap: '0.5rem', alignItems: 'center', marginTop: '0.5rem' }}>
                        <code style={{ flex: 1, padding: '0.35rem 0.6rem', background: 'var(--surface-2)', borderRadius: '6px',
                                       fontSize: '0.75rem', overflowX: 'auto', whiteSpace: 'nowrap' }}>{manifestUrl(g)}</code>
                        <button type="button" className="btn btn-secondary btn-small" onClick={() => copy(g)} title="Copy the gallery address">
                            <i className={`fas ${copied === g.id ? 'fa-check' : 'fa-copy'}`}></i>
                        </button>
                    </div>
                    {open === g.id && (
                        <div style={{ marginTop: '0.75rem' }}>
                            <PhotoGallery entityType="gallery" entityId={g.id} title="Photos"
                                          ingest={{ always: true, format: 'image/webp' }}
                                          hint="Drop photos here or click to browse. Drag tiles to set the order your website shows — the first photo leads."
                                          captionPlaceholder="Add a caption" />
                        </div>
                    )}
                </div>
            ))}
        </div>
    );
};
