import { useEffect, useMemo, useRef, useState } from 'react'
import { Accordion, Button, ButtonGroup, Col, Container, Form, Modal, Row, Tab, Tabs } from 'react-bootstrap'
import DataTable, { createTheme } from 'react-data-table-component'
import { useTranslation } from 'react-i18next'
import { useDropzone } from 'react-dropzone'
import { useAuth } from '../context/AuthContext'
import {
    createForum,
    deleteForum,
    fetchSettings,
    listAllForums,
    listRanks,
    listRoles,
    listUsers,
    reorderForums,
    saveSetting,
    saveSettings,
    createRank,
    deleteRank,
    updateUserRank,
    updateRank,
    updateUser,
    createRole,
    updateRole,
    deleteRole,
    uploadRankBadgeImage,
    uploadFavicon,
    uploadLogo,
    updateForum,
    listAttachmentGroups,
    createAttachmentGroup,
    updateAttachmentGroup,
    deleteAttachmentGroup,
    reorderAttachmentGroups,
    listAttachmentExtensions,
    createAttachmentExtension,
    updateAttachmentExtension,
    deleteAttachmentExtension,
} from '../api/client'

export default function Acp({ isAdmin }) {
    const { t } = useTranslation()
    const { roles: authRoles } = useAuth()
    const canManageFounder = authRoles.includes('ROLE_FOUNDER')
    const [forums, setForums] = useState([])
    const [loading, setLoading] = useState(false)
    const [error, setError] = useState('')
    const [selectedId, setSelectedId] = useState(null)
    const [draggingId, setDraggingId] = useState(null)
    const [overId, setOverId] = useState(null)
    const pendingOrder = useRef(null)
    const [createType, setCreateType] = useState(null)
    const [users, setUsers] = useState([])
    const [userSearch, setUserSearch] = useState('')
    const [usersLoading, setUsersLoading] = useState(false)
    const [usersError, setUsersError] = useState('')
    const [usersPage, setUsersPage] = useState(1)
    const [usersPerPage, setUsersPerPage] = useState(10)
    const [userSort, setUserSort] = useState({ columnId: 'name', direction: 'asc' })
    const [ranks, setRanks] = useState([])
    const [ranksLoading, setRanksLoading] = useState(false)
    const [ranksError, setRanksError] = useState('')
    const [rankUpdatingId, setRankUpdatingId] = useState(null)
    const [rankFormName, setRankFormName] = useState('')
    const [rankFormType, setRankFormType] = useState('text')
    const [rankFormText, setRankFormText] = useState('')
    const [rankFormColor, setRankFormColor] = useState('')
    const [rankFormImage, setRankFormImage] = useState(null)
    const [rankSaving, setRankSaving] = useState(false)
    const [showRankCreate, setShowRankCreate] = useState(false)
    const [showRankModal, setShowRankModal] = useState(false)
    const [rankEdit, setRankEdit] = useState({
        id: null,
        name: '',
        badgeType: 'text',
        badgeText: '',
        badgeImageUrl: '',
        color: '',
    })
    const [rankEditImage, setRankEditImage] = useState(null)
    const [showUserModal, setShowUserModal] = useState(false)
    const [userForm, setUserForm] = useState({ id: null, name: '', email: '', rankId: '', roles: [] })
    const [roleQuery, setRoleQuery] = useState('')
    const [roleMenuOpen, setRoleMenuOpen] = useState(false)
    const roleMenuRef = useRef(null)
    const [roles, setRoles] = useState([])
    const [rolesLoading, setRolesLoading] = useState(false)
    const [rolesError, setRolesError] = useState('')
    const [roleFormName, setRoleFormName] = useState('')
    const [roleFormColor, setRoleFormColor] = useState('')
    const [roleSaving, setRoleSaving] = useState(false)
    const [showRoleCreate, setShowRoleCreate] = useState(false)
    const [showRoleModal, setShowRoleModal] = useState(false)
    const [roleEdit, setRoleEdit] = useState({
        id: null,
        name: '',
        originalName: '',
        color: '',
        isCore: false,
    })
    const [attachmentGroups, setAttachmentGroups] = useState([])
    const [attachmentGroupsLoading, setAttachmentGroupsLoading] = useState(false)
    const [attachmentGroupsError, setAttachmentGroupsError] = useState('')
    const [attachmentGroupSaving, setAttachmentGroupSaving] = useState(false)
    const [showAttachmentGroupModal, setShowAttachmentGroupModal] = useState(false)
    const [attachmentGroupEdit, setAttachmentGroupEdit] = useState({
        id: null,
        name: '',
        parentId: '',
        max_size_kb: 25600,
        is_active: true,
    })
    const [attachmentExtensions, setAttachmentExtensions] = useState([])
    const [attachmentExtensionsLoading, setAttachmentExtensionsLoading] = useState(false)
    const [attachmentExtensionsError, setAttachmentExtensionsError] = useState('')
    const [attachmentExtensionSaving, setAttachmentExtensionSaving] = useState(false)
    const [attachmentExtensionSavingId, setAttachmentExtensionSavingId] = useState(null)
    const [attachmentSeedSaving, setAttachmentSeedSaving] = useState(false)
    const [showAttachmentExtensionModal, setShowAttachmentExtensionModal] = useState(false)
    const [attachmentExtensionEdit, setAttachmentExtensionEdit] = useState(null)
    const [showAttachmentExtensionDelete, setShowAttachmentExtensionDelete] = useState(false)
    const [attachmentExtensionDeleteTarget, setAttachmentExtensionDeleteTarget] = useState(null)
    const [newAttachmentExtension, setNewAttachmentExtension] = useState({
        extension: '',
        groupId: '',
        allowedMimes: '',
    })
    const attachmentExtensionInputRef = useRef(null)
    const [attachmentGroupCollapsed, setAttachmentGroupCollapsed] = useState(new Set())
    const [attachmentGroupDraggingId, setAttachmentGroupDraggingId] = useState(null)
    const [attachmentGroupOverId, setAttachmentGroupOverId] = useState(null)
    const attachmentGroupPendingOrder = useRef(null)
    const [userSaving, setUserSaving] = useState(false)
    const [generalSaving, setGeneralSaving] = useState(false)
    const [generalUploading, setGeneralUploading] = useState(false)
    const [generalError, setGeneralError] = useState('')
    const [generalSettings, setGeneralSettings] = useState({
        forum_name: '',
        default_theme: 'auto',
        accent_color_dark: '',
        accent_color_light: '',
        logo_dark: '',
        logo_light: '',
        show_header_name: 'true',
        favicon_ico: '',
        favicon_16: '',
        favicon_32: '',
        favicon_48: '',
        favicon_64: '',
        favicon_128: '',
        favicon_256: '',
    })
    const settingsDetailMap = {
        forum_name: 'forumName',
        default_theme: 'defaultTheme',
        accent_color_dark: 'accentDark',
        accent_color_light: 'accentLight',
        logo_dark: 'logoDark',
        logo_light: 'logoLight',
        show_header_name: 'showHeaderName',
        favicon_ico: 'faviconIco',
        favicon_16: 'favicon16',
        favicon_32: 'favicon32',
        favicon_48: 'favicon48',
        favicon_64: 'favicon64',
        favicon_128: 'favicon128',
        favicon_256: 'favicon256',
    }
    const [themeMode, setThemeMode] = useState(
        document.documentElement.getAttribute('data-bs-theme') || 'light'
    )

    useEffect(() => {
        createTheme('speedbb-dark', {
            text: {
                primary: '#e6e8eb',
                secondary: '#9aa4b2',
            },
            background: {
                default: 'transparent',
            },
            context: {
                background: '#1a1f29',
                text: '#ffffff',
            },
            divider: {
                default: '#2a2f3a',
            },
            action: {
                button: 'rgba(230, 232, 235, 0.12)',
                hover: 'rgba(230, 232, 235, 0.08)',
                disabled: 'rgba(230, 232, 235, 0.35)',
            },
        })

        createTheme('speedbb-light', {
            text: {
                primary: '#0e121b',
                secondary: '#5b6678',
            },
            background: {
                default: '#ffffff',
            },
            context: {
                background: '#f7f2ea',
                text: '#0e121b',
            },
            divider: {
                default: '#e0d7c7',
            },
            action: {
                button: 'rgba(14, 18, 27, 0.12)',
                hover: 'rgba(14, 18, 27, 0.06)',
                disabled: 'rgba(14, 18, 27, 0.35)',
            },
        })
    }, [])

    useEffect(() => {
        if (!isAdmin) return
        let active = true
        const loadSettings = async () => {
            try {
                const allSettings = await fetchSettings()
                const settingsMap = new Map(allSettings.map((setting) => [setting.key, setting.value]))
                if (!active) return
                const next = {
                    forum_name: settingsMap.get('forum_name') || '',
                    default_theme: settingsMap.get('default_theme') || 'auto',
                    accent_color_dark: settingsMap.get('accent_color_dark') || '',
                    accent_color_light: settingsMap.get('accent_color_light') || '',
                    logo_dark: settingsMap.get('logo_dark') || '',
                    logo_light: settingsMap.get('logo_light') || '',
                    show_header_name: settingsMap.get('show_header_name') || 'true',
                    favicon_ico: settingsMap.get('favicon_ico') || '',
                    favicon_16: settingsMap.get('favicon_16') || '',
                    favicon_32: settingsMap.get('favicon_32') || '',
                    favicon_48: settingsMap.get('favicon_48') || '',
                    favicon_64: settingsMap.get('favicon_64') || '',
                    favicon_128: settingsMap.get('favicon_128') || '',
                    favicon_256: settingsMap.get('favicon_256') || '',
                }
                setGeneralSettings(next)
            } catch (err) {
                if (active) setGeneralError(err.message)
            }
        }
        loadSettings()
        return () => {
            active = false
        }
    }, [isAdmin])

    const handleGeneralSave = async (event) => {
        event.preventDefault()
        setGeneralSaving(true)
        setGeneralError('')
        try {
            await saveSettings(
                Object.entries(generalSettings).map(([key, value]) => ({
                    key,
                    value: typeof value === 'string' ? value.trim() : String(value ?? ''),
                }))
            )
            const detail = Object.entries(generalSettings).reduce((acc, [key, value]) => {
                const mappedKey = settingsDetailMap[key]
                if (!mappedKey) return acc
                if (key === 'show_header_name') {
                    acc[mappedKey] = value !== 'false'
                    return acc
                }
                acc[mappedKey] = typeof value === 'string' ? value.trim() : String(value ?? '')
                return acc
            }, {})
            window.dispatchEvent(new CustomEvent('speedbb-settings-updated', { detail }))
        } catch (err) {
            setGeneralError(err.message)
        } finally {
            setGeneralSaving(false)
        }
    }

    const handleDefaultThemeChange = async (value) => {
        const previous = generalSettings.default_theme
        setGeneralSettings((prev) => ({ ...prev, default_theme: value }))
        setGeneralError('')
        try {
            await saveSetting('default_theme', value)
            window.dispatchEvent(
                new CustomEvent('speedbb-settings-updated', {
                    detail: { defaultTheme: value },
                })
            )
        } catch (err) {
            setGeneralSettings((prev) => ({ ...prev, default_theme: previous }))
            setGeneralError(err.message)
        }
    }

    const handleLogoUpload = async (file, settingKey) => {
        if (!file) return
        setGeneralUploading(true)
        setGeneralError('')
        try {
            const result = await uploadLogo(file)
            const url = result?.url || ''
            setGeneralSettings((prev) => ({ ...prev, [settingKey]: url }))
            if (url) {
                await saveSetting(settingKey, url)
                const mappedKey = settingsDetailMap[settingKey]
                if (mappedKey) {
                    window.dispatchEvent(
                        new CustomEvent('speedbb-settings-updated', {
                            detail: { [mappedKey]: url },
                        })
                    )
                }
            }
        } catch (err) {
            setGeneralError(err.message)
        } finally {
            setGeneralUploading(false)
        }
    }

    const handleFaviconUpload = async (file, settingKey) => {
        if (!file) return
        setGeneralUploading(true)
        setGeneralError('')
        try {
            const result = await uploadFavicon(file)
            const url = result?.url || ''
            setGeneralSettings((prev) => ({ ...prev, [settingKey]: url }))
            if (url) {
                await saveSetting(settingKey, url)
                const mappedKey = settingsDetailMap[settingKey]
                if (mappedKey) {
                    window.dispatchEvent(
                        new CustomEvent('speedbb-settings-updated', {
                            detail: { [mappedKey]: url },
                        })
                    )
                }
            }
        } catch (err) {
            setGeneralError(err.message)
        } finally {
            setGeneralUploading(false)
        }
    }

    const faviconIcoDropzone = useDropzone({
        accept: {
            'image/png': ['.png'],
            'image/x-icon': ['.ico'],
        },
        maxFiles: 1,
        onDrop: (files) => handleFaviconUpload(files[0], 'favicon_ico'),
    })

    const favicon16Dropzone = useDropzone({
        accept: {
            'image/png': ['.png'],
            'image/x-icon': ['.ico'],
        },
        maxFiles: 1,
        onDrop: (files) => handleFaviconUpload(files[0], 'favicon_16'),
    })

    const favicon32Dropzone = useDropzone({
        accept: {
            'image/png': ['.png'],
            'image/x-icon': ['.ico'],
        },
        maxFiles: 1,
        onDrop: (files) => handleFaviconUpload(files[0], 'favicon_32'),
    })

    const favicon48Dropzone = useDropzone({
        accept: {
            'image/png': ['.png'],
            'image/x-icon': ['.ico'],
        },
        maxFiles: 1,
        onDrop: (files) => handleFaviconUpload(files[0], 'favicon_48'),
    })

    const favicon64Dropzone = useDropzone({
        accept: {
            'image/png': ['.png'],
            'image/x-icon': ['.ico'],
        },
        maxFiles: 1,
        onDrop: (files) => handleFaviconUpload(files[0], 'favicon_64'),
    })

    const favicon128Dropzone = useDropzone({
        accept: {
            'image/png': ['.png'],
            'image/x-icon': ['.ico'],
        },
        maxFiles: 1,
        onDrop: (files) => handleFaviconUpload(files[0], 'favicon_128'),
    })

    const favicon256Dropzone = useDropzone({
        accept: {
            'image/png': ['.png'],
            'image/x-icon': ['.ico'],
        },
        maxFiles: 1,
        onDrop: (files) => handleFaviconUpload(files[0], 'favicon_256'),
    })

    const darkLogoDropzone = useDropzone({
        accept: {
            'image/*': ['.jpg', '.jpeg', '.png', '.gif', '.webp', '.svg'],
        },
        maxFiles: 1,
        onDrop: (files) => handleLogoUpload(files[0], 'logo_dark'),
    })

    const lightLogoDropzone = useDropzone({
        accept: {
            'image/*': ['.jpg', '.jpeg', '.png', '.gif', '.webp', '.svg'],
        },
        maxFiles: 1,
        onDrop: (files) => handleLogoUpload(files[0], 'logo_light'),
    })

    useEffect(() => {
        const observer = new MutationObserver(() => {
            setThemeMode(document.documentElement.getAttribute('data-bs-theme') || 'light')
        })

        observer.observe(document.documentElement, {
            attributes: true,
            attributeFilter: ['data-bs-theme'],
        })

        return () => observer.disconnect()
    }, [])
    const filteredUsers = useMemo(() => {
        const term = userSearch.trim().toLowerCase()
        if (!term) return users
        return users.filter((user) =>
            [user.name, user.email, user.rank?.name]
                .filter(Boolean)
                .some((value) => value.toLowerCase().includes(term))
        )
    }, [users, userSearch])

    const userColumns = useMemo(
        () => {
            const iconFor = (id) => {
                if (userSort.columnId !== id) {
                    return 'bi-arrow-down-up'
                }
                return userSort.direction === 'asc' ? 'bi-caret-up-fill' : 'bi-caret-down-fill'
            }

            return [
            {
                id: 'name',
                name: (
                    <span className="bb-sort-label">
                        {t('user.name')}
                        <i className={`bi ${iconFor('name')}`} aria-hidden="true" />
                    </span>
                ),
                selector: (row) => row.name,
                sortable: true,
                sortFunction: (a, b) => (a.name || '').localeCompare(b.name || '', undefined, {
                    sensitivity: 'base',
                }),
            },
            {
                id: 'email',
                name: (
                    <span className="bb-sort-label">
                        {t('user.email')}
                        <i className={`bi ${iconFor('email')}`} aria-hidden="true" />
                    </span>
                ),
                selector: (row) => row.email,
                sortable: true,
            },
            {
                id: 'rank',
                name: (
                    <span className="bb-sort-label">
                        {t('user.rank')}
                        <i className={`bi ${iconFor('rank')}`} aria-hidden="true" />
                    </span>
                ),
                width: '220px',
                sortable: true,
                sortFunction: (a, b) =>
                    (a.rank?.name || '').localeCompare(b.rank?.name || ''),
                cell: (row) => (
                    <Form.Select
                        size="sm"
                        value={row.rank?.id ?? ''}
                        disabled={ranksLoading || rankUpdatingId === row.id}
                        onChange={async (event) => {
                            const nextRankId = event.target.value ? Number(event.target.value) : null
                            setRankUpdatingId(row.id)
                            try {
                                const updated = await updateUserRank(row.id, nextRankId)
                                setUsers((prev) =>
                                    prev.map((user) =>
                                        user.id === row.id ? { ...user, rank: updated.rank } : user
                                    )
                                )
                            } catch (err) {
                                setUsersError(err.message)
                            } finally {
                                setRankUpdatingId(null)
                            }
                        }}
                    >
                        <option value="">{t('user.rank_unassigned')}</option>
                        {ranks.map((rank) => (
                            <option key={rank.id} value={rank.id}>
                                {rank.name}
                            </option>
                        ))}
                    </Form.Select>
                ),
            },
            {
                name: '',
                width: '180px',
                right: true,
                cell: (row) => (
                    <div className="bb-user-actions">
                        <ButtonGroup className="bb-action-group">
                            <Button
                                variant="dark"
                                title={t('user.impersonate')}
                                onClick={() => console.log('impersonate', row)}
                            >
                                <i className="bi bi-person-badge" aria-hidden="true" />
                            </Button>
                            {(() => {
                                const editLocked = (row.roles || []).includes('ROLE_FOUNDER') && !canManageFounder
                                return (
                                    <Button
                                        variant="dark"
                                        title={editLocked ? t('user.founder_locked') : t('user.edit')}
                                        aria-disabled={editLocked}
                                        className={editLocked ? 'bb-btn-disabled' : undefined}
                                        onClick={() => {
                                            if (editLocked) return
                                            setUserForm({
                                                id: row.id,
                                                name: row.name,
                                                email: row.email,
                                                rankId: row.rank?.id ?? '',
                                                roles: row.roles || [],
                                            })
                                            setShowUserModal(true)
                                            setUsersError('')
                                        }}
                                    >
                                        <i className="bi bi-pencil" aria-hidden="true" />
                                    </Button>
                                )
                            })()}
                            <Button
                                variant="dark"
                                title={t('user.delete')}
                                onClick={() => console.log('delete user', row)}
                            >
                                <i className="bi bi-trash" aria-hidden="true" />
                            </Button>
                        </ButtonGroup>
                    </div>
                ),
            },
        ]
        },
        [t, ranks, ranksLoading, rankUpdatingId, userSort]
    )
    const userTableStyles = useMemo(
        () => ({
            table: {
                style: {
                    backgroundColor: themeMode === 'dark' ? 'transparent' : '#ffffff',
                },
            },
            headRow: {
                style: {
                    backgroundColor: themeMode === 'dark' ? '#1a1f29' : '#f7f2ea',
                    borderBottomColor: themeMode === 'dark' ? '#2a2f3a' : '#e0d7c7',
                    color: themeMode === 'dark' ? '#e6e8eb' : '#0e121b',
                    fontWeight: 600,
                },
            },
            rows: {
                style: {
                    backgroundColor: themeMode === 'dark' ? 'rgba(255, 255, 255, 0.02)' : '#ffffff',
                    color: themeMode === 'dark' ? '#e6e8eb' : '#0e121b',
                },
                stripedStyle: {
                    backgroundColor: themeMode === 'dark' ? 'rgba(255, 255, 255, 0.05)' : '#f7f2ea',
                    color: themeMode === 'dark' ? '#e6e8eb' : '#0e121b',
                },
                highlightOnHoverStyle: {
                    backgroundColor: themeMode === 'dark'
                        ? 'transparent'
                        : 'rgba(0, 0, 0, 0.04)',
                },
            },
            pagination: {
                style: {
                    backgroundColor: themeMode === 'dark' ? '#1a1f29' : '#ffffff',
                    color: themeMode === 'dark' ? '#cfd6df' : '#5b6678',
                    borderTopColor: themeMode === 'dark' ? '#2a2f3a' : '#e0d7c7',
                },
            },
        }),
        [themeMode]
    )

    const UsersPagination = ({ rowsPerPage, rowCount, onChangePage }) => {
        const totalPages = Math.max(1, Math.ceil(rowCount / rowsPerPage))
        const current = Math.min(usersPage, totalPages)

        const pages = []
        for (let page = Math.max(1, current - 2); page <= Math.min(totalPages, current + 2); page += 1) {
            pages.push(page)
        }

        const goTo = (page) => {
            if (page < 1 || page > totalPages) return
            onChangePage(page, rowCount)
        }

        return (
            <div className="bb-pagination">
                <div className="bb-pagination-range">
                    {t('table.rows_per_page')} {rowsPerPage}{' '}
                    <span className="bb-muted">
                        {((current - 1) * rowsPerPage) + 1}-{Math.min(current * rowsPerPage, rowCount)} {t('table.range_separator')} {rowCount}
                    </span>
                </div>
                <div className="bb-pagination-actions">
                    <button type="button" onClick={() => goTo(1)} disabled={current === 1}>
                        «
                    </button>
                    <button type="button" onClick={() => goTo(current - 1)} disabled={current === 1}>
                        ‹
                    </button>
                    {pages.map((page) => (
                        <button
                            key={page}
                            type="button"
                            className={page === current ? 'is-active' : ''}
                            onClick={() => goTo(page)}
                        >
                            {page}
                        </button>
                    ))}
                    <button type="button" onClick={() => goTo(current + 1)} disabled={current === totalPages}>
                        ›
                    </button>
                    <button type="button" onClick={() => goTo(totalPages)} disabled={current === totalPages}>
                        »
                    </button>
                </div>
            </div>
        )
    }
    const [collapsed, setCollapsed] = useState(() => new Set())
    const hasInitializedCollapse = useRef(false)
    const [showModal, setShowModal] = useState(false)
    const [form, setForm] = useState({
        name: '',
        description: '',
        type: 'category',
        parentId: '',
    })

    const refreshForums = async () => {
        setLoading(true)
        setError('')
        try {
            const data = await listAllForums()
            setForums(data.filter((forum) => !forum.deleted_at))
        } catch (err) {
            setError(err.message)
        } finally {
            setLoading(false)
        }
    }

    useEffect(() => {
        if (isAdmin) {
            refreshForums()
        }
    }, [isAdmin])

    useEffect(() => {
        if (!hasInitializedCollapse.current && forums.length > 0) {
            const ids = forums
                .filter((forum) => forum.type === 'category')
                .map((forum) => String(forum.id))
            setCollapsed(new Set(ids))
            hasInitializedCollapse.current = true
        }
    }, [forums])

    const refreshUsers = async () => {
        setUsersLoading(true)
        setUsersError('')
        try {
            const data = await listUsers()
            setUsers(data)
        } catch (err) {
            setUsersError(err.message)
        } finally {
            setUsersLoading(false)
        }
    }

    useEffect(() => {
        if (isAdmin) {
            refreshUsers()
        }
    }, [isAdmin])

    useEffect(() => {
        if (!roleMenuOpen) return
        const handleClick = (event) => {
            if (!roleMenuRef.current) return
            if (!roleMenuRef.current.contains(event.target)) {
                setRoleMenuOpen(false)
            }
        }
        document.addEventListener('mousedown', handleClick)
        return () => document.removeEventListener('mousedown', handleClick)
    }, [roleMenuOpen])

    useEffect(() => {
        if (!isAdmin) return
        let active = true
        const loadRoles = async () => {
            setRolesLoading(true)
            setRolesError('')
            try {
                const data = await listRoles()
                if (active) setRoles(data)
            } catch (err) {
                if (active) setRolesError(err.message)
            } finally {
                if (active) setRolesLoading(false)
            }
        }
        loadRoles()
        return () => {
            active = false
        }
    }, [isAdmin])

    const refreshRanks = async () => {
        setRanksLoading(true)
        setRanksError('')
        try {
            const data = await listRanks()
            setRanks(data)
        } catch (err) {
            setRanksError(err.message)
        } finally {
            setRanksLoading(false)
        }
    }

    useEffect(() => {
        if (isAdmin) {
            refreshRanks()
        }
    }, [isAdmin])

    const handleCreateRank = async (event) => {
        if (event?.preventDefault) {
            event.preventDefault()
        }
        if (!rankFormName.trim()) return
        if (rankFormType === 'image' && !rankFormImage) {
            setRanksError(t('rank.badge_image_required'))
            return
        }
        setRankSaving(true)
        setRanksError('')
        try {
            const created = await createRank({
                name: rankFormName.trim(),
                badge_type: rankFormType,
                badge_text: rankFormType === 'text' ? rankFormText.trim() || rankFormName.trim() : null,
                color: rankFormColor.trim() || null,
            })
            let next = created
            if (rankFormType === 'image' && rankFormImage) {
                const updated = await uploadRankBadgeImage(created.id, rankFormImage)
                next = { ...created, ...updated }
            }
            setRanks((prev) => [...prev, next].sort((a, b) => a.name.localeCompare(b.name)))
            setRankFormName('')
            setRankFormType('text')
            setRankFormText('')
            setRankFormColor('')
            setRankFormImage(null)
            setShowRankCreate(false)
        } catch (err) {
            setRanksError(err.message)
        } finally {
            setRankSaving(false)
        }
    }

    const isCoreRole = (name) => name === 'ROLE_ADMIN' || name === 'ROLE_USER' || name === 'ROLE_FOUNDER'

    const formatRoleLabel = (name) => {
        if (!name) return ''
        const withoutPrefix = name.startsWith('ROLE_') ? name.slice(5) : name
        return withoutPrefix
            .toLowerCase()
            .replace(/_/g, ' ')
            .replace(/\b\w/g, (char) => char.toUpperCase())
    }

    const filteredRoles = useMemo(() => {
        const query = roleQuery.trim().toLowerCase()
        if (!query) return roles
        return roles.filter((role) =>
            formatRoleLabel(role.name).toLowerCase().includes(query)
        )
    }, [roles, roleQuery])

    const formatSizeKb = (kb) => {
        if (!kb && kb !== 0) return ''
        if (kb < 1024) return `${kb} KB`
        return `${(kb / 1024).toFixed(1)} MB`
    }

    const attachmentDefaultSeed = [
        {
            name: 'Media',
            max_size_kb: 25600,
            children: [
                {
                    name: 'Image',
                    max_size_kb: 25600,
                    extensions: [
                        { ext: 'png', mimes: ['image/png'] },
                        { ext: 'jpg', mimes: ['image/jpeg'] },
                        { ext: 'jpeg', mimes: ['image/jpeg'] },
                        { ext: 'gif', mimes: ['image/gif'] },
                        { ext: 'webp', mimes: ['image/webp'] },
                        { ext: 'bmp', mimes: ['image/bmp'] },
                        { ext: 'svg', mimes: ['image/svg+xml'] },
                    ],
                },
                {
                    name: 'Video',
                    max_size_kb: 102400,
                    extensions: [
                        { ext: 'mp4', mimes: ['video/mp4'] },
                        { ext: 'webm', mimes: ['video/webm'] },
                        { ext: 'mov', mimes: ['video/quicktime'] },
                        { ext: 'avi', mimes: ['video/x-msvideo'] },
                        { ext: 'mkv', mimes: ['video/x-matroska'] },
                    ],
                },
                {
                    name: 'Audio',
                    max_size_kb: 25600,
                    extensions: [
                        { ext: 'mp3', mimes: ['audio/mpeg'] },
                        { ext: 'wav', mimes: ['audio/wav'] },
                        { ext: 'ogg', mimes: ['audio/ogg'] },
                        { ext: 'flac', mimes: ['audio/flac'] },
                        { ext: 'm4a', mimes: ['audio/mp4'] },
                    ],
                },
            ],
        },
        {
            name: 'Files',
            max_size_kb: 25600,
            children: [
                {
                    name: 'Archive',
                    max_size_kb: 51200,
                    extensions: [
                        { ext: 'zip', mimes: ['application/zip'] },
                        { ext: 'rar', mimes: ['application/vnd.rar'] },
                        { ext: '7z', mimes: ['application/x-7z-compressed'] },
                        { ext: 'tar', mimes: ['application/x-tar'] },
                        { ext: 'gz', mimes: ['application/gzip'] },
                    ],
                },
                {
                    name: 'Documents',
                    max_size_kb: 25600,
                    extensions: [
                        { ext: 'txt', mimes: ['text/plain'] },
                        { ext: 'pdf', mimes: ['application/pdf'] },
                        { ext: 'doc', mimes: ['application/msword'] },
                        { ext: 'docx', mimes: ['application/vnd.openxmlformats-officedocument.wordprocessingml.document'] },
                        { ext: 'rtf', mimes: ['application/rtf'] },
                        { ext: 'odt', mimes: ['application/vnd.oasis.opendocument.text'] },
                        { ext: 'xls', mimes: ['application/vnd.ms-excel'] },
                        { ext: 'xlsx', mimes: ['application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'] },
                        { ext: 'ppt', mimes: ['application/vnd.ms-powerpoint'] },
                        { ext: 'pptx', mimes: ['application/vnd.openxmlformats-officedocument.presentationml.presentation'] },
                        { ext: 'csv', mimes: ['text/csv'] },
                    ],
                },
                {
                    name: 'Other',
                    max_size_kb: 25600,
                    extensions: [
                        { ext: 'json', mimes: ['application/json'] },
                        { ext: 'xml', mimes: ['application/xml', 'text/xml'] },
                        { ext: 'log', mimes: ['text/plain'] },
                    ],
                },
            ],
        },
    ]

    const normalizeList = (value) =>
        value
            .split(/[\n,]/)
            .map((item) => item.trim())
            .filter(Boolean)

    const loadAttachmentGroups = async () => {
        setAttachmentGroupsLoading(true)
        setAttachmentGroupsError('')
        try {
            const data = await listAttachmentGroups()
            setAttachmentGroups(data)
        } catch (err) {
            setAttachmentGroupsError(err.message)
        } finally {
            setAttachmentGroupsLoading(false)
        }
    }

    const loadAttachmentExtensions = async () => {
        setAttachmentExtensionsLoading(true)
        setAttachmentExtensionsError('')
        try {
            const data = await listAttachmentExtensions()
            setAttachmentExtensions(data)
        } catch (err) {
            setAttachmentExtensionsError(err.message)
        } finally {
            setAttachmentExtensionsLoading(false)
        }
    }

    const openAttachmentGroupModal = (group = null) => {
        if (group) {
            setAttachmentGroupEdit({
                id: group.id,
                name: group.name || '',
                parentId: group.parent_id ? String(group.parent_id) : '',
                max_size_kb: group.max_size_kb ?? 25600,
                is_active: group.is_active ?? true,
            })
        } else {
            setAttachmentGroupEdit({
                id: null,
                name: '',
                parentId: '',
                max_size_kb: 25600,
                is_active: true,
            })
        }
        setShowAttachmentGroupModal(true)
    }

    const openAttachmentGroupChildModal = (parentId) => {
        setAttachmentGroupEdit({
            id: null,
            name: '',
            parentId: parentId ? String(parentId) : '',
            max_size_kb: 25600,
            is_active: true,
        })
        setShowAttachmentGroupModal(true)
    }

    const handleAttachmentGroupSubmit = async (event) => {
        event.preventDefault()
        setAttachmentGroupSaving(true)
        setAttachmentGroupsError('')
        try {
            const payload = {
                name: attachmentGroupEdit.name.trim(),
                parent_id: attachmentGroupEdit.parentId ? Number(attachmentGroupEdit.parentId) : null,
                max_size_kb: Number(attachmentGroupEdit.max_size_kb) || 1,
                is_active: Boolean(attachmentGroupEdit.is_active),
            }

            if (attachmentGroupEdit.id) {
                const updated = await updateAttachmentGroup(attachmentGroupEdit.id, payload)
                setAttachmentGroups((prev) =>
                    prev.map((item) => (item.id === updated.id ? updated : item))
                )
            } else {
                const created = await createAttachmentGroup(payload)
                setAttachmentGroups((prev) => [...prev, created].sort((a, b) => a.name.localeCompare(b.name)))
            }

            setShowAttachmentGroupModal(false)
        } catch (err) {
            setAttachmentGroupsError(err.message)
        } finally {
            setAttachmentGroupSaving(false)
        }
    }

    const handleAttachmentGroupDelete = async (group) => {
        if (!window.confirm(t('attachment.group_delete_confirm'))) return
        setAttachmentGroupSaving(true)
        setAttachmentGroupsError('')
        try {
            await deleteAttachmentGroup(group.id)
            setAttachmentGroups((prev) => prev.filter((item) => item.id !== group.id))
        } catch (err) {
            setAttachmentGroupsError(err.message)
        } finally {
            setAttachmentGroupSaving(false)
        }
    }

    const handleAttachmentExtensionCreate = async (event) => {
        event.preventDefault()
        if (!newAttachmentExtension.extension.trim()) return
        setAttachmentExtensionSaving(true)
        setAttachmentExtensionsError('')
        try {
            if (attachmentExtensionEdit) {
                const payload = {
                    attachment_group_id: newAttachmentExtension.groupId
                        ? Number(newAttachmentExtension.groupId)
                        : null,
                    allowed_mimes: newAttachmentExtension.allowedMimes
                        ? normalizeList(newAttachmentExtension.allowedMimes)
                        : null,
                }
                const updated = await updateAttachmentExtension(attachmentExtensionEdit.id, payload)
                setAttachmentExtensions((prev) =>
                    prev.map((item) => (item.id === updated.id ? updated : item))
                )
            } else {
                const payload = {
                    extension: newAttachmentExtension.extension.trim(),
                    attachment_group_id: newAttachmentExtension.groupId
                        ? Number(newAttachmentExtension.groupId)
                        : null,
                    allowed_mimes: newAttachmentExtension.allowedMimes
                        ? normalizeList(newAttachmentExtension.allowedMimes)
                        : null,
                }
                const created = await createAttachmentExtension(payload)
                setAttachmentExtensions((prev) =>
                    [...prev, created].sort((a, b) => a.extension.localeCompare(b.extension))
                )
            }
            setNewAttachmentExtension({ extension: '', groupId: '', allowedMimes: '' })
            setAttachmentExtensionEdit(null)
            setShowAttachmentExtensionModal(false)
        } catch (err) {
            setAttachmentExtensionsError(err.message)
        } finally {
            setAttachmentExtensionSaving(false)
        }
    }

    const handleAttachmentExtensionUpdate = async (extensionId, groupId, allowedMimes) => {
        setAttachmentExtensionSavingId(extensionId)
        setAttachmentExtensionsError('')
        try {
            const payload = {
                attachment_group_id: groupId ? Number(groupId) : null,
                allowed_mimes: allowedMimes ? normalizeList(allowedMimes) : null,
            }
            const updated = await updateAttachmentExtension(extensionId, payload)
            setAttachmentExtensions((prev) =>
                prev.map((item) => (item.id === updated.id ? updated : item))
            )
        } catch (err) {
            setAttachmentExtensionsError(err.message)
        } finally {
            setAttachmentExtensionSavingId(null)
        }
    }

    const handleAttachmentExtensionDelete = async (extension) => {
        setAttachmentExtensionDeleteTarget(extension)
        setShowAttachmentExtensionDelete(true)
    }

    const confirmAttachmentExtensionDelete = async () => {
        if (!attachmentExtensionDeleteTarget) return
        setAttachmentExtensionSaving(true)
        setAttachmentExtensionsError('')
        try {
            await deleteAttachmentExtension(attachmentExtensionDeleteTarget.id)
            setAttachmentExtensions((prev) =>
                prev.filter((item) => item.id !== attachmentExtensionDeleteTarget.id)
            )
            setShowAttachmentExtensionDelete(false)
            setAttachmentExtensionDeleteTarget(null)
        } catch (err) {
            setAttachmentExtensionsError(err.message)
        } finally {
            setAttachmentExtensionSaving(false)
        }
    }

    const openAttachmentExtensionEdit = (extension) => {
        setAttachmentExtensionEdit(extension)
        setNewAttachmentExtension({
            extension: extension.extension || '',
            groupId: extension.attachment_group_id ? String(extension.attachment_group_id) : '',
            allowedMimes: (extension.allowed_mimes || []).join(', '),
        })
        setShowAttachmentExtensionModal(true)
    }

    const handleSeedAttachmentDefaults = async () => {
        setAttachmentSeedSaving(true)
        setAttachmentGroupsError('')
        setAttachmentExtensionsError('')
        try {
            const groupsByName = new Map(attachmentGroups.map((group) => [group.name, group]))
            const extensionsByGroup = new Map()
            attachmentExtensions.forEach((ext) => {
                const groupId = ext.attachment_group_id ? String(ext.attachment_group_id) : 'none'
                if (!extensionsByGroup.has(groupId)) {
                    extensionsByGroup.set(groupId, new Set())
                }
                extensionsByGroup
                    .get(groupId)
                    .add(String(ext.extension || '').toLowerCase())
            })
            const createdGroups = []
            const createdExtensions = []

            for (const group of attachmentDefaultSeed) {
                let parent = groupsByName.get(group.name)
                if (!parent) {
                    parent = await createAttachmentGroup({
                        name: group.name,
                        max_size_kb: group.max_size_kb,
                        is_active: true,
                    })
                    groupsByName.set(group.name, parent)
                    createdGroups.push(parent)
                }
                createdGroups.push(parent)

                for (const child of group.children || []) {
                    let createdChild = groupsByName.get(child.name)
                    if (!createdChild) {
                        createdChild = await createAttachmentGroup({
                            name: child.name,
                            parent_id: parent.id,
                            max_size_kb: child.max_size_kb,
                            is_active: true,
                        })
                        groupsByName.set(child.name, createdChild)
                        createdGroups.push(createdChild)
                    }

                    const groupKey = String(createdChild.id)
                    const existingSet = extensionsByGroup.get(groupKey) || new Set()

                    for (const ext of child.extensions || []) {
                        const key = String(ext.ext || '').toLowerCase()
                        if (existingSet.has(key)) {
                            continue
                        }
                        const createdExt = await createAttachmentExtension({
                            extension: ext.ext,
                            attachment_group_id: createdChild.id,
                            allowed_mimes: ext.mimes,
                        })
                        createdExtensions.push(createdExt)
                        existingSet.add(key)
                    }
                    extensionsByGroup.set(groupKey, existingSet)
                }
            }

            setAttachmentGroups((prev) =>
                [...prev, ...createdGroups].sort((a, b) => a.name.localeCompare(b.name))
            )
            setAttachmentExtensions((prev) =>
                [...prev, ...createdExtensions].sort((a, b) => a.extension.localeCompare(b.extension))
            )
        } catch (err) {
            setAttachmentGroupsError(err.message)
        } finally {
            setAttachmentSeedSaving(false)
        }
    }

    const handleAttachmentGroupAutoNest = async () => {
        const groupsByName = new Map(attachmentGroups.map((group) => [group.name, group]))
        const needsParent = attachmentGroups.every((group) => !group.parent_id)
        if (!needsParent) return

        setAttachmentSeedSaving(true)
        setAttachmentGroupsError('')
        try {
            const ensureParent = async (name) => {
                const existing = groupsByName.get(name)
                if (existing) return existing
                const created = await createAttachmentGroup({
                    name,
                    max_size_kb: 25600,
                    is_active: true,
                })
                groupsByName.set(name, created)
                setAttachmentGroups((prev) => [...prev, created])
                return created
            }

            const mediaParent = await ensureParent('Media')
            const filesParent = await ensureParent('Files')

            const mapping = {
                Image: mediaParent.id,
                Video: mediaParent.id,
                Audio: mediaParent.id,
                Archive: filesParent.id,
                Documents: filesParent.id,
                Other: filesParent.id,
            }

            const updatedGroups = []
            for (const group of attachmentGroups) {
                const targetParent = mapping[group.name]
                if (!targetParent) continue
                const updated = await updateAttachmentGroup(group.id, {
                    name: group.name,
                    parent_id: targetParent,
                    max_size_kb: group.max_size_kb,
                    is_active: group.is_active,
                })
                updatedGroups.push(updated)
            }

            setAttachmentGroups((prev) =>
                prev.map((group) => updatedGroups.find((u) => u.id === group.id) || group)
            )
        } catch (err) {
            setAttachmentGroupsError(err.message)
        } finally {
            setAttachmentSeedSaving(false)
        }
    }

    const handleAddExtensionForGroup = (groupId) => {
        setNewAttachmentExtension({
            extension: '',
            groupId: groupId ? String(groupId) : '',
            allowedMimes: '',
        })
        setAttachmentExtensionEdit(null)
        setShowAttachmentExtensionModal(true)
    }

    const openAttachmentExtensionModal = () => {
        setNewAttachmentExtension({
            extension: '',
            groupId: '',
            allowedMimes: '',
        })
        setAttachmentExtensionEdit(null)
        setShowAttachmentExtensionModal(true)
    }

    useEffect(() => {
        if (isAdmin) {
            loadAttachmentGroups()
            loadAttachmentExtensions()
        }
    }, [isAdmin])

    useEffect(() => {
        if (attachmentGroups.length === 0) return
        const ids = attachmentGroups.map((group) => String(group.id))
        setAttachmentGroupCollapsed(new Set(ids))
    }, [attachmentGroups.length])

    const getAttachmentGroupParentId = (group) => group.parent_id ?? null

    const buildAttachmentGroupTree = useMemo(() => {
        const map = new Map()
        const roots = []

        attachmentGroups.forEach((group) => {
            map.set(String(group.id), { ...group, children: [] })
        })

        attachmentGroups.forEach((group) => {
            const parentId = group.parent_id
            const node = map.get(String(group.id))
            if (parentId && map.has(String(parentId))) {
                map.get(String(parentId)).children.push(node)
            } else {
                roots.push(node)
            }
        })

        const sortNodes = (nodes) => {
            nodes.sort((a, b) => {
                const aPos = a.position ?? 0
                const bPos = b.position ?? 0
                if (aPos !== bPos) return aPos - bPos
                return (a.name || '').localeCompare(b.name || '')
            })
            nodes.forEach((node) => {
                if (node.children?.length) {
                    sortNodes(node.children)
                }
            })
        }

        sortNodes(roots)
        return roots
    }, [attachmentGroups])

    const attachmentGroupOptions = useMemo(() => {
        const options = []
        const walk = (nodes, depth) => {
            nodes.forEach((node) => {
                const prefix = depth > 0 ? `${'—'.repeat(depth)} ` : ''
                options.push({ id: node.id, label: `${prefix}${node.name}` })
                if (node.children?.length) {
                    walk(node.children, depth + 1)
                }
            })
        }
        walk(buildAttachmentGroupTree, 0)
        return options
    }, [buildAttachmentGroupTree])

    const isAttachmentGroupExpanded = (groupId) => !attachmentGroupCollapsed.has(String(groupId))

    const toggleAttachmentGroupExpanded = (groupId) => {
        const key = String(groupId)
        setAttachmentGroupCollapsed((prev) => {
            const next = new Set(prev)
            if (next.has(key)) {
                next.delete(key)
            } else {
                next.add(key)
            }
            return next
        })
    }

    const handleAttachmentGroupCollapseAll = () => {
        const ids = attachmentGroups.map((group) => String(group.id))
        setAttachmentGroupCollapsed(new Set(ids))
    }

    const handleAttachmentGroupExpandAll = () => {
        setAttachmentGroupCollapsed(new Set())
    }

    const applyAttachmentGroupLocalOrder = (parentId, orderedIds) => {
        setAttachmentGroups((prev) =>
            prev.map((group) => {
                const pid = getAttachmentGroupParentId(group)
                if (String(pid ?? '') !== String(parentId ?? '')) {
                    return group
                }
                const newIndex = orderedIds.indexOf(String(group.id))
                return newIndex === -1 ? group : { ...group, position: newIndex + 1 }
            })
        )
    }

    const handleAttachmentGroupDragStart = (event, groupId) => {
        event.dataTransfer.effectAllowed = 'move'
        event.dataTransfer.setData('text/plain', String(groupId))
        setAttachmentGroupDraggingId(String(groupId))
    }

    const handleAttachmentGroupDragEnd = () => {
        if (attachmentGroupPendingOrder.current) {
            const { parentId, ordered } = attachmentGroupPendingOrder.current
            attachmentGroupPendingOrder.current = null
            reorderAttachmentGroups(parentId, ordered).catch((err) => setAttachmentGroupsError(err.message))
        }
        setAttachmentGroupDraggingId(null)
        setAttachmentGroupOverId(null)
    }

    const handleAttachmentGroupDragOver = (event, targetId, parentId) => {
        event.preventDefault()
        event.dataTransfer.dropEffect = 'move'
        if (!attachmentGroupDraggingId || String(attachmentGroupDraggingId) === String(targetId)) {
            return
        }

        const draggedGroup = attachmentGroups.find(
            (group) => String(group.id) === String(attachmentGroupDraggingId)
        )
        if (!draggedGroup) {
            return
        }

        const draggedParentId = getAttachmentGroupParentId(draggedGroup)
        if (String(draggedParentId ?? '') !== String(parentId ?? '')) {
            return
        }

        const siblings = attachmentGroups.filter((group) => {
            const pid = getAttachmentGroupParentId(group)
            return String(pid ?? '') === String(parentId ?? '')
        })

        const ordered = siblings
            .slice()
            .sort((a, b) => {
                if (a.position !== b.position) return a.position - b.position
                return a.name.localeCompare(b.name)
            })
            .map((group) => String(group.id))

        const fromIndex = ordered.indexOf(String(attachmentGroupDraggingId))
        const toIndex = ordered.indexOf(String(targetId))
        if (fromIndex === -1 || toIndex === -1 || fromIndex === toIndex) {
            return
        }

        ordered.splice(toIndex, 0, ordered.splice(fromIndex, 1)[0])
        setAttachmentGroupOverId(String(targetId))
        applyAttachmentGroupLocalOrder(parentId, ordered)
        attachmentGroupPendingOrder.current = { parentId, ordered }
    }

    const handleAttachmentGroupDragEnter = (groupId) => {
        if (attachmentGroupDraggingId && String(groupId) !== String(attachmentGroupDraggingId)) {
            setAttachmentGroupOverId(String(groupId))
        }
    }

    const handleAttachmentGroupDragLeave = (event, groupId) => {
        if (event.currentTarget.contains(event.relatedTarget)) {
            return
        }
        if (attachmentGroupOverId === String(groupId)) {
            setAttachmentGroupOverId(null)
        }
    }

    const handleAttachmentGroupDrop = async (event, targetId, parentId) => {
        event.preventDefault()
        const draggedId = event.dataTransfer.getData('text/plain')
        if (!draggedId || String(draggedId) === String(targetId)) {
            setAttachmentGroupDraggingId(null)
            setAttachmentGroupOverId(null)
            return
        }

        const siblings = attachmentGroups.filter((group) => {
            const pid = getAttachmentGroupParentId(group)
            return String(pid ?? '') === String(parentId ?? '')
        })

        const ordered = siblings
            .slice()
            .sort((a, b) => {
                if (a.position !== b.position) return a.position - b.position
                return a.name.localeCompare(b.name)
            })
            .map((group) => String(group.id))

        const fromIndex = ordered.indexOf(String(draggedId))
        const toIndex = ordered.indexOf(String(targetId))
        if (fromIndex === -1 || toIndex === -1) {
            return
        }

        ordered.splice(toIndex, 0, ordered.splice(fromIndex, 1)[0])
        attachmentGroupPendingOrder.current = null

        try {
            await reorderAttachmentGroups(parentId, ordered)
            const updated = attachmentGroups.map((group) => {
                const pid = getAttachmentGroupParentId(group)
                if (String(pid ?? '') !== String(parentId ?? '')) {
                    return group
                }
                const newIndex = ordered.indexOf(String(group.id))
                return newIndex === -1 ? group : { ...group, position: newIndex + 1 }
            })
            setAttachmentGroups(updated)
        } catch (err) {
            setAttachmentGroupsError(err.message)
        } finally {
            setAttachmentGroupDraggingId(null)
            setAttachmentGroupOverId(null)
        }
    }

    const renderAttachmentGroupTree = (nodes, depth = 0) =>
        nodes.map((node) => {
            const groupExtensions = attachmentExtensions.filter(
                (ext) => Number(ext.attachment_group_id) === Number(node.id)
            )
            const isExpandable = (node.children?.length || 0) > 0 || groupExtensions.length > 0
            return (
            <div key={node.id}>
                <div
                    className={`bb-drag-item d-flex align-items-center justify-content-between border rounded p-2 mb-2 ${
                        attachmentGroupOverId === String(node.id) ? 'bb-drop-target' : ''
                    } ${attachmentGroupDraggingId === String(node.id) ? 'bb-dragging' : ''}`}
                    style={{ marginLeft: depth * 16 }}
                    draggable
                    onDragStart={(event) => handleAttachmentGroupDragStart(event, node.id)}
                    onDragEnd={handleAttachmentGroupDragEnd}
                    onDragOver={(event) =>
                        handleAttachmentGroupDragOver(event, node.id, getAttachmentGroupParentId(node))
                    }
                    onDragEnter={() => handleAttachmentGroupDragEnter(node.id)}
                    onDragLeave={(event) => handleAttachmentGroupDragLeave(event, node.id)}
                    onDrop={(event) => handleAttachmentGroupDrop(event, node.id, getAttachmentGroupParentId(node))}
                >
                    <div
                        className="d-flex align-items-start gap-3 bb-attachment-tree-toggle"
                        role={isExpandable ? 'button' : undefined}
                        tabIndex={isExpandable ? 0 : undefined}
                        onClick={() => {
                            if (isExpandable) {
                                toggleAttachmentGroupExpanded(node.id)
                            }
                        }}
                        onKeyDown={(event) => {
                            if (isExpandable && (event.key === 'Enter' || event.key === ' ')) {
                                event.preventDefault()
                                toggleAttachmentGroupExpanded(node.id)
                            }
                        }}
                    >
                        <span className="bb-icon">
                            <i className="bi bi-folder2" />
                            {isExpandable && (
                                <button
                                    type="button"
                                    className="bb-collapse-toggle"
                                    onClick={(event) => {
                                        event.stopPropagation()
                                        toggleAttachmentGroupExpanded(node.id)
                                    }}
                                    aria-label={
                                        isAttachmentGroupExpanded(node.id) ? t('acp.collapse') : t('acp.expand')
                                    }
                                    title={
                                        isAttachmentGroupExpanded(node.id) ? t('acp.collapse') : t('acp.expand')
                                    }
                                >
                                    <i
                                        className={`bi ${
                                            isAttachmentGroupExpanded(node.id)
                                                ? 'bi-caret-down-fill'
                                                : 'bi-caret-right-fill'
                                        }`}
                                        aria-hidden="true"
                                    />
                                </button>
                            )}
                        </span>
                        <div>
                            <div className="fw-semibold d-flex align-items-center gap-2">
                                <span>{node.name}</span>
                            </div>
                            <div className="bb-muted d-flex flex-wrap gap-2">
                                <span>{formatSizeKb(node.max_size_kb)}</span>
                                <span>•</span>
                                <span>
                                    {node.is_active ? t('attachment.active') : t('attachment.inactive')}
                                </span>
                                {typeof node.extensions_count === 'number' && (
                                    <>
                                        <span>•</span>
                                        <span>
                                            {t('attachment.group_extensions', { count: node.extensions_count })}
                                        </span>
                                    </>
                                )}
                            </div>
                        </div>
                    </div>
                    <div className="d-flex align-items-center gap-3">
                        <span
                            className="bb-drag-handle text-muted"
                            style={{ cursor: 'grab', display: 'inline-flex' }}
                            title={t('acp.drag_handle')}
                        >
                            <i className="bi bi-arrow-down-up" aria-hidden="true" />
                        </span>
                        <div className="bb-tree-action-group">
                            <ButtonGroup size="sm" className="bb-action-group w-100">
                                <Button
                                    variant="dark"
                                    onClick={() => openAttachmentGroupChildModal(node.id)}
                                    title={t('attachment.group_add_child')}
                                >
                                    <i className="bi bi-folder-plus" aria-hidden="true" />
                                </Button>
                                <Button
                                    variant="dark"
                                    onClick={() => handleAddExtensionForGroup(node.id)}
                                    title={t('attachment.extension_add_button')}
                                >
                                    <i className="bi bi-file-earmark-plus" aria-hidden="true" />
                                </Button>
                                <Button
                                    variant="dark"
                                    onClick={() => openAttachmentGroupModal(node)}
                                    title={t('acp.edit')}
                                >
                                    <i className="bi bi-pencil" aria-hidden="true" />
                                </Button>
                                <Button
                                    variant="dark"
                                    onClick={() => handleAttachmentGroupDelete(node)}
                                    disabled={attachmentGroupSaving}
                                    title={t('acp.delete')}
                                >
                                    <i className="bi bi-trash" aria-hidden="true" />
                                </Button>
                            </ButtonGroup>
                        </div>
                    </div>
                </div>
                {isAttachmentGroupExpanded(node.id) && (
                    <div className="mb-2">
                        {node.children?.length > 0 && renderAttachmentGroupTree(node.children, depth + 1)}
                        {groupExtensions.length > 0 && (
                            <div
                                className="bb-attachment-extension-table"
                                style={{ marginLeft: (depth + 1) * 16 }}
                            >
                                <div className="bb-attachment-extension-header tr-header">
                                    <span>{t('attachment.extension')}</span>
                                    <span>{t('attachment.allowed_mimes')}</span>
                                    <span>{t('attachment.extension_group')}</span>
                                    <span>{t('attachment.actions')}</span>
                                </div>
                                {groupExtensions.map((extension) => (
                                    <div key={extension.id} className="bb-attachment-extension-row">
                                        <span className="bb-attachment-extension-name">
                                            {extension.extension}
                                        </span>
                                        <span className="bb-attachment-extension-meta">
                                            {(extension.allowed_mimes || []).join(', ')}
                                        </span>
                                        <span className="bb-attachment-extension-meta">
                                            {attachmentGroups.find((group) => group.id === extension.attachment_group_id)?.name
                                                || t('attachment.extension_unassigned')}
                                        </span>
                                        <div className="bb-attachment-extension-actions">
                                            <ButtonGroup size="sm" className="bb-action-group">
                                                <Button
                                                    variant="dark"
                                                    onClick={() => openAttachmentExtensionEdit(extension)}
                                                    disabled={attachmentExtensionSaving}
                                                >
                                                    <i className="bi bi-pencil" aria-hidden="true" />
                                                </Button>
                                                <Button
                                                    variant="dark"
                                                    onClick={() => handleAttachmentExtensionDelete(extension)}
                                                    disabled={attachmentExtensionSaving}
                                                >
                                                    <i className="bi bi-trash" aria-hidden="true" />
                                                </Button>
                                            </ButtonGroup>
                                        </div>
                                    </div>
                                ))}
                            </div>
                        )}
                    </div>
                )}
            </div>
        )
        })

    const handleCreateRole = async (event) => {
        event.preventDefault()
        if (!roleFormName.trim()) return
        setRoleSaving(true)
        setRolesError('')
        try {
            const created = await createRole({
                name: roleFormName.trim(),
                color: roleFormColor.trim() || null,
            })
            setRoles((prev) => [...prev, created].sort((a, b) => a.name.localeCompare(b.name)))
            setRoleFormName('')
            setRoleFormColor('')
            setShowRoleCreate(false)
        } catch (err) {
            setRolesError(err.message)
        } finally {
            setRoleSaving(false)
        }
    }

    const getParentId = (forum) => {
        if (!forum.parent) return null
        if (typeof forum.parent === 'string') {
            return forum.parent.split('/').pop()
        }
        return forum.parent.id ?? null
    }

    const forumTree = useMemo(() => {
        const map = new Map()
        const roots = []

        forums.forEach((forum) => {
            map.set(String(forum.id), { ...forum, children: [] })
        })

        forums.forEach((forum) => {
            const parentId = getParentId(forum)
            const node = map.get(String(forum.id))
            if (parentId && map.has(String(parentId))) {
                map.get(String(parentId)).children.push(node)
            } else {
                roots.push(node)
            }
        })

        const sortNodes = (nodes) => {
            nodes.sort((a, b) => {
                if (a.position !== b.position) return a.position - b.position
                return a.name.localeCompare(b.name)
            })
            nodes.forEach((node) => sortNodes(node.children))
        }

        sortNodes(roots)

        return { roots, map }
    }, [forums])

    const categoryOptions = useMemo(
        () => forums.filter((forum) => forum.type === 'category'),
        [forums]
    )

    const handleSelectForum = (forum) => {
        const parentId =
            typeof forum.parent === 'string'
                ? forum.parent.split('/').pop()
                : forum.parent?.id ?? ''
        setSelectedId(String(forum.id))
        setShowModal(true)
        setCreateType(null)
        setForm({
            name: forum.name || '',
            description: forum.description || '',
            type: forum.type || 'category',
            parentId: parentId ? String(parentId) : '',
        })
    }

    const handleReset = () => {
        setSelectedId(null)
        setShowModal(false)
        setCreateType(null)
        setForm({
            name: '',
            description: '',
            type: 'category',
            parentId: '',
        })
    }

    const isExpanded = (forumId) => {
        const key = String(forumId)
        return !collapsed.has(key)
    }

    const toggleExpanded = (forumId) => {
        const key = String(forumId)
        setCollapsed((prev) => {
            const next = new Set(prev)
            if (next.has(key)) {
                next.delete(key)
            } else {
                next.add(key)
            }
            return next
        })
    }

    const handleCollapseAll = () => {
        const ids = forums
            .filter((forum) => forum.type === 'category')
            .map((forum) => String(forum.id))
        setCollapsed(new Set(ids))
    }

    const handleExpandAll = () => {
        setCollapsed(new Set())
    }

    const handleStartCreate = (type) => {
        const current = selectedId
        setSelectedId(null)
        setShowModal(true)
        setCreateType(type)
        const parentFromSelection = current
            ? forums.find((forum) => String(forum.id) === String(current))
            : null
        const parentId =
            parentFromSelection?.type === 'category' ? String(parentFromSelection.id) : ''
        setForm({
            name: '',
            description: '',
            type,
            parentId,
        })
    }

    const handleStartCreateChild = (type, parentId) => {
        setSelectedId(null)
        setShowModal(true)
        setCreateType(type)
        setForm({
            name: '',
            description: '',
            type,
            parentId: parentId ? String(parentId) : '',
        })
    }

    const handleSubmit = async (event) => {
        event.preventDefault()
        setError('')
        const trimmedName = form.name.trim()
        if (!trimmedName) {
            setError(t('acp.forums_name_required'))
            return
        }
        if (form.type === 'forum' && !form.parentId) {
            setError(t('acp.forums_parent_required'))
            return
        }
        try {
            if (selectedId) {
                await updateForum(selectedId, {
                    name: trimmedName,
                    description: form.description,
                    type: form.type,
                    parentId: form.parentId || null,
                })
            } else {
                await createForum({
                    name: trimmedName,
                    description: form.description,
                    type: form.type,
                    parentId: form.parentId || null,
                })
            }
            handleReset()
            refreshForums()
        } catch (err) {
            setError(err.message)
        }
    }

    const handleDelete = async (forumId) => {
        setError('')
        if (!confirm(t('acp.forums_confirm_delete'))) {
            return
        }
        try {
            await deleteForum(forumId)
            if (selectedId === String(forumId)) {
                handleReset()
            }
            refreshForums()
        } catch (err) {
            setError(err.message)
        }
    }

    const handleDragStart = (event, forumId) => {
        event.dataTransfer.effectAllowed = 'move'
        event.dataTransfer.setData('text/plain', String(forumId))
        setDraggingId(String(forumId))
    }

    const handleDragEnd = () => {
        if (pendingOrder.current) {
            const { parentId, ordered } = pendingOrder.current
            pendingOrder.current = null
            reorderForums(parentId, ordered).catch((err) => setError(err.message))
        }
        setDraggingId(null)
        setOverId(null)
    }

    const applyLocalOrder = (parentId, orderedIds) => {
        setForums((prev) =>
            prev.map((forum) => {
                const pid = getParentId(forum)
                if (String(pid ?? '') !== String(parentId ?? '')) {
                    return forum
                }
                const newIndex = orderedIds.indexOf(String(forum.id))
                return newIndex === -1 ? forum : { ...forum, position: newIndex + 1 }
            })
        )
    }

    const handleDragOver = (event, targetId, parentId) => {
        event.preventDefault()
        event.dataTransfer.dropEffect = 'move'
        if (!draggingId || String(draggingId) === String(targetId)) {
            return
        }

        const draggedForum = forums.find((forum) => String(forum.id) === String(draggingId))
        if (!draggedForum) {
            return
        }

        const draggedParentId = getParentId(draggedForum)
        if (String(draggedParentId ?? '') !== String(parentId ?? '')) {
            return
        }

        const siblings = forums.filter((forum) => {
            const pid = getParentId(forum)
            return String(pid ?? '') === String(parentId ?? '')
        })

        const ordered = siblings
            .slice()
            .sort((a, b) => {
                if (a.position !== b.position) return a.position - b.position
                return a.name.localeCompare(b.name)
            })
            .map((forum) => String(forum.id))

        const fromIndex = ordered.indexOf(String(draggingId))
        const toIndex = ordered.indexOf(String(targetId))
        if (fromIndex === -1 || toIndex === -1 || fromIndex === toIndex) {
            return
        }

        ordered.splice(toIndex, 0, ordered.splice(fromIndex, 1)[0])
        setOverId(String(targetId))
        applyLocalOrder(parentId, ordered)
        pendingOrder.current = { parentId, ordered }
    }

    const handleDragEnter = (forumId) => {
        if (draggingId && String(forumId) !== String(draggingId)) {
            setOverId(String(forumId))
        }
    }

    const handleDragLeave = (event, forumId) => {
        if (event.currentTarget.contains(event.relatedTarget)) {
            return
        }
        if (overId === String(forumId)) {
            setOverId(null)
        }
    }

    const handleDrop = async (event, targetId, parentId) => {
        event.preventDefault()
        const draggedId = event.dataTransfer.getData('text/plain')
        if (!draggedId || String(draggedId) === String(targetId)) {
            setDraggingId(null)
            setOverId(null)
            return
        }

        const siblings = forums.filter((forum) => {
            const pid = getParentId(forum)
            return String(pid ?? '') === String(parentId ?? '')
        })

        const ordered = siblings
            .slice()
            .sort((a, b) => {
                if (a.position !== b.position) return a.position - b.position
                return a.name.localeCompare(b.name)
            })
            .map((forum) => String(forum.id))

        const fromIndex = ordered.indexOf(String(draggedId))
        const toIndex = ordered.indexOf(String(targetId))
        if (fromIndex === -1 || toIndex === -1) {
            return
        }

        ordered.splice(toIndex, 0, ordered.splice(fromIndex, 1)[0])
        pendingOrder.current = null

        try {
            await reorderForums(parentId, ordered)
            const updated = forums.map((forum) => {
                const pid = getParentId(forum)
                if (String(pid ?? '') !== String(parentId ?? '')) {
                    return forum
                }
                const newIndex = ordered.indexOf(String(forum.id))
                return newIndex === -1 ? forum : { ...forum, position: newIndex + 1 }
            })
            setForums(updated)
        } catch (err) {
            setError(err.message)
        } finally {
            setDraggingId(null)
            setOverId(null)
        }
    }

    const renderTree = (nodes, depth = 0) =>
        nodes.map((node) => (
            <div key={node.id}>
                <div
                    className={`bb-drag-item d-flex align-items-center justify-content-between border rounded p-2 mb-2 ${
                        overId === String(node.id) ? 'bb-drop-target' : ''
                    } ${draggingId === String(node.id) ? 'bb-dragging' : ''}`}
                    style={{ marginLeft: depth * 16 }}
                    draggable
                    onDragStart={(event) => handleDragStart(event, node.id)}
                    onDragEnd={handleDragEnd}
                    onDragOver={(event) => handleDragOver(event, node.id, getParentId(node))}
                    onDragEnter={() => handleDragEnter(node.id)}
                    onDragLeave={(event) => handleDragLeave(event, node.id)}
                    onDrop={(event) => handleDrop(event, node.id, getParentId(node))}
                >
                    <div className="d-flex align-items-start gap-3">
                        <span className={`bb-icon ${node.type === 'forum' ? 'bb-icon--forum' : ''}`}>
                            <i className={`bi ${node.type === 'category' ? 'bi-folder2' : 'bi-chat-left-text'}`} />
                            {node.type === 'category' && node.children?.length > 0 && (
                                <button
                                    type="button"
                                    className="bb-collapse-toggle"
                                    onClick={() => toggleExpanded(node.id)}
                                    aria-label={isExpanded(node.id) ? t('acp.collapse') : t('acp.expand')}
                                    title={isExpanded(node.id) ? t('acp.collapse') : t('acp.expand')}
                                >
                                    <i
                                        className={`bi ${
                                            isExpanded(node.id) ? 'bi-caret-down-fill' : 'bi-caret-right-fill'
                                        }`}
                                        aria-hidden="true"
                                    />
                                </button>
                            )}
                        </span>
                        <div>
                            <div className="fw-semibold d-flex align-items-center gap-2">
                                <span>{node.name}</span>
                            </div>
                            <div className="bb-muted">{node.description || ''}</div>
                        </div>
                    </div>
                    <div className="d-flex align-items-center gap-3">
                        <span
                            className="bb-drag-handle text-muted"
                            style={{ cursor: 'grab', display: 'inline-flex' }}
                            title={t('acp.drag_handle')}
                        >
                            <i className="bi bi-arrow-down-up" aria-hidden="true" />
                        </span>
                        <div className="bb-tree-action-group">
                            <ButtonGroup size="sm" className="bb-action-group w-100">
                                {node.type === 'category' && (
                                    <>
                                        <Button
                                            variant="dark"
                                            onClick={() => handleStartCreateChild('category', node.id)}
                                            title={t('acp.add_category')}
                                        >
                                            <i className="bi bi-folder-plus" aria-hidden="true" />
                                        </Button>
                                        <Button
                                            variant="dark"
                                            onClick={() => handleStartCreateChild('forum', node.id)}
                                            title={t('acp.add_forum')}
                                        >
                                            <i className="bi bi-chat-left-text" aria-hidden="true" />
                                        </Button>
                                    </>
                                )}
                                <Button variant="dark" onClick={() => handleSelectForum(node)} title={t('acp.edit')}>
                                    <i className="bi bi-pencil" aria-hidden="true" />
                                </Button>
                                <Button variant="dark" onClick={() => handleDelete(node.id)} title={t('acp.delete')}>
                                    <i className="bi bi-trash" aria-hidden="true" />
                                </Button>
                            </ButtonGroup>
                        </div>
                    </div>
                </div>
                {node.children?.length > 0 &&
                    (!node.type || node.type !== 'category' || isExpanded(node.id)) && (
                        <div className="mb-2">{renderTree(node.children, depth + 1)}</div>
                    )}
            </div>
        ))

    if (!isAdmin) {
        return (
            <Container fluid className="py-5">
                <h2 className="mb-3">{t('acp.title')}</h2>
                <p className="bb-muted">{t('acp.no_access')}</p>
            </Container>
        )
    }

    return (
        <Container fluid className="bb-acp py-4">
            <h2 className="mb-4">{t('acp.title')}</h2>
            <Tabs defaultActiveKey="general" className="mb-3">
                <Tab eventKey="general" title={t('acp.general')}>
                    <p className="bb-muted">{t('acp.general_hint')}</p>
                    {generalError && <p className="text-danger">{generalError}</p>}
                    <Form onSubmit={handleGeneralSave} className="bb-acp-general">
                        <Row className="g-3">
                            <Col lg={6}>
                                <Form.Group>
                                    <Form.Label>{t('acp.forum_name')}</Form.Label>
                                    <Form.Control
                                        type="text"
                                        value={generalSettings.forum_name}
                                        onChange={(event) =>
                                            setGeneralSettings((prev) => ({ ...prev, forum_name: event.target.value }))
                                        }
                                    />
                                </Form.Group>
                                <Form.Group className="mt-2">
                                    <Form.Check
                                        type="checkbox"
                                        id="acp-show-header-name"
                                        label={t('acp.show_header_name')}
                                        checked={generalSettings.show_header_name !== 'false'}
                                        onChange={(event) =>
                                            setGeneralSettings((prev) => ({
                                                ...prev,
                                                show_header_name: event.target.checked ? 'true' : 'false',
                                            }))
                                        }
                                    />
                                </Form.Group>
                            </Col>
                            <Col lg={6}>
                                <Form.Group>
                                    <Form.Label>{t('acp.default_theme')}</Form.Label>
                                    <Form.Select
                                        value={generalSettings.default_theme}
                                        onChange={(event) => handleDefaultThemeChange(event.target.value)}
                                    >
                                        <option value="auto">{t('ucp.system_default')}</option>
                                        <option value="dark">{t('nav.theme_dark')}</option>
                                        <option value="light">{t('nav.theme_light')}</option>
                                    </Form.Select>
                                </Form.Group>
                            </Col>
                            <Col lg={6}>
                                <Form.Group>
                                    <Form.Label>{t('acp.accent_dark')}</Form.Label>
                                    <div className="d-flex align-items-center gap-2">
                                        <Form.Control
                                            type="text"
                                            value={generalSettings.accent_color_dark}
                                            onChange={(event) =>
                                                setGeneralSettings((prev) => ({
                                                    ...prev,
                                                    accent_color_dark: event.target.value,
                                                }))
                                            }
                                            placeholder="#f29b3f"
                                        />
                                        <Form.Control
                                            type="color"
                                            value={generalSettings.accent_color_dark || '#f29b3f'}
                                            onChange={(event) =>
                                                setGeneralSettings((prev) => ({
                                                    ...prev,
                                                    accent_color_dark: event.target.value,
                                                }))
                                            }
                                        />
                                    </div>
                                </Form.Group>
                            </Col>
                            <Col lg={6}>
                                <Form.Group>
                                    <Form.Label>{t('acp.accent_light')}</Form.Label>
                                    <div className="d-flex align-items-center gap-2">
                                        <Form.Control
                                            type="text"
                                            value={generalSettings.accent_color_light}
                                            onChange={(event) =>
                                                setGeneralSettings((prev) => ({
                                                    ...prev,
                                                    accent_color_light: event.target.value,
                                                }))
                                            }
                                            placeholder="#f29b3f"
                                        />
                                        <Form.Control
                                            type="color"
                                            value={generalSettings.accent_color_light || '#f29b3f'}
                                            onChange={(event) =>
                                                setGeneralSettings((prev) => ({
                                                    ...prev,
                                                    accent_color_light: event.target.value,
                                                }))
                                            }
                                        />
                                    </div>
                                </Form.Group>
                            </Col>
                            <Col lg={6}>
                                <Form.Group>
                                    <Form.Label>{t('acp.logo_dark')}</Form.Label>
                                    <div
                                        {...darkLogoDropzone.getRootProps({
                                            className: 'bb-dropzone',
                                        })}
                                    >
                                        <input {...darkLogoDropzone.getInputProps()} />
                                        {generalSettings.logo_dark ? (
                                            <div className="bb-dropzone-preview">
                                                <img src={generalSettings.logo_dark} alt={t('acp.logo_dark')} />
                                            </div>
                                        ) : (
                                            <div className="bb-dropzone-placeholder">
                                                <i className="bi bi-upload" aria-hidden="true" />
                                                <span>{t('acp.logo_upload')}</span>
                                            </div>
                                        )}
                                    </div>
                                </Form.Group>
                            </Col>
                            <Col lg={6}>
                                <Form.Group>
                                    <Form.Label>{t('acp.logo_light')}</Form.Label>
                                    <div
                                        {...lightLogoDropzone.getRootProps({
                                            className: 'bb-dropzone',
                                        })}
                                    >
                                        <input {...lightLogoDropzone.getInputProps()} />
                                        {generalSettings.logo_light ? (
                                            <div className="bb-dropzone-preview">
                                                <img src={generalSettings.logo_light} alt={t('acp.logo_light')} />
                                            </div>
                                        ) : (
                                            <div className="bb-dropzone-placeholder">
                                                <i className="bi bi-upload" aria-hidden="true" />
                                                <span>{t('acp.logo_upload')}</span>
                                            </div>
                                        )}
                                    </div>
                                </Form.Group>
                            </Col>
                            <Col xs={12}>
                                <Accordion className="bb-acp-accordion">
                                    <Accordion.Item eventKey="favicons">
                                        <Accordion.Header>{t('acp.favicons')}</Accordion.Header>
                                        <Accordion.Body>
                                            <Row className="g-3">
                                                <Col lg={4}>
                                                    <Form.Group>
                                                        <Form.Label>{t('acp.favicon_ico')}</Form.Label>
                                                        <div {...faviconIcoDropzone.getRootProps({ className: 'bb-dropzone' })}>
                                                            <input {...faviconIcoDropzone.getInputProps()} />
                                                            {generalSettings.favicon_ico ? (
                                                                <div className="bb-dropzone-preview">
                                                                    <img src={generalSettings.favicon_ico} alt={t('acp.favicon_ico')} />
                                                                </div>
                                                            ) : (
                                                                <div className="bb-dropzone-placeholder">
                                                                    <i className="bi bi-upload" aria-hidden="true" />
                                                                    <span>{t('acp.logo_upload')}</span>
                                                                </div>
                                                            )}
                                                        </div>
                                                    </Form.Group>
                                                </Col>
                                                <Col lg={4}>
                                                    <Form.Group>
                                                        <Form.Label>{t('acp.favicon_16')}</Form.Label>
                                                        <div {...favicon16Dropzone.getRootProps({ className: 'bb-dropzone' })}>
                                                            <input {...favicon16Dropzone.getInputProps()} />
                                                            {generalSettings.favicon_16 ? (
                                                                <div className="bb-dropzone-preview">
                                                                    <img src={generalSettings.favicon_16} alt={t('acp.favicon_16')} />
                                                                </div>
                                                            ) : (
                                                                <div className="bb-dropzone-placeholder">
                                                                    <i className="bi bi-upload" aria-hidden="true" />
                                                                    <span>{t('acp.logo_upload')}</span>
                                                                </div>
                                                            )}
                                                        </div>
                                                    </Form.Group>
                                                </Col>
                                                <Col lg={4}>
                                                    <Form.Group>
                                                        <Form.Label>{t('acp.favicon_32')}</Form.Label>
                                                        <div {...favicon32Dropzone.getRootProps({ className: 'bb-dropzone' })}>
                                                            <input {...favicon32Dropzone.getInputProps()} />
                                                            {generalSettings.favicon_32 ? (
                                                                <div className="bb-dropzone-preview">
                                                                    <img src={generalSettings.favicon_32} alt={t('acp.favicon_32')} />
                                                                </div>
                                                            ) : (
                                                                <div className="bb-dropzone-placeholder">
                                                                    <i className="bi bi-upload" aria-hidden="true" />
                                                                    <span>{t('acp.logo_upload')}</span>
                                                                </div>
                                                            )}
                                                        </div>
                                                    </Form.Group>
                                                </Col>
                                                <Col lg={4}>
                                                    <Form.Group>
                                                        <Form.Label>{t('acp.favicon_48')}</Form.Label>
                                                        <div {...favicon48Dropzone.getRootProps({ className: 'bb-dropzone' })}>
                                                            <input {...favicon48Dropzone.getInputProps()} />
                                                            {generalSettings.favicon_48 ? (
                                                                <div className="bb-dropzone-preview">
                                                                    <img src={generalSettings.favicon_48} alt={t('acp.favicon_48')} />
                                                                </div>
                                                            ) : (
                                                                <div className="bb-dropzone-placeholder">
                                                                    <i className="bi bi-upload" aria-hidden="true" />
                                                                    <span>{t('acp.logo_upload')}</span>
                                                                </div>
                                                            )}
                                                        </div>
                                                    </Form.Group>
                                                </Col>
                                                <Col lg={4}>
                                                    <Form.Group>
                                                        <Form.Label>{t('acp.favicon_64')}</Form.Label>
                                                        <div {...favicon64Dropzone.getRootProps({ className: 'bb-dropzone' })}>
                                                            <input {...favicon64Dropzone.getInputProps()} />
                                                            {generalSettings.favicon_64 ? (
                                                                <div className="bb-dropzone-preview">
                                                                    <img src={generalSettings.favicon_64} alt={t('acp.favicon_64')} />
                                                                </div>
                                                            ) : (
                                                                <div className="bb-dropzone-placeholder">
                                                                    <i className="bi bi-upload" aria-hidden="true" />
                                                                    <span>{t('acp.logo_upload')}</span>
                                                                </div>
                                                            )}
                                                        </div>
                                                    </Form.Group>
                                                </Col>
                                                <Col lg={4}>
                                                    <Form.Group>
                                                        <Form.Label>{t('acp.favicon_128')}</Form.Label>
                                                        <div {...favicon128Dropzone.getRootProps({ className: 'bb-dropzone' })}>
                                                            <input {...favicon128Dropzone.getInputProps()} />
                                                            {generalSettings.favicon_128 ? (
                                                                <div className="bb-dropzone-preview">
                                                                    <img src={generalSettings.favicon_128} alt={t('acp.favicon_128')} />
                                                                </div>
                                                            ) : (
                                                                <div className="bb-dropzone-placeholder">
                                                                    <i className="bi bi-upload" aria-hidden="true" />
                                                                    <span>{t('acp.logo_upload')}</span>
                                                                </div>
                                                            )}
                                                        </div>
                                                    </Form.Group>
                                                </Col>
                                                <Col lg={4}>
                                                    <Form.Group>
                                                        <Form.Label>{t('acp.favicon_256')}</Form.Label>
                                                        <div {...favicon256Dropzone.getRootProps({ className: 'bb-dropzone' })}>
                                                            <input {...favicon256Dropzone.getInputProps()} />
                                                            {generalSettings.favicon_256 ? (
                                                                <div className="bb-dropzone-preview">
                                                                    <img src={generalSettings.favicon_256} alt={t('acp.favicon_256')} />
                                                                </div>
                                                            ) : (
                                                                <div className="bb-dropzone-placeholder">
                                                                    <i className="bi bi-upload" aria-hidden="true" />
                                                                    <span>{t('acp.logo_upload')}</span>
                                                                </div>
                                                            )}
                                                        </div>
                                                    </Form.Group>
                                                </Col>
                                            </Row>
                                        </Accordion.Body>
                                    </Accordion.Item>
                                </Accordion>
                            </Col>
                            <Col xs={12} className="d-flex justify-content-end">
                                <Button
                                    type="submit"
                                    className="bb-accent-button"
                                    disabled={generalSaving || generalUploading}
                                >
                                    {generalSaving ? t('form.saving') : t('acp.save')}
                                </Button>
                            </Col>
                        </Row>
                    </Form>
                </Tab>
                <Tab eventKey="forums" title={t('acp.forums')}>
                    <p className="bb-muted">{t('acp.forums_hint')}</p>
                    {error && <p className="text-danger">{error}</p>}
                    <Row className="g-4">
                        <Col lg={12}>
                            <div className="d-flex align-items-center justify-content-between mb-3 gap-3 flex-wrap">
                                <div className="d-flex align-items-center gap-2">
                                    <h5 className="mb-0">{t('acp.forums_tree')}</h5>
                                    <Button size="sm" variant="outline-dark" className="bb-acp-action" onClick={handleExpandAll}>
                                        <i className="bi bi-arrows-expand me-1" aria-hidden="true" />
                                        {t('acp.expand_all')}
                                    </Button>
                                    <Button size="sm" variant="outline-dark" className="bb-acp-action" onClick={handleCollapseAll}>
                                        <i className="bi bi-arrows-collapse me-1" aria-hidden="true" />
                                        {t('acp.collapse_all')}
                                    </Button>
                                </div>
                                <div className="d-flex gap-2">
                                    <Button
                                        size="sm"
                                        variant="outline-dark"
                                        className={`bb-acp-action ${createType === 'category' ? 'bb-acp-action--active' : ''}`}
                                        onClick={() => handleStartCreate('category')}
                                    >
                                        <i className="bi bi-folder2 me-1" aria-hidden="true" />
                                        {t('acp.new_category')}
                                    </Button>
                                    <Button
                                        size="sm"
                                        variant="outline-dark"
                                        className={`bb-acp-action ${createType === 'forum' ? 'bb-acp-action--active' : ''}`}
                                        onClick={() => handleStartCreate('forum')}
                                    >
                                        <i className="bi bi-chat-left-text me-1" aria-hidden="true" />
                                        {t('acp.new_forum')}
                                    </Button>
                                </div>
                            </div>
                            {loading && <p className="bb-muted">{t('acp.loading')}</p>}
                            {!loading && forumTree.roots.length === 0 && (
                                <p className="bb-muted">{t('acp.forums_empty')}</p>
                            )}
                            {forumTree.roots.length > 0 && (
                                <div className="mt-2">{renderTree(forumTree.roots)}</div>
                            )}
                        </Col>
                    </Row>
                </Tab>
                <Tab eventKey="users" title={t('acp.users')}>
                    {usersError && <p className="text-danger">{usersError}</p>}
                    {ranksError && <p className="text-danger">{ranksError}</p>}
                    {usersLoading && <p className="bb-muted">{t('acp.loading')}</p>}
                    {!usersLoading && (
                        <DataTable
                            columns={userColumns}
                            data={filteredUsers}
                            pagination
                            striped
                            highlightOnHover={themeMode !== 'dark'}
                            dense
                            theme={themeMode === 'dark' ? 'speedbb-dark' : 'speedbb-light'}
                            customStyles={userTableStyles}
                            sortIcon={<span className="bb-sort-hidden" aria-hidden="true" />}
                            defaultSortFieldId="name"
                            onSort={(column, direction) => {
                                setUserSort({ columnId: column.id, direction })
                            }}
                            paginationComponentOptions={{
                                rowsPerPageText: t('table.rows_per_page'),
                                rangeSeparatorText: t('table.range_separator'),
                            }}
                            paginationPerPage={usersPerPage}
                            onChangePage={(page) => setUsersPage(page)}
                            onChangeRowsPerPage={(perPage) => {
                                setUsersPerPage(perPage)
                                setUsersPage(1)
                            }}
                            paginationComponent={UsersPagination}
                            subHeader
                            subHeaderComponent={
                                <Form.Control
                                    className="bb-user-search"
                                    value={userSearch}
                                    onChange={(event) => setUserSearch(event.target.value)}
                                    placeholder={t('user.search')}
                                />
                            }
                        />
                    )}
                </Tab>
                <Tab eventKey="groups" title={t('acp.groups')}>
                    {rolesError && <p className="text-danger">{rolesError}</p>}
                    <div className="d-flex justify-content-end mb-3">
                        <Button
                            type="button"
                            className="bb-accent-button"
                            onClick={() => setShowRoleCreate(true)}
                        >
                            {t('group.create')}
                        </Button>
                    </div>
                    {rolesLoading && <p className="bb-muted">{t('acp.loading')}</p>}
                    {!rolesLoading && roles.length === 0 && (
                        <p className="bb-muted">{t('group.empty')}</p>
                    )}
                    {!rolesLoading && roles.length > 0 && (
                        <div className="bb-rank-list">
                            {roles.map((role) => {
                                const coreRole = isCoreRole(role.name)
                                return (
                                    <div key={role.id} className="bb-rank-row">
                                        <div className="bb-rank-main">
                                            <span className="d-flex align-items-center gap-2">
                                                {role.color && (
                                                    <span
                                                        className="bb-rank-color"
                                                        style={{ backgroundColor: role.color }}
                                                        aria-hidden="true"
                                                    />
                                                )}
                                                <span>{formatRoleLabel(role.name)}</span>
                                            </span>
                                        </div>
                                        <div className="bb-rank-actions">
                                            <Button
                                                size="sm"
                                                variant="dark"
                                                title={coreRole ? t('group.core_locked') : t('group.edit')}
                                                onClick={() => {
                                                    setRoleEdit({
                                                        id: role.id,
                                                        name: formatRoleLabel(role.name),
                                                        originalName: role.name,
                                                        color: role.color || '',
                                                        isCore: coreRole,
                                                    })
                                                    setShowRoleModal(true)
                                                    setRolesError('')
                                                }}
                                            >
                                                <i className="bi bi-pencil" aria-hidden="true" />
                                            </Button>
                                            <Button
                                                size="sm"
                                                variant="dark"
                                                disabled={coreRole}
                                                title={coreRole ? t('group.core_locked') : t('group.delete')}
                                                onClick={async () => {
                                                    if (coreRole) return
                                                    if (!window.confirm(t('group.delete_confirm'))) return
                                                    setRoleSaving(true)
                                                    setRolesError('')
                                                    try {
                                                        await deleteRole(role.id)
                                                        setRoles((prev) =>
                                                            prev.filter((item) => item.id !== role.id)
                                                        )
                                                        setUsers((prev) =>
                                                            prev.map((user) => ({
                                                                ...user,
                                                                roles: (user.roles || []).filter(
                                                                    (name) => name !== role.name
                                                                ),
                                                            }))
                                                        )
                                                    } catch (err) {
                                                        setRolesError(err.message)
                                                    } finally {
                                                        setRoleSaving(false)
                                                    }
                                                }}
                                            >
                                                <i className="bi bi-trash" aria-hidden="true" />
                                            </Button>
                                        </div>
                                    </div>
                                )
                            })}
                        </div>
                    )}
                </Tab>
                <Tab eventKey="ranks" title={t('acp.ranks')}>
                    {ranksError && <p className="text-danger">{ranksError}</p>}
                    <div className="d-flex justify-content-end mb-3">
                        <Button
                            type="button"
                            className="bb-accent-button"
                            onClick={() => setShowRankCreate(true)}
                        >
                            {t('rank.create')}
                        </Button>
                    </div>
                    {ranksLoading && <p className="bb-muted">{t('acp.loading')}</p>}
                    {!ranksLoading && ranks.length === 0 && (
                        <p className="bb-muted">{t('rank.empty')}</p>
                    )}
                    {!ranksLoading && ranks.length > 0 && (
                        <div className="bb-rank-list">
                            {ranks.map((rank) => (
                                <div key={rank.id} className="bb-rank-row">
                                    <div className="bb-rank-main">
                                        <span className="d-flex align-items-center gap-2">
                                            {rank.color && (
                                                <span
                                                    className="bb-rank-color"
                                                    style={{ backgroundColor: rank.color }}
                                                    aria-hidden="true"
                                                />
                                            )}
                                            <span>{rank.name}</span>
                                        </span>
                                    </div>
                                    <div className="bb-rank-actions">
                                        {rank.badge_type === 'image' && rank.badge_image_url && (
                                            <img src={rank.badge_image_url} alt="" />
                                        )}
                                        {rank.badge_type !== 'image' && rank.badge_text && (
                                            <span className="bb-rank-badge">{rank.badge_text}</span>
                                        )}
                                        <Button
                                            size="sm"
                                            variant="dark"
                                            onClick={() => {
                                                setRankEdit({
                                                    id: rank.id,
                                                    name: rank.name,
                                                    badgeType: rank.badge_type || 'text',
                                                    badgeText: rank.badge_text || '',
                                                    badgeImageUrl: rank.badge_image_url || '',
                                                    color: rank.color || '',
                                                })
                                                setRankEditImage(null)
                                                setShowRankModal(true)
                                                setRanksError('')
                                            }}
                                        >
                                            <i className="bi bi-pencil" aria-hidden="true" />
                                        </Button>
                                        <Button
                                            size="sm"
                                            variant="dark"
                                            onClick={async () => {
                                                if (!window.confirm(t('rank.delete_confirm'))) return
                                                setRankSaving(true)
                                                setRanksError('')
                                                try {
                                                    await deleteRank(rank.id)
                                                    setRanks((prev) => prev.filter((item) => item.id !== rank.id))
                                                } catch (err) {
                                                    setRanksError(err.message)
                                                } finally {
                                                    setRankSaving(false)
                                                }
                                            }}
                                        >
                                            <i className="bi bi-trash" aria-hidden="true" />
                                        </Button>
                                    </div>
                                </div>
                            ))}
                        </div>
                    )}
                </Tab>
                <Tab eventKey="attachments" title={t('acp.attachments')}>
                    {attachmentGroupsError && <p className="text-danger">{attachmentGroupsError}</p>}
                    {attachmentExtensionsError && <p className="text-danger">{attachmentExtensionsError}</p>}
                    <div className="bb-attachment-admin">
                        <div className="bb-attachment-admin-section">
                            <div className="d-flex justify-content-between align-items-center mb-3">
                                <h5 className="mb-0">{t('attachment.groups_title')}</h5>
                                <div className="d-flex align-items-center gap-2">
                                    <Button
                                        type="button"
                                        className="bb-accent-button"
                                        onClick={handleSeedAttachmentDefaults}
                                        disabled={attachmentSeedSaving}
                                    >
                                        {attachmentSeedSaving
                                            ? t('attachment.seed_in_progress')
                                            : t('attachment.seed_defaults')}
                                    </Button>
                                    <Button
                                        type="button"
                                        variant="outline-secondary"
                                        onClick={handleAttachmentGroupExpandAll}
                                    >
                                        {t('acp.expand_all')}
                                    </Button>
                                    <Button
                                        type="button"
                                        variant="outline-secondary"
                                        onClick={handleAttachmentGroupCollapseAll}
                                    >
                                        {t('acp.collapse_all')}
                                    </Button>
                                    <Button
                                        type="button"
                                        className="bb-accent-button"
                                        onClick={() => openAttachmentGroupModal()}
                                    >
                                        {t('attachment.group_create')}
                                    </Button>
                                </div>
                            </div>
                            {attachmentGroupsLoading && <p className="bb-muted">{t('acp.loading')}</p>}
                            {!attachmentGroupsLoading && attachmentGroups.length === 0 && (
                                <div className="bb-muted">
                                    <p className="mb-2">{t('attachment.group_empty')}</p>
                                    <Button
                                        type="button"
                                        className="bb-accent-button"
                                        onClick={handleSeedAttachmentDefaults}
                                        disabled={attachmentSeedSaving}
                                    >
                                        {attachmentSeedSaving
                                            ? t('attachment.seed_in_progress')
                                            : t('attachment.seed_defaults')}
                                    </Button>
                                    <div className="bb-muted mt-2">
                                        {t('attachment.seed_hint')}
                                    </div>
                                </div>
                            )}
                            {!attachmentGroupsLoading && attachmentGroups.length > 0
                                && attachmentGroups.every((group) => !group.parent_id) && (
                                <div className="bb-muted mb-3">
                                    <Button
                                        type="button"
                                        className="bb-accent-button me-2"
                                        onClick={handleSeedAttachmentDefaults}
                                        disabled={attachmentSeedSaving}
                                    >
                                        {attachmentSeedSaving
                                            ? t('attachment.seed_in_progress')
                                            : t('attachment.seed_defaults')}
                                    </Button>
                                    <Button
                                        type="button"
                                        variant="outline-secondary"
                                        onClick={handleAttachmentGroupAutoNest}
                                        disabled={attachmentSeedSaving}
                                    >
                                        {attachmentSeedSaving
                                            ? t('attachment.seed_in_progress')
                                            : t('attachment.group_auto_nest')}
                                    </Button>
                                    <div className="bb-muted mt-2">
                                        {t('attachment.group_auto_nest_hint')}
                                    </div>
                                </div>
                            )}
                            {!attachmentGroupsLoading && attachmentGroups.length > 0 && (
                                <div className="bb-attachment-tree">
                                    {renderAttachmentGroupTree(buildAttachmentGroupTree)}
                                </div>
                            )}
                        </div>
                    </div>
                </Tab>
            </Tabs>
            <Modal show={showModal} onHide={handleReset} centered size="lg">
                <Modal.Header closeButton closeVariant="white">
                    <Modal.Title>
                        {selectedId
                            ? form.type === 'category'
                                ? t('acp.forums_edit_category_title')
                                : t('acp.forums_edit_forum_title')
                            : createType === 'category'
                                ? t('acp.forums_create_category_title')
                                : createType === 'forum'
                                    ? t('acp.forums_create_forum_title')
                                    : t('acp.forums_create_title')}
                    </Modal.Title>
                </Modal.Header>
                <Modal.Body>
                    <p className="bb-muted">
                        {selectedId
                            ? form.type === 'category'
                                ? t('acp.forums_edit_category_hint')
                                : t('acp.forums_edit_forum_hint')
                            : createType === 'category'
                                ? t('acp.forums_create_category_hint')
                                : createType === 'forum'
                                    ? t('acp.forums_create_forum_hint')
                                    : t('acp.forums_form_hint')}
                    </p>
                    <Form onSubmit={handleSubmit}>
                        <Form.Group className="mb-3">
                            <Form.Label>{t('form.title')}</Form.Label>
                            <Form.Control
                                type="text"
                                value={form.name}
                                onChange={(event) => setForm({ ...form, name: event.target.value })}
                                required
                            />
                        </Form.Group>
                        <Form.Group className="mb-3">
                            <Form.Label>{t('form.description')}</Form.Label>
                            <Form.Control
                                as="textarea"
                                rows={3}
                                value={form.description}
                                onChange={(event) => setForm({ ...form, description: event.target.value })}
                            />
                        </Form.Group>
                        {selectedId && (
                            <Form.Group className="mb-3">
                                <Form.Label>{t('acp.forums_type')}</Form.Label>
                                <Form.Select
                                    value={form.type}
                                    onChange={(event) => setForm({ ...form, type: event.target.value })}
                                >
                                    <option value="category">{t('forum.type_category')}</option>
                                    <option value="forum">{t('forum.type_forum')}</option>
                                </Form.Select>
                            </Form.Group>
                        )}
                        <Form.Group className="mb-3">
                            <Form.Label>{t('acp.forums_parent')}</Form.Label>
                            <Form.Select
                                value={form.parentId}
                                onChange={(event) => setForm({ ...form, parentId: event.target.value })}
                            >
                                <option value="" disabled={form.type === 'forum'}>
                                    {t('acp.forums_parent_root')}
                                </option>
                                {categoryOptions
                                    .filter((option) => String(option.id) !== String(selectedId))
                                    .map((option) => (
                                        <option key={option.id} value={option.id}>
                                            {option.name}
                                        </option>
                                    ))}
                            </Form.Select>
                        </Form.Group>
                        <div className="d-flex gap-2 justify-content-between">
                            <Button type="button" variant="outline-secondary" onClick={handleReset}>
                                {t('acp.cancel')}
                            </Button>
                            <Button type="submit" className="bb-accent-button">
                                {selectedId ? t('acp.save') : t('acp.create')}
                            </Button>
                        </div>
                    </Form>
                </Modal.Body>
            </Modal>
            <Modal
                show={showUserModal}
                onHide={() => setShowUserModal(false)}
                centered
            >
                <Modal.Header closeButton>
                    <Modal.Title>{t('user.edit_title')}</Modal.Title>
                </Modal.Header>
                <Modal.Body>
                    {usersError && <p className="text-danger">{usersError}</p>}
                    <Form
                        onSubmit={async (event) => {
                            event.preventDefault()
                            if ((userForm.roles || []).includes('ROLE_FOUNDER') && !canManageFounder) {
                                setUsersError(t('user.founder_locked'))
                                return
                            }
                            setUserSaving(true)
                            setUsersError('')
                            try {
                                const payload = {
                                    name: userForm.name,
                                    email: userForm.email,
                                    rank_id: userForm.rankId ? Number(userForm.rankId) : null,
                                }
                                if (roles.length) {
                                    payload.roles = userForm.roles || []
                                }
                                const updated = await updateUser(userForm.id, payload)
                                setUsers((prev) =>
                                    prev.map((user) =>
                                        user.id === updated.id ? { ...user, ...updated } : user
                                    )
                                )
                                setShowUserModal(false)
                            } catch (err) {
                                setUsersError(err.message)
                            } finally {
                                setUserSaving(false)
                            }
                        }}
                    >
                        {(userForm.roles || []).includes('ROLE_FOUNDER') && !canManageFounder && (
                            <p className="text-danger">{t('user.founder_locked')}</p>
                        )}
                        <Form.Group className="mb-3">
                            <Form.Label>{t('form.username')}</Form.Label>
                            <Form.Control
                                value={userForm.name}
                                onChange={(event) =>
                                    setUserForm((prev) => ({ ...prev, name: event.target.value }))
                                }
                                required
                                disabled={(userForm.roles || []).includes('ROLE_FOUNDER') && !canManageFounder}
                            />
                        </Form.Group>
                        <Form.Group className="mb-3">
                            <Form.Label>{t('form.email')}</Form.Label>
                            <Form.Control
                                type="email"
                                value={userForm.email}
                                onChange={(event) =>
                                    setUserForm((prev) => ({ ...prev, email: event.target.value }))
                                }
                                required
                                disabled={(userForm.roles || []).includes('ROLE_FOUNDER') && !canManageFounder}
                            />
                        </Form.Group>
                        <Form.Group className="mb-3">
                            <Form.Label>{t('user.rank')}</Form.Label>
                            <Form.Select
                                value={userForm.rankId ?? ''}
                                onChange={(event) =>
                                    setUserForm((prev) => ({ ...prev, rankId: event.target.value }))
                                }
                                disabled={ranksLoading || ((userForm.roles || []).includes('ROLE_FOUNDER') && !canManageFounder)}
                            >
                                <option value="">{t('user.rank_unassigned')}</option>
                                {ranks.map((rank) => (
                                    <option key={rank.id} value={rank.id}>
                                        {rank.name}
                                    </option>
                                ))}
                            </Form.Select>
                        </Form.Group>
                        <Form.Group className="mb-3">
                            <Form.Label>{t('user.roles')}</Form.Label>
                            <div className="bb-multiselect" ref={roleMenuRef}>
                                <button
                                    type="button"
                                    className="bb-multiselect__control"
                                    onClick={() => setRoleMenuOpen((prev) => !prev)}
                                    disabled={!roles.length || ((userForm.roles || []).includes('ROLE_FOUNDER') && !canManageFounder)}
                                >
                                    <span className="bb-multiselect__value">
                                        {(userForm.roles || []).length === 0 && (
                                            <span className="bb-multiselect__placeholder">
                                                {t('user.roles')}
                                            </span>
                                        )}
                                        {(userForm.roles || []).map((roleName) => {
                                            const role = roles.find((item) => item.name === roleName)
                                            return (
                                                <span key={roleName} className="bb-multiselect__chip">
                                                    {role?.color && (
                                                        <span
                                                            className="bb-multiselect__chip-color"
                                                            style={{ backgroundColor: role.color }}
                                                            aria-hidden="true"
                                                        />
                                                    )}
                                                    {formatRoleLabel(roleName)}
                                                    {!(roleName === 'ROLE_FOUNDER' && !canManageFounder) && (
                                                        <span
                                                            className="bb-multiselect__chip-remove"
                                                            onClick={(event) => {
                                                                event.stopPropagation()
                                                                setUserForm((prev) => ({
                                                                    ...prev,
                                                                    roles: (prev.roles || []).filter(
                                                                        (name) => name !== roleName
                                                                    ),
                                                                }))
                                                            }}
                                                            aria-hidden="true"
                                                        >
                                                            ×
                                                        </span>
                                                    )}
                                                </span>
                                            )
                                        })}
                                    </span>
                                    <span className="bb-multiselect__caret" aria-hidden="true">
                                        <i className="bi bi-chevron-down" />
                                    </span>
                                </button>
                                {roleMenuOpen && (
                                    <div className="bb-multiselect__menu">
                                        <div className="bb-multiselect__search">
                                            <input
                                                type="text"
                                                value={roleQuery}
                                                onChange={(event) => setRoleQuery(event.target.value)}
                                                placeholder={t('user.search')}
                                            />
                                        </div>
                                        <div className="bb-multiselect__options">
                                            {filteredRoles.length === 0 && (
                                                <div className="bb-multiselect__empty">
                                                    {t('rank.empty')}
                                                </div>
                                            )}
                                            {filteredRoles.map((role) => {
                                                const isSelected = (userForm.roles || []).includes(role.name)
                                                const isFounderRole = role.name === 'ROLE_FOUNDER'
                                                const isLocked = isFounderRole && !canManageFounder
                                                return (
                                                    <button
                                                        type="button"
                                                        key={role.id}
                                                        className={`bb-multiselect__option ${isSelected ? 'is-selected' : ''}`}
                                                        onClick={() =>
                                                            setUserForm((prev) => {
                                                                if (isLocked) {
                                                                    return prev
                                                                }
                                                                const next = new Set(prev.roles || [])
                                                                if (next.has(role.name)) {
                                                                    next.delete(role.name)
                                                                } else {
                                                                    next.add(role.name)
                                                                }
                                                                return { ...prev, roles: Array.from(next) }
                                                            })
                                                        }
                                                        disabled={isLocked}
                                                    >
                                                        <span className="bb-multiselect__option-main">
                                                            {role.color && (
                                                                <span
                                                                    className="bb-multiselect__chip-color"
                                                                    style={{ backgroundColor: role.color }}
                                                                    aria-hidden="true"
                                                                />
                                                            )}
                                                            {formatRoleLabel(role.name)}
                                                        </span>
                                                        {isSelected && (
                                                            <i className="bi bi-check-lg" aria-hidden="true" />
                                                        )}
                                                    </button>
                                                )
                                            })}
                                        </div>
                                    </div>
                                )}
                            </div>
                        </Form.Group>
                        <div className="d-flex justify-content-between gap-2">
                            <Button
                                type="button"
                                variant="outline-secondary"
                                onClick={() => setShowUserModal(false)}
                                disabled={userSaving}
                            >
                                {t('acp.cancel')}
                            </Button>
                            <Button type="submit" className="bb-accent-button" variant="dark" disabled={userSaving}>
                                {userSaving ? t('form.saving') : t('acp.save')}
                            </Button>
                        </div>
                    </Form>
                </Modal.Body>
            </Modal>
            <Modal
                show={showRoleModal}
                onHide={() => setShowRoleModal(false)}
                centered
            >
                <Modal.Header closeButton>
                    <Modal.Title>{t('group.edit_title')}</Modal.Title>
                </Modal.Header>
                <Modal.Body>
                    {rolesError && <p className="text-danger">{rolesError}</p>}
                    <Form
                        onSubmit={async (event) => {
                            event.preventDefault()
                            if (!roleEdit.name.trim()) return
                            setRoleSaving(true)
                            setRolesError('')
                            try {
                                const updated = await updateRole(roleEdit.id, {
                                    name: roleEdit.name.trim(),
                                    color: roleEdit.color.trim() || null,
                                })
                                setRoles((prev) =>
                                    prev
                                        .map((item) => (item.id === updated.id ? updated : item))
                                        .sort((a, b) => a.name.localeCompare(b.name))
                                )
                                if (roleEdit.originalName && roleEdit.originalName !== updated.name) {
                                    setUsers((prev) =>
                                        prev.map((user) => ({
                                            ...user,
                                            roles: (user.roles || []).map((name) =>
                                                name === roleEdit.originalName ? updated.name : name
                                            ),
                                        }))
                                    )
                                }
                                setShowRoleModal(false)
                            } catch (err) {
                                setRolesError(err.message)
                            } finally {
                                setRoleSaving(false)
                            }
                        }}
                    >
                        <Form.Group className="mb-3">
                            <Form.Label>{t('group.name')}</Form.Label>
                            <Form.Control
                                value={roleEdit.name}
                                onChange={(event) =>
                                    setRoleEdit((prev) => ({ ...prev, name: event.target.value }))
                                }
                                disabled={roleEdit.isCore}
                                required
                            />
                        </Form.Group>
                        <Form.Group className="mb-3">
                            <Form.Label>{t('group.color')}</Form.Label>
                            <div className="d-flex align-items-center gap-2">
                                <Form.Control
                                    value={roleEdit.color}
                                    onChange={(event) =>
                                        setRoleEdit((prev) => ({ ...prev, color: event.target.value }))
                                    }
                                    placeholder={t('group.color_placeholder')}
                                />
                                <Form.Control
                                    type="color"
                                    value={roleEdit.color || '#f29b3f'}
                                    onChange={(event) =>
                                        setRoleEdit((prev) => ({ ...prev, color: event.target.value }))
                                    }
                                />
                            </div>
                        </Form.Group>
                        <div className="d-flex justify-content-between gap-2">
                            <Button
                                type="button"
                                variant="outline-secondary"
                                onClick={() => setShowRoleModal(false)}
                                disabled={roleSaving}
                            >
                                {t('acp.cancel')}
                            </Button>
                            <Button type="submit" className="bb-accent-button" variant="dark" disabled={roleSaving}>
                                {roleSaving ? t('form.saving') : t('acp.save')}
                            </Button>
                        </div>
                    </Form>
                </Modal.Body>
            </Modal>
            <Modal
                show={showRoleCreate}
                onHide={() => setShowRoleCreate(false)}
                centered
            >
                <Modal.Header closeButton>
                    <Modal.Title>{t('group.create_title')}</Modal.Title>
                </Modal.Header>
                <Modal.Body>
                    {rolesError && <p className="text-danger">{rolesError}</p>}
                    <Form onSubmit={handleCreateRole}>
                        <Form.Group>
                            <Form.Label>{t('group.name')}</Form.Label>
                            <Form.Control
                                value={roleFormName}
                                onChange={(event) => setRoleFormName(event.target.value)}
                                placeholder={t('group.name_placeholder')}
                                disabled={roleSaving}
                            />
                        </Form.Group>
                        <Form.Group className="mt-3">
                            <Form.Label>{t('group.color')}</Form.Label>
                            <div className="d-flex align-items-center gap-2">
                                <Form.Control
                                    value={roleFormColor}
                                    onChange={(event) => setRoleFormColor(event.target.value)}
                                    placeholder={t('group.color_placeholder')}
                                    disabled={roleSaving}
                                />
                                <Form.Control
                                    type="color"
                                    value={roleFormColor || '#f29b3f'}
                                    onChange={(event) => setRoleFormColor(event.target.value)}
                                    disabled={roleSaving}
                                />
                            </div>
                        </Form.Group>
                        <div className="d-flex justify-content-between mt-4">
                            <Button
                                type="submit"
                                className="bb-accent-button"
                                variant="dark"
                                disabled={roleSaving || !roleFormName.trim()}
                            >
                                {roleSaving ? t('form.saving') : t('group.create')}
                            </Button>
                        </div>
                    </Form>
                </Modal.Body>
            </Modal>
            <Modal
                show={showRankModal}
                onHide={() => setShowRankModal(false)}
                centered
            >
                <Modal.Header closeButton>
                    <Modal.Title>{t('rank.edit_title')}</Modal.Title>
                </Modal.Header>
                <Modal.Body>
                    {ranksError && <p className="text-danger">{ranksError}</p>}
                    <Form
                        onSubmit={async (event) => {
                            event.preventDefault()
                            if (!rankEdit.name.trim()) return
                            if (rankEdit.badgeType === 'text' && !rankEdit.badgeText.trim()) {
                                setRanksError(t('rank.badge_text_required'))
                                return
                            }
                            setRankSaving(true)
                            setRanksError('')
                            try {
                                const updated = await updateRank(rankEdit.id, {
                                    name: rankEdit.name.trim(),
                                    badge_type: rankEdit.badgeType,
                                    badge_text:
                                        rankEdit.badgeType === 'text'
                                            ? rankEdit.badgeText.trim() || rankEdit.name.trim()
                                            : null,
                                    color: rankEdit.color.trim() || null,
                                })
                                let next = updated
                                if (rankEdit.badgeType === 'image' && rankEditImage) {
                                    const upload = await uploadRankBadgeImage(rankEdit.id, rankEditImage)
                                    next = { ...updated, ...upload }
                                }
                                setRanks((prev) =>
                                    prev
                                        .map((item) => (item.id === next.id ? { ...item, ...next } : item))
                                        .sort((a, b) => a.name.localeCompare(b.name))
                                )
                                setShowRankModal(false)
                            } catch (err) {
                                setRanksError(err.message)
                            } finally {
                                setRankSaving(false)
                            }
                        }}
                    >
                        <Form.Group className="mb-3">
                            <Form.Label>{t('rank.name')}</Form.Label>
                            <Form.Control
                                value={rankEdit.name}
                                onChange={(event) =>
                                    setRankEdit((prev) => ({ ...prev, name: event.target.value }))
                                }
                                required
                            />
                        </Form.Group>
                        <Form.Group className="mb-3">
                            <Form.Label>{t('rank.color')}</Form.Label>
                            <div className="d-flex align-items-center gap-3 flex-wrap">
                                <Form.Check
                                    type="checkbox"
                                    id="rank-edit-color-default"
                                    label={t('rank.color_default')}
                                    checked={!rankEdit.color}
                                    onChange={(event) =>
                                        setRankEdit((prev) => ({
                                            ...prev,
                                            color: event.target.checked ? '' : prev.color || '#f29b3f',
                                        }))
                                    }
                                />
                                <div className="d-flex align-items-center gap-2">
                                    <Form.Control
                                        value={rankEdit.color}
                                        onChange={(event) =>
                                            setRankEdit((prev) => ({ ...prev, color: event.target.value }))
                                        }
                                        placeholder={t('rank.color_placeholder')}
                                        disabled={!rankEdit.color}
                                    />
                                    <Form.Control
                                        type="color"
                                        value={rankEdit.color || '#f29b3f'}
                                        onChange={(event) =>
                                            setRankEdit((prev) => ({ ...prev, color: event.target.value }))
                                        }
                                        disabled={!rankEdit.color}
                                    />
                                </div>
                            </div>
                        </Form.Group>
                        <Form.Group className="mb-3">
                            <Form.Label>{t('rank.badge_type')}</Form.Label>
                            <div className="d-flex gap-3 flex-wrap">
                                <Form.Check
                                    type="radio"
                                    id="rank-edit-badge-none"
                                    name="rankEditBadgeType"
                                    label={t('rank.badge_none')}
                                    checked={rankEdit.badgeType === 'none'}
                                    onChange={() =>
                                        setRankEdit((prev) => ({ ...prev, badgeType: 'none' }))
                                    }
                                />
                                <Form.Check
                                    type="radio"
                                    id="rank-edit-badge-text"
                                    name="rankEditBadgeType"
                                    label={t('rank.badge_text')}
                                    checked={rankEdit.badgeType === 'text'}
                                    onChange={() =>
                                        setRankEdit((prev) => ({ ...prev, badgeType: 'text' }))
                                    }
                                />
                                <Form.Check
                                    type="radio"
                                    id="rank-edit-badge-image"
                                    name="rankEditBadgeType"
                                    label={t('rank.badge_image')}
                                    checked={rankEdit.badgeType === 'image'}
                                    onChange={() =>
                                        setRankEdit((prev) => ({ ...prev, badgeType: 'image' }))
                                    }
                                />
                            </div>
                        </Form.Group>
                        {rankEdit.badgeType === 'text' && (
                            <Form.Group className="mb-3">
                                <Form.Label>{t('rank.badge_text')}</Form.Label>
                                <Form.Control
                                    value={rankEdit.badgeText}
                                    onChange={(event) =>
                                        setRankEdit((prev) => ({ ...prev, badgeText: event.target.value }))
                                    }
                                    placeholder={t('rank.badge_text_placeholder')}
                                    required
                                />
                            </Form.Group>
                        )}
                        {rankEdit.badgeType === 'image' && (
                            <Form.Group className="mb-3">
                                <Form.Label>{t('rank.badge_image')}</Form.Label>
                                {rankEdit.badgeImageUrl && !rankEditImage && (
                                    <div className="bb-rank-badge-preview">
                                        <img src={rankEdit.badgeImageUrl} alt="" />
                                    </div>
                                )}
                                <Form.Control
                                    type="file"
                                    accept="image/png,image/jpeg,image/jpg,image/gif,image/webp"
                                    onChange={(event) => setRankEditImage(event.target.files?.[0] || null)}
                                />
                            </Form.Group>
                        )}
                        <div className="d-flex justify-content-between gap-2">
                            <Button
                                type="button"
                                variant="outline-secondary"
                                onClick={() => setShowRankModal(false)}
                                disabled={rankSaving}
                            >
                                {t('acp.cancel')}
                            </Button>
                            <Button type="submit" className="bb-accent-button" variant="dark" disabled={rankSaving}>
                                {rankSaving ? t('form.saving') : t('acp.save')}
                            </Button>
                        </div>
                    </Form>
                </Modal.Body>
            </Modal>
            <Modal
                show={showRankCreate}
                onHide={() => setShowRankCreate(false)}
                centered
            >
                <Modal.Header closeButton>
                    <Modal.Title>{t('rank.create_title')}</Modal.Title>
                </Modal.Header>
                <Modal.Body>
                    {ranksError && <p className="text-danger">{ranksError}</p>}
                    <Form onSubmit={handleCreateRank}>
                        <Form.Group>
                            <Form.Label>{t('rank.name')}</Form.Label>
                            <Form.Control
                                value={rankFormName}
                                onChange={(event) => setRankFormName(event.target.value)}
                                placeholder={t('rank.name_placeholder')}
                                disabled={rankSaving}
                            />
                        </Form.Group>
                        <Form.Group className="mt-3">
                            <Form.Label>{t('rank.color')}</Form.Label>
                            <div className="d-flex align-items-center gap-3 flex-wrap">
                                <Form.Check
                                    type="checkbox"
                                    id="rank-create-color-default"
                                    label={t('rank.color_default')}
                                    checked={!rankFormColor}
                                    onChange={(event) =>
                                        setRankFormColor(event.target.checked ? '' : '#f29b3f')
                                    }
                                    disabled={rankSaving}
                                />
                                <div className="d-flex align-items-center gap-2">
                                    <Form.Control
                                        value={rankFormColor}
                                        onChange={(event) => setRankFormColor(event.target.value)}
                                        placeholder={t('rank.color_placeholder')}
                                        disabled={rankSaving || !rankFormColor}
                                    />
                                    <Form.Control
                                        type="color"
                                        value={rankFormColor || '#f29b3f'}
                                        onChange={(event) => setRankFormColor(event.target.value)}
                                        disabled={rankSaving || !rankFormColor}
                                    />
                                </div>
                            </div>
                        </Form.Group>
                        <Form.Group className="mt-3">
                            <Form.Label>{t('rank.badge_type')}</Form.Label>
                            <div className="d-flex gap-3 flex-wrap">
                                <Form.Check
                                    type="radio"
                                    id="rank-badge-none"
                                    name="rankBadgeType"
                                    label={t('rank.badge_none')}
                                    checked={rankFormType === 'none'}
                                    onChange={() => setRankFormType('none')}
                                />
                                <Form.Check
                                    type="radio"
                                    id="rank-badge-text"
                                    name="rankBadgeType"
                                    label={t('rank.badge_text')}
                                    checked={rankFormType === 'text'}
                                    onChange={() => setRankFormType('text')}
                                />
                                <Form.Check
                                    type="radio"
                                    id="rank-badge-image"
                                    name="rankBadgeType"
                                    label={t('rank.badge_image')}
                                    checked={rankFormType === 'image'}
                                    onChange={() => setRankFormType('image')}
                                />
                            </div>
                        </Form.Group>
                        {rankFormType === 'text' && (
                            <Form.Group className="mt-3">
                                <Form.Label>{t('rank.badge_text')}</Form.Label>
                                <Form.Control
                                    value={rankFormText}
                                    onChange={(event) => setRankFormText(event.target.value)}
                                    placeholder={t('rank.badge_text_placeholder')}
                                    disabled={rankSaving}
                                />
                            </Form.Group>
                        )}
                        {rankFormType === 'image' && (
                            <Form.Group className="mt-3">
                                <Form.Label>{t('rank.badge_image')}</Form.Label>
                                <Form.Control
                                    type="file"
                                    accept="image/png,image/jpeg,image/jpg,image/gif,image/webp"
                                    onChange={(event) => setRankFormImage(event.target.files?.[0] || null)}
                                    disabled={rankSaving}
                                />
                            </Form.Group>
                        )}
                        <div className="d-flex justify-content-between mt-4">
                            <Button
                                type="submit"
                                className="bb-accent-button"
                                variant="dark"
                                disabled={rankSaving || !rankFormName.trim()}
                            >
                                {rankSaving ? t('form.saving') : t('rank.create')}
                            </Button>
                        </div>
                    </Form>
                </Modal.Body>
            </Modal>
            <Modal
                show={showAttachmentGroupModal}
                onHide={() => setShowAttachmentGroupModal(false)}
                centered
            >
                <Modal.Header closeButton>
                    <Modal.Title>
                        {attachmentGroupEdit.id
                            ? t('attachment.group_edit_title')
                            : t('attachment.group_create_title')}
                    </Modal.Title>
                </Modal.Header>
                <Modal.Body>
                    {attachmentGroupsError && <p className="text-danger">{attachmentGroupsError}</p>}
                    <Form onSubmit={handleAttachmentGroupSubmit}>
                        <Form.Group className="mb-3">
                            <Form.Label>{t('attachment.group_name')}</Form.Label>
                            <Form.Control
                                value={attachmentGroupEdit.name}
                                onChange={(event) =>
                                    setAttachmentGroupEdit((prev) => ({ ...prev, name: event.target.value }))
                                }
                                required
                            />
                        </Form.Group>
                        <Form.Group className="mb-3">
                            <Form.Label>{t('attachment.group_parent')}</Form.Label>
                            <Form.Select
                                value={attachmentGroupEdit.parentId}
                                onChange={(event) =>
                                    setAttachmentGroupEdit((prev) => ({ ...prev, parentId: event.target.value }))
                                }
                            >
                                <option value="">{t('attachment.group_parent_none')}</option>
                                {attachmentGroupOptions
                                    .filter((option) => String(option.id) !== String(attachmentGroupEdit.id || ''))
                                    .map((option) => (
                                        <option key={option.id} value={option.id}>
                                            {option.label}
                                        </option>
                                    ))}
                            </Form.Select>
                        </Form.Group>
                        <Form.Group className="mb-3">
                            <Form.Label>{t('attachment.group_max_size')}</Form.Label>
                            <Form.Control
                                type="number"
                                min="1"
                                max="512000"
                                value={attachmentGroupEdit.max_size_kb}
                                onChange={(event) =>
                                    setAttachmentGroupEdit((prev) => ({
                                        ...prev,
                                        max_size_kb: event.target.value,
                                    }))
                                }
                            />
                            <Form.Text className="bb-muted">
                                {t('attachment.group_max_size_hint')}
                            </Form.Text>
                        </Form.Group>
                        <Form.Group className="mb-3">
                            <Form.Check
                                type="checkbox"
                                id="attachment-group-active"
                                label={t('attachment.group_active')}
                                checked={Boolean(attachmentGroupEdit.is_active)}
                                onChange={(event) =>
                                    setAttachmentGroupEdit((prev) => ({
                                        ...prev,
                                        is_active: event.target.checked,
                                    }))
                                }
                            />
                        </Form.Group>
                        <div className="d-flex justify-content-between gap-2">
                            <Button
                                type="button"
                                variant="outline-secondary"
                                onClick={() => setShowAttachmentGroupModal(false)}
                                disabled={attachmentGroupSaving}
                            >
                                {t('acp.cancel')}
                            </Button>
                            <Button
                                type="submit"
                                className="bb-accent-button"
                                variant="dark"
                                disabled={attachmentGroupSaving}
                            >
                                {attachmentGroupSaving ? t('form.saving') : t('acp.save')}
                            </Button>
                        </div>
                    </Form>
                </Modal.Body>
            </Modal>
            <Modal
                show={showAttachmentExtensionModal}
                onHide={() => setShowAttachmentExtensionModal(false)}
                centered
            >
                <Modal.Header closeButton>
                    <Modal.Title>
                        {attachmentExtensionEdit ? t('attachment.extension_edit') : t('attachment.extension_add')}
                    </Modal.Title>
                </Modal.Header>
                <Modal.Body>
                    {attachmentExtensionsError && <p className="text-danger">{attachmentExtensionsError}</p>}
                    <Form onSubmit={handleAttachmentExtensionCreate}>
                        <Form.Group className="mb-3">
                            <Form.Label>{t('attachment.extension')}</Form.Label>
                            <Form.Control
                                type="text"
                                value={newAttachmentExtension.extension}
                                onChange={(event) =>
                                    setNewAttachmentExtension((prev) => ({
                                        ...prev,
                                        extension: event.target.value,
                                    }))
                                }
                                placeholder={t('attachment.extension_placeholder')}
                                ref={attachmentExtensionInputRef}
                                autoFocus
                                required
                                disabled={Boolean(attachmentExtensionEdit)}
                            />
                        </Form.Group>
                        <Form.Group className="mb-3">
                            <Form.Label>{t('attachment.allowed_mimes')}</Form.Label>
                            <Form.Control
                                type="text"
                                value={newAttachmentExtension.allowedMimes}
                                onChange={(event) =>
                                    setNewAttachmentExtension((prev) => ({
                                        ...prev,
                                        allowedMimes: event.target.value,
                                    }))
                                }
                                placeholder={t('attachment.extension_mimes_placeholder')}
                            />
                        </Form.Group>
                        <Form.Group className="mb-3">
                            <Form.Label>{t('attachment.extension_group')}</Form.Label>
                            <Form.Select
                                value={newAttachmentExtension.groupId}
                                onChange={(event) =>
                                    setNewAttachmentExtension((prev) => ({
                                        ...prev,
                                        groupId: event.target.value,
                                    }))
                                }
                            >
                                <option value="">{t('attachment.extension_unassigned')}</option>
                                {attachmentGroups.map((group) => (
                                    <option key={group.id} value={group.id}>
                                        {group.is_active
                                            ? group.name
                                            : `${group.name} (${t('attachment.inactive')})`}
                                    </option>
                                ))}
                            </Form.Select>
                        </Form.Group>
                        <div className="d-flex justify-content-between gap-2">
                            <Button
                                type="button"
                                variant="outline-secondary"
                                onClick={() => setShowAttachmentExtensionModal(false)}
                                disabled={attachmentExtensionSaving}
                            >
                                {t('acp.cancel')}
                            </Button>
                            <Button
                                type="submit"
                                className="bb-accent-button"
                                variant="dark"
                                disabled={attachmentExtensionSaving || !newAttachmentExtension.extension.trim()}
                            >
                                {attachmentExtensionSaving
                                    ? t('form.saving')
                                    : attachmentExtensionEdit
                                        ? t('acp.save')
                                        : t('attachment.extension_add')}
                            </Button>
                        </div>
                    </Form>
                </Modal.Body>
            </Modal>
            <Modal
                show={showAttachmentExtensionDelete}
                onHide={() => setShowAttachmentExtensionDelete(false)}
                centered
            >
                <Modal.Header closeButton>
                    <Modal.Title>{t('attachment.extension_delete_confirm')}</Modal.Title>
                </Modal.Header>
                <Modal.Body>
                    <p className="bb-muted">
                        {attachmentExtensionDeleteTarget?.extension}
                    </p>
                    <div className="d-flex justify-content-between gap-2">
                        <Button
                            type="button"
                            variant="outline-secondary"
                            onClick={() => setShowAttachmentExtensionDelete(false)}
                            disabled={attachmentExtensionSaving}
                        >
                            {t('acp.cancel')}
                        </Button>
                        <Button
                            type="button"
                            className="bb-accent-button"
                            variant="dark"
                            onClick={confirmAttachmentExtensionDelete}
                            disabled={attachmentExtensionSaving}
                        >
                            {attachmentExtensionSaving ? t('form.saving') : t('acp.delete')}
                        </Button>
                    </div>
                </Modal.Body>
            </Modal>
        </Container>
    )
}
