'use client';

/**
 * Funcionalidades tipológicas — listagem operacional (padrão guia-listagens).
 * @route /projetos/[id]/software/funcionalidades
 */

import React, { useCallback, useMemo, useState } from 'react';
import { useParams, usePathname, useSearchParams } from 'next/navigation';
import {
    Alert,
    Badge,
    Button,
    Form,
    Input,
    Modal,
    Select,
    Space,
    Tag,
    Tooltip,
} from 'antd';
import type { ColumnsType } from 'antd/es/table';
import { Filter, Plus, Puzzle, Save } from 'lucide-react';
import { keepPreviousData } from '@tanstack/react-query';
import { ICON_SIZE_MD, iconTokenSize } from '@/components/icons';
import ProjetoLayout from '@/components/layouts/ProjetoLayout';
import { ButtonHeaderIcon } from '@/components/ui';
import { ListPageLayout } from '@/components/layouts/ListPageLayout';
import {
    FILTROS_MODAL_TAB_KEY,
    FiltrosModalFooterPadrao,
    FiltrosModalTabsTitulo,
    ListPageCreateFloatButton,
    ListagemEmptyState,
    ListagemListaError,
    ListingActionsColumnCell,
    ListingBulkFabModal,
    ListingColumnCustomizeModal,
    ListingFiltersTab,
    ListingPageOptionsButton,
    ListingPageOptionsModal,
    ListingSavedFiltersSection,
    SavedFilterActiveTag,
    buildListingRowInteractiveProps,
    listingServerSortNoOp,
    useListingMobileScrollHint,
    useListingVisibleColumns,
    type FiltrosModalTabsTituloActiveKey,
    type ListingColumnCatalogEntry,
} from '@/components/listings';
import { TableScrollWrapper } from '@/components/tables/TableScrollWrapper';
import { LazyDataTable, LazyExportButton } from '@/components/lazy';
import { FormTextarea } from '@/components/form';
import { confirmDialog } from '@/lib/feedback/confirmDialog';
import { message } from '@/lib/feedback/message';
import { notifyApiError } from '@/lib/feedback/notifyApiError';
import {
    useWaygestFormModalProps,
    waygestFormModalFooterClassName,
} from '@/hooks/useWaygestFormModalProps';
import { useQueryCache } from '@/hooks/useQueryCache';
import { useMutationCache } from '@/hooks/useMutationCache';
import { useProjetoWriteGates } from '@/features/projetos/hooks/useProjetoWriteGates';
import { useListingFilteredRowSelection } from '@/hooks/useListingFilteredRowSelection';
import { useListingBulkActionsModal } from '@/hooks/useListingBulkActionsModal';
import { usePaginatedResponseFallback } from '@/hooks/usePaginatedResponseFallback';
import {
    listingSortColumnUi,
    useServerSideListingTableChange,
    type ServerSideSortState,
} from '@/hooks/useServerSideListingTableChange';
import { useDebouncedValue } from '@/hooks/useDebouncedValue';
import { useIsMobile } from '@/hooks/useIsMobile';
import { queryKeys } from '@/lib/cache/queryKeys';
import { API_ENDPOINTS } from '@/lib/api/endpoints';
import apiClient from '@/lib/api/client';
import { detailPageQueryErrorSubTitle } from '@/lib/utils/detailPageQueryErrorSubTitle';
import { formatDateTimePt } from '@/lib/format/formatDateTimePt';
import type { ExportColumn } from '@/lib/utils/export';
import headerIconStyles from '@/components/ui/buttons/ButtonHeaderIcon/ButtonHeaderIcon.module.scss';
import { ProjetoTipologicoEmptyState } from '@/features/projetos/projeto-tipologico-empty-state';
import {
    PRIORIDADE_LABEL,
    PRIORIDADE_OPTIONS,
    STATUS_LABEL,
    STATUS_OPTIONS,
    type ProjetoSoftwareFuncionalidade,
    type ProjetoSoftwareFuncionalidadeListResponse,
} from './types';
import {
    PROJETOS_SOFTWARE_FUNCIONALIDADES_LIST_MODULE_KEY,
    softwareFuncionalidadesFiltrosFromPayload,
    softwareFuncionalidadesFiltrosToPayload,
} from './utils/softwareFuncionalidadesFiltrosPayload';
import {
    SOFTWARE_FUNCIONALIDADES_PER_PAGE_DEFAULT,
    type SoftwareFuncionalidadesListaUrlSnapshot,
} from './utils/softwareFuncionalidadesListaFiltersUrl';
import { useSoftwareFuncionalidadesListaUrlSync } from './hooks/useSoftwareFuncionalidadesListaUrlSync';

const FORM_ID = 'projeto-software-funcionalidade-form';

const EXPORT_HELP =
    'Exporta apenas os registros visíveis nesta página (respeita filtros e paginação da listagem). Escolha o formato no passo seguinte.';

const EMPTY_ROWS: ProjetoSoftwareFuncionalidade[] = [];

const DEFAULT_SORT: Exclude<ServerSideSortState, null> = {
    columnKey: 'ordem',
    order: 'ascend',
};

const COLUMN_CATALOG: ListingColumnCatalogEntry[] = [
    { key: 'codigo', label: 'Código', ordem: 1, visivel_padrao: true },
    { key: 'nome', label: 'Nome', ordem: 2, obrigatoria: true },
    { key: 'modulo', label: 'Módulo', ordem: 3, visivel_padrao: true },
    { key: 'status', label: 'Status', ordem: 4, visivel_padrao: true },
    { key: 'prioridade', label: 'Prioridade', ordem: 5, visivel_padrao: true },
    { key: 'criticidade', label: 'Criticidade', ordem: 6, visivel_padrao: false },
    { key: 'responsavel', label: 'Responsável', ordem: 7, visivel_padrao: false },
    { key: 'versao', label: 'Versão', ordem: 8, visivel_padrao: false },
    { key: 'ordem', label: 'Ordem', ordem: 9, visivel_padrao: false },
    { key: 'created_at', label: 'Data de cadastro', ordem: 10, visivel_padrao: false },
    { key: 'updated_at', label: 'Última atualização', ordem: 11, visivel_padrao: false },
];

type ModuloOpt = { id: number; nome: string };

function routeSegmentId(params: ReturnType<typeof useParams>): string {
    const raw = params?.id;
    if (typeof raw === 'string') return raw;
    if (Array.isArray(raw)) return raw[0] ?? '';
    return '';
}

function labelOrDash(map: Record<string, string>, value: string | null | undefined): string {
    if (!value) return '—';
    return map[value] ?? value;
}

export function ProjetoSoftwareFuncionalidadesScreen() {
    const params = useParams();
    const pathname = usePathname() ?? '';
    const searchParams = useSearchParams();
    const id = routeSegmentId(params);
    const isMobile = useIsMobile();
    const { canEditar, tooltipSemPermissao } = useProjetoWriteGates();
    const tooltipSemEdicao = !canEditar
        ? tooltipSemPermissao('editar funcionalidades')
        : undefined;
    const formModalLayout = useWaygestFormModalProps();
    const filtrosModalLayout = useWaygestFormModalProps();
    const [form] = Form.useForm();

    const [page, setPage] = useState(1);
    const [perPage, setPerPage] = useState(SOFTWARE_FUNCIONALIDADES_PER_PAGE_DEFAULT);
    const [appliedBusca, setAppliedBusca] = useState('');
    const [appliedStatus, setAppliedStatus] = useState('');
    const [appliedPrioridade, setAppliedPrioridade] = useState('');
    const [appliedModuloId, setAppliedModuloId] = useState('');
    const [tableSort, setTableSort] = useState<ServerSideSortState>(null);
    const [filtrosModalOpen, setFiltrosModalOpen] = useState(false);
    const [filtrosModalTab, setFiltrosModalTab] = useState<FiltrosModalTabsTituloActiveKey>(
        FILTROS_MODAL_TAB_KEY.filtrar,
    );
    const [draftBusca, setDraftBusca] = useState('');
    const [draftStatus, setDraftStatus] = useState('');
    const [draftPrioridade, setDraftPrioridade] = useState('');
    const [draftModuloId, setDraftModuloId] = useState('');
    const [modalOpen, setModalOpen] = useState(false);
    const [editing, setEditing] = useState<ProjetoSoftwareFuncionalidade | null>(null);
    const [opcoesItem, setOpcoesItem] = useState<ProjetoSoftwareFuncionalidade | null>(null);
    const [listaMaisOpcoesOpen, setListaMaisOpcoesOpen] = useState(false);
    const [colunasVisiveisModalOpen, setColunasVisiveisModalOpen] = useState(false);
    const [filtroSalvoAtivo, setFiltroSalvoAtivo] = useState<string | null>(null);
    const [bulkBusy, setBulkBusy] = useState(false);

    const debouncedBusca = useDebouncedValue(appliedBusca, 320);
    const { visibleKeys, columnOrder, setVisibleKeys } = useListingVisibleColumns(
        PROJETOS_SOFTWARE_FUNCIONALIDADES_LIST_MODULE_KEY,
        COLUMN_CATALOG,
    );

    const snapshot: SoftwareFuncionalidadesListaUrlSnapshot = useMemo(
        () => ({
            page,
            perPage,
            busca: appliedBusca,
            status: appliedStatus,
            prioridade: appliedPrioridade,
            projeto_modulo_id: appliedModuloId,
            tableSort,
        }),
        [page, perPage, appliedBusca, appliedStatus, appliedPrioridade, appliedModuloId, tableSort],
    );

    const onHydrateFromUrl = useCallback((values: SoftwareFuncionalidadesListaUrlSnapshot) => {
        setPage(values.page);
        setPerPage(values.perPage);
        setAppliedBusca(values.busca);
        setAppliedStatus(values.status);
        setAppliedPrioridade(values.prioridade);
        setAppliedModuloId(values.projeto_modulo_id);
        setTableSort(values.tableSort);
        setFiltroSalvoAtivo(null);
    }, []);

    useSoftwareFuncionalidadesListaUrlSync({
        pathname,
        searchParams,
        snapshot,
        onHydrateFromUrl,
    });

    const apiSortBy = tableSort?.columnKey ?? DEFAULT_SORT.columnKey;
    const apiSortDir = (tableSort?.order ?? DEFAULT_SORT.order) === 'descend' ? 'desc' : 'asc';

    const listParams = useMemo(
        () => ({
            page,
            per_page: perPage,
            ...(debouncedBusca.trim() ? { busca: debouncedBusca.trim() } : {}),
            ...(appliedStatus ? { status: appliedStatus } : {}),
            ...(appliedPrioridade ? { prioridade: appliedPrioridade } : {}),
            ...(appliedModuloId ? { projeto_modulo_id: appliedModuloId } : {}),
            sort_by: apiSortBy,
            sort_direction: apiSortDir,
        }),
        [
            page,
            perPage,
            debouncedBusca,
            appliedStatus,
            appliedPrioridade,
            appliedModuloId,
            apiSortBy,
            apiSortDir,
        ],
    );

    const {
        data: listResponse,
        isLoading,
        isFetching,
        isError,
        error: queryError,
        refetch,
    } = useQueryCache<ProjetoSoftwareFuncionalidadeListResponse>({
        queryKey: queryKeys.projetos.funcionalidadesList(id, listParams),
        endpoint: API_ENDPOINTS.projetos.funcionalidades.index(id),
        params: listParams,
        enabled: !!id,
        staleTime: 60_000,
        gcTime: 5 * 60_000,
        placeholderData: keepPreviousData,
    });

    const { data: modulosData } = useQueryCache<{ data?: ModuloOpt[] } | ModuloOpt[]>({
        queryKey: queryKeys.projetos.modulosList(id, { per_page: 100 }),
        endpoint: API_ENDPOINTS.projetos.modulos.index(id),
        params: { per_page: 100 },
        enabled: !!id,
        staleTime: 60_000,
    });

    const paginatedData = usePaginatedResponseFallback<ProjetoSoftwareFuncionalidade>(
        listResponse,
        perPage,
        EMPTY_ROWS,
    );
    const listRows = paginatedData.data;
    const sortColumnUi = listingSortColumnUi(tableSort, DEFAULT_SORT);
    const handleTableChange = useServerSideListingTableChange({
        sortState: tableSort,
        setSortState: setTableSort,
        setPage,
        setPerPage,
    });

    const modulos = useMemo(() => {
        if (Array.isArray(modulosData)) return modulosData;
        return modulosData?.data ?? [];
    }, [modulosData]);

    const { rowSelection, selectedRowKeys, clearSelection } = useListingFilteredRowSelection(
        listRows,
        listRows.map((r: any) => r.id),
        bulkBusy,
        { serverPaginated: true },
    );

    const selectedIds = useMemo(
        () => selectedRowKeys.map((k) => Number(k)).filter((n) => Number.isFinite(n)),
        [selectedRowKeys],
    );

    const {
        modalOpen: modalAcoesMassaOpen,
        openModal: openModalAcoesMassa,
        closeModal: closeModalAcoesMassa,
        scheduleAfterClose: scheduleAfterMassModalClose,
    } = useListingBulkActionsModal({ selectedCount: selectedIds.length });

    const openCreate = useCallback(() => {
        if (!canEditar) {
            message.warning(tooltipSemEdicao || 'Sem permissão para cadastrar funcionalidades');
            return;
        }
        setEditing(null);
        form.resetFields();
        form.setFieldsValue({ status: 'ativo' });
        setModalOpen(true);
        setOpcoesItem(null);
    }, [canEditar, form, tooltipSemEdicao]);

    const openEdit = useCallback(
        (row: ProjetoSoftwareFuncionalidade) => {
            setEditing(row);
            form.setFieldsValue({
                codigo: row.codigo ?? '',
                nome: row.nome,
                projeto_modulo_id: row.projeto_modulo_id ?? undefined,
                descricao: row.descricao ?? '',
                status: row.status ?? 'ativo',
                prioridade: row.prioridade ?? undefined,
                criticidade: row.criticidade ?? undefined,
                responsavel: row.responsavel ?? '',
                versao: row.versao ?? '',
                observacoes: row.observacoes ?? '',
            });
            setModalOpen(true);
            setOpcoesItem(null);
        },
        [form],
    );

    const handleDelete = useCallback(
        (row: ProjetoSoftwareFuncionalidade) => {
            confirmDialog({
                title: 'Excluir funcionalidade?',
                content: `Remover “${row.nome}”? Esta ação não pode ser desfeita.`,
                okText: 'Excluir',
                okType: 'danger',
                cancelText: 'Cancelar',
                onOk: async () => {
                    try {
                        await apiClient.delete(
                            API_ENDPOINTS.projetos.funcionalidades.destroy(id, row.id),
                        );
                        message.success('Funcionalidade excluída.');
                        setOpcoesItem(null);
                        clearSelection();
                        void refetch();
                    } catch (error) {
                        notifyApiError(error, 'Erro ao excluir.', 'funcionalidades');
                    }
                },
            });
        },
        [id, refetch, clearSelection],
    );

    const execBulkExcluir = useCallback(async () => {
        if (selectedIds.length === 0) return;
        setBulkBusy(true);
        try {
            const results = await Promise.allSettled(
                selectedIds.map((rowId) =>
                    apiClient.delete(API_ENDPOINTS.projetos.funcionalidades.destroy(id, rowId)),
                ),
            );
            const ok = results.filter((r: any) => r.status === 'fulfilled').length;
            const fail = results.length - ok;
            clearSelection();
            await refetch();
            if (ok > 0 && fail === 0) {
                message.success(
                    ok === 1 ? 'Funcionalidade excluída.' : `${ok} funcionalidades excluídas.`,
                );
                return;
            }
            if (ok > 0 && fail > 0) {
                message.warning(`${ok} excluída(s), ${fail} falharam.`);
                return;
            }
            message.error('Não foi possível excluir as funcionalidades selecionadas.');
        } finally {
            setBulkBusy(false);
        }
    }, [selectedIds, id, clearSelection, refetch]);

    const saveMutation = useMutationCache({
        endpoint: editing
            ? API_ENDPOINTS.projetos.funcionalidades.update(id, editing.id)
            : API_ENDPOINTS.projetos.funcionalidades.store(id),
        method: editing ? 'PUT' : 'POST',
        invalidateQueries: [
            queryKeys.projetos.funcionalidades(id),
            queryKeys.projetos.documentacaoHealth(id),
        ],
        onSuccess: () => {
            message.success(editing ? 'Funcionalidade atualizada.' : 'Funcionalidade registrada.');
            setModalOpen(false);
            setEditing(null);
            form.resetFields();
            void refetch();
        },
        onError: (error: unknown) => {
            notifyApiError(error, 'Erro ao salvar a funcionalidade.', 'funcionalidades');
        },
    });

    const filtrosAtivosCount =
        (appliedBusca.trim() ? 1 : 0) +
        (appliedStatus ? 1 : 0) +
        (appliedPrioridade ? 1 : 0) +
        (appliedModuloId ? 1 : 0);
    const filtrosComAlgumAtivo = filtrosAtivosCount > 0;

    const abrirModalFiltros = () => {
        setDraftBusca(appliedBusca);
        setDraftStatus(appliedStatus);
        setDraftPrioridade(appliedPrioridade);
        setDraftModuloId(appliedModuloId);
        setFiltrosModalTab(FILTROS_MODAL_TAB_KEY.filtrar);
        setFiltrosModalOpen(true);
    };

    const aplicarFiltrosModal = () => {
        setAppliedBusca(draftBusca);
        setAppliedStatus(draftStatus);
        setAppliedPrioridade(draftPrioridade);
        setAppliedModuloId(draftModuloId);
        setPage(1);
        setFiltrosModalOpen(false);
        setFiltroSalvoAtivo(null);
    };

    const limparTodosFiltros = () => {
        setAppliedBusca('');
        setAppliedStatus('');
        setAppliedPrioridade('');
        setAppliedModuloId('');
        setDraftBusca('');
        setDraftStatus('');
        setDraftPrioridade('');
        setDraftModuloId('');
        setPage(1);
        setTableSort(null);
        setFiltroSalvoAtivo(null);
        setFiltrosModalOpen(false);
    };

    const visibleSet = useMemo(() => new Set(visibleKeys), [visibleKeys]);
    const columns = useMemo((): ColumnsType<ProjetoSoftwareFuncionalidade> => {
        const cols: ColumnsType<ProjetoSoftwareFuncionalidade> = [
            {
                key: 'opcoes',
                title: '',
                width: 48,
                fixed: 'left',
                render: (_: unknown, record) => (
                    <ListingActionsColumnCell
                        ariaLabel={`Opções da funcionalidade ${record.nome}`}
                        onOpen={(e) => {
                            e.stopPropagation();
                            setOpcoesItem(record);
                        }}
                    />
                ),
            },
        ];
        if (visibleSet.has('codigo')) {
            cols.push({
                key: 'codigo',
                dataIndex: 'codigo',
                title: 'Código',
                width: 100,
                sorter: listingServerSortNoOp,
                sortOrder: sortColumnUi.columnKey === 'codigo' ? sortColumnUi.order : undefined,
                render: (v: string | null) => v || '—',
            });
        }
        if (visibleSet.has('nome')) {
            cols.push({
                key: 'nome',
                dataIndex: 'nome',
                title: 'Nome',
                sorter: listingServerSortNoOp,
                sortOrder: sortColumnUi.columnKey === 'nome' ? sortColumnUi.order : undefined,
            });
        }
        if (visibleSet.has('modulo')) {
            cols.push({
                key: 'modulo',
                title: 'Módulo',
                render: (_: unknown, r) => r.modulo?.nome ?? '—',
            });
        }
        if (visibleSet.has('status')) {
            cols.push({
                key: 'status',
                dataIndex: 'status',
                title: 'Status',
                width: 120,
                sorter: listingServerSortNoOp,
                sortOrder: sortColumnUi.columnKey === 'status' ? sortColumnUi.order : undefined,
                render: (v: string | null) =>
                    v ? <Tag>{labelOrDash(STATUS_LABEL, v)}</Tag> : '—',
            });
        }
        if (visibleSet.has('prioridade')) {
            cols.push({
                key: 'prioridade',
                dataIndex: 'prioridade',
                title: 'Prioridade',
                width: 120,
                sorter: listingServerSortNoOp,
                sortOrder: sortColumnUi.columnKey === 'prioridade' ? sortColumnUi.order : undefined,
                render: (v: string | null) => labelOrDash(PRIORIDADE_LABEL, v),
            });
        }
        if (visibleSet.has('criticidade')) {
            cols.push({
                key: 'criticidade',
                dataIndex: 'criticidade',
                title: 'Criticidade',
                width: 120,
                sorter: listingServerSortNoOp,
                sortOrder:
                    sortColumnUi.columnKey === 'criticidade' ? sortColumnUi.order : undefined,
                render: (v: string | null) => labelOrDash(PRIORIDADE_LABEL, v),
            });
        }
        if (visibleSet.has('responsavel')) {
            cols.push({
                key: 'responsavel',
                dataIndex: 'responsavel',
                title: 'Responsável',
                sorter: listingServerSortNoOp,
                sortOrder:
                    sortColumnUi.columnKey === 'responsavel' ? sortColumnUi.order : undefined,
                render: (v: string | null) => v || '—',
            });
        }
        if (visibleSet.has('versao')) {
            cols.push({
                key: 'versao',
                dataIndex: 'versao',
                title: 'Versão',
                width: 100,
                sorter: listingServerSortNoOp,
                sortOrder: sortColumnUi.columnKey === 'versao' ? sortColumnUi.order : undefined,
                render: (v: string | null) => v || '—',
            });
        }
        if (visibleSet.has('ordem')) {
            cols.push({
                key: 'ordem',
                dataIndex: 'ordem',
                title: 'Ordem',
                width: 90,
                align: 'right',
                sorter: listingServerSortNoOp,
                sortOrder: sortColumnUi.columnKey === 'ordem' ? sortColumnUi.order : undefined,
                render: (v: number | null) => (v != null ? v : '—'),
            });
        }
        if (visibleSet.has('created_at')) {
            cols.push({
                key: 'created_at',
                dataIndex: 'created_at',
                title: 'Data de cadastro',
                sorter: listingServerSortNoOp,
                sortOrder: sortColumnUi.columnKey === 'created_at' ? sortColumnUi.order : undefined,
                render: (iso: string | null | undefined) => (iso ? formatDateTimePt(iso) : '—'),
            });
        }
        if (visibleSet.has('updated_at')) {
            cols.push({
                key: 'updated_at',
                dataIndex: 'updated_at',
                title: 'Última atualização',
                sorter: listingServerSortNoOp,
                sortOrder: sortColumnUi.columnKey === 'updated_at' ? sortColumnUi.order : undefined,
                render: (iso: string | null | undefined) => (iso ? formatDateTimePt(iso) : '—'),
            });
        }
        return cols;
    }, [visibleSet, sortColumnUi]);

    const exportColumns: ExportColumn[] = [
        { key: 'codigo', label: 'Código' },
        { key: 'nome', label: 'Nome' },
        { key: 'status', label: 'Status' },
        { key: 'prioridade', label: 'Prioridade' },
        { key: 'responsavel', label: 'Responsável' },
    ];

    const exportRows = useMemo(
        () =>
            listRows.map((r: any) => ({
                codigo: r.codigo ?? '',
                nome: r.nome,
                status: labelOrDash(STATUS_LABEL, r.status),
                prioridade: labelOrDash(PRIORIDADE_LABEL, r.prioridade),
                responsavel: r.responsavel ?? '',
            })),
        [listRows],
    );

    const total = paginatedData.meta?.total ?? listRows.length;
    const showEmpty = !isLoading && !isError && total === 0;
    const tabelaScrollHint = useListingMobileScrollHint(
        'Deslize horizontalmente para ver todas as colunas.',
    );

    if (!id) return null;

    const listingToolbar = (
        <Space wrap size={8} align="center">
            <ListingPageOptionsButton
                data-testid="software-funcionalidades-lista-mais-opcoes"
                expanded={listaMaisOpcoesOpen}
                onClick={() => setListaMaisOpcoesOpen(true)}
            />
            <Tooltip
                title={
                    filtrosComAlgumAtivo
                        ? 'Há filtros ativos — abra para alterar busca, status, prioridade ou módulo.'
                        : 'Filtrar funcionalidades'
                }
            >
                <span style={{ display: 'inline-block' }}>
                    <Badge dot={filtrosComAlgumAtivo} color="geekblue">
                        <ButtonHeaderIcon
                            icon={<Filter size={ICON_SIZE_MD} aria-hidden />}
                            aria-label="Abrir filtros"
                            data-testid="software-funcionalidades-abrir-filtros"
                            title={
                                filtrosAtivosCount > 0
                                    ? `Filtros (${filtrosAtivosCount})`
                                    : 'Filtros'
                            }
                            onClick={abrirModalFiltros}
                            className={headerIconStyles.btnHeaderIcon}
                        />
                    </Badge>
                </span>
            </Tooltip>
            <Tooltip title={EXPORT_HELP}>
                <span style={{ display: 'inline-block' }} data-testid="software-funcionalidades-exportar">
                    <LazyExportButton
                        data={exportRows as unknown as Record<string, unknown>[]}
                        columns={exportColumns}
                        filename={`funcionalidades-projeto-${id}-pagina-${page}`}
                        title="Exportar"
                        iconOnly
                        size="large"
                        exportMenuMode="modal"
                        helpTooltip={EXPORT_HELP}
                        className={headerIconStyles.btnHeaderIcon}
                    />
                </span>
            </Tooltip>
        </Space>
    );

    return (
        <ProjetoLayout
            projetoId={id}
            pageTitle="Funcionalidades"
            showPageTitleIcon={false}
            titleSection="Produto"
            breadcrumbItems={[
                { title: 'Projeto', path: `/projetos/${id}` },
                { title: 'Produto', path: `/projetos/${id}/software/funcionalidades` },
                { title: 'Funcionalidades' },
            ]}
            headerAction={!isMobile ? listingToolbar : undefined}
            data-testid="projeto-funcionalidades"
        >
            <ListPageLayout
                suppressPageHeader
                header={{ title: '' }}
                mobileInlineActions={isMobile ? listingToolbar : undefined}
                loading={isLoading && !listResponse}
                loadingTip="Carregando listagem…"
                onRefresh={() => void refetch()}
                refreshLoading={isFetching && !isLoading}
                mobileOnOpenFilters={abrirModalFiltros}
                onResetFilters={limparTodosFiltros}
                activeFiltersCount={filtrosAtivosCount}
                content={
                    <>
                        {filtroSalvoAtivo ? (
                            <SavedFilterActiveTag nome={filtroSalvoAtivo} withLeadingBreak={false} />
                        ) : null}
                        {isError ? (
                            <ListagemListaError
                                message="Não foi possível carregar as funcionalidades"
                                description={detailPageQueryErrorSubTitle(queryError)}
                                onRetry={() => void refetch()}
                                data-testid="software-funcionalidades-lista-retry"
                            />
                        ) : null}
                        {filtrosComAlgumAtivo && !isError ? (
                            <Alert
                                type="info"
                                showIcon
                                style={{ marginBottom: 15 }}
                                message="Filtros ativos"
                                description={
                                    <Button type="link" onClick={limparTodosFiltros}>
                                        Limpar filtros
                                    </Button>
                                }
                            />
                        ) : null}
                        {showEmpty && filtrosComAlgumAtivo ? (
                            <ListagemEmptyState
                                type="warning"
                                icon={<Puzzle size={iconTokenSize.xl} aria-hidden />}
                                message="Nenhum resultado para os filtros"
                                description="Ajuste os critérios ou limpe os filtros."
                                ctaLabel="Limpar filtros"
                                onCta={limparTodosFiltros}
                                data-testid="software-funcionalidades-lista-empty-filtros"
                            />
                        ) : null}
                        {showEmpty && !filtrosComAlgumAtivo ? (
                            <ProjetoTipologicoEmptyState
                                title="Nenhuma funcionalidade estruturada"
                                domainKey="funcionalidades"
                                projetoId={id}
                                primaryAction={
                                    canEditar ? (
                                        <Button type="primary" onClick={openCreate}>
                                            Adicionar funcionalidade
                                        </Button>
                                    ) : undefined
                                }
                            />
                        ) : null}
                        {!isError && !showEmpty ? (
                            <TableScrollWrapper hint={tabelaScrollHint}>
                                <LazyDataTable
                                    ariaRegionLabel="Funcionalidades do projeto"
                                    rowKey="id"
                                    columns={columns}
                                    paginatedData={paginatedData}
                                    loading={isLoading}
                                    fetching={isFetching}
                                    showRefresh={false}
                                    onChange={handleTableChange}
                                    onPageChange={(p: number, ps?: number) => {
                                        setPage(p);
                                        if (ps) setPerPage(ps);
                                    }}
                                    scroll={{ x: 'max-content' }}
                                    rowSelection={rowSelection}
                                    onRow={(record: ProjetoSoftwareFuncionalidade) =>
                                        buildListingRowInteractiveProps(record, {
                                            onAtivate: (r) => openEdit(r),
                                            getRowSummary: (r) => r.nome,
                                            ariaLabelWithSummary: (summary) =>
                                                `Funcionalidade: ${summary}. Enter abre a edição.`,
                                            ariaLabelFallback:
                                                'Funcionalidade. Enter abre a edição.',
                                        })
                                    }
                                    autoMobileFromColumns={{
                                        testIdPrefix: 'software-funcionalidades',
                                        listHeading: 'Lista de funcionalidades',
                                        getFallbackTitle: (r) =>
                                            r.nome?.trim() ||
                                            r.codigo?.trim() ||
                                            `Funcionalidade ${r.id}`,
                                        onCardClick: openEdit,
                                        onOpenOptions: (item) => setOpcoesItem(item),
                                    }}
                                />
                            </TableScrollWrapper>
                        ) : null}
                    </>
                }
            />

            {selectedRowKeys.length > 0 ? (
                <ListingBulkFabModal
                    showFab
                    modalOpen={modalAcoesMassaOpen}
                    onOpenModal={openModalAcoesMassa}
                    onCloseModal={closeModalAcoesMassa}
                    busy={bulkBusy}
                    modalTitle="Ações em massa"
                    fabAriaLabel="Ações em massa nas funcionalidades selecionadas"
                    actions={[
                        {
                            key: 'excluir',
                            label: 'Excluir selecionados',
                            danger: true,
                            disabled: !canEditar,
                            onClick: () =>
                                scheduleAfterMassModalClose(() => {
                                    confirmDialog({
                                        title: 'Excluir funcionalidades selecionadas',
                                        content: `Excluir ${selectedIds.length} funcionalidade(s)? Esta ação não pode ser desfeita.`,
                                        okText: 'Excluir',
                                        okType: 'danger',
                                        cancelText: 'Cancelar',
                                        onOk: () => execBulkExcluir(),
                                    });
                                }),
                        },
                    ]}
                />
            ) : canEditar ? (
                <ListPageCreateFloatButton
                    icon={<Plus size={ICON_SIZE_MD} aria-hidden />}
                    onClick={openCreate}
                    aria-label="Adicionar funcionalidade"
                    tooltip="Adicionar funcionalidade"
                />
            ) : null}

            <ListingPageOptionsModal
                open={listaMaisOpcoesOpen}
                onClose={() => setListaMaisOpcoesOpen(false)}
                subtitle="Funcionalidades"
                onColunasVisiveis={() => {
                    setListaMaisOpcoesOpen(false);
                    setColunasVisiveisModalOpen(true);
                }}
                extraActions={
                    canEditar
                        ? [
                              {
                                  key: 'novo',
                                  label: 'Adicionar funcionalidade',
                                  icon: <Plus size={ICON_SIZE_MD} aria-hidden />,
                                  onClick: () => {
                                      setListaMaisOpcoesOpen(false);
                                      openCreate();
                                  },
                              },
                          ]
                        : []
                }
                data-testid="software-funcionalidades-lista-opcoes-pagina-modal"
            />

            <ListingColumnCustomizeModal
                open={colunasVisiveisModalOpen}
                onClose={() => setColunasVisiveisModalOpen(false)}
                catalog={COLUMN_CATALOG}
                value={visibleKeys}
                order={columnOrder}
                onApply={setVisibleKeys}
                data-testid="software-funcionalidades-customizar-colunas-modal"
            />

            <Modal
                {...filtrosModalLayout}
                title={
                    <FiltrosModalTabsTitulo
                        activeKey={filtrosModalTab}
                        onChange={setFiltrosModalTab}
                    />
                }
                open={filtrosModalOpen}
                onCancel={() => setFiltrosModalOpen(false)}
                footer={
                    <FiltrosModalFooterPadrao
                        onLimparTodos={limparTodosFiltros}
                        onFechar={() => setFiltrosModalOpen(false)}
                        showFiltrarPrimary={filtrosModalTab === FILTROS_MODAL_TAB_KEY.filtrar}
                        onFiltrar={aplicarFiltrosModal}
                    />
                }
                data-testid="software-funcionalidades-filtros-modal"
            >
                {filtrosModalTab === FILTROS_MODAL_TAB_KEY.filtrar ? (
                    <Form layout="vertical">
                        <Form.Item label="Busca">
                            <Input
                                allowClear
                                value={draftBusca}
                                onChange={(e) => setDraftBusca(e.target.value)}
                                placeholder="Nome, código, descrição ou responsável"
                            />
                        </Form.Item>
                        <Form.Item label="Status">
                            <Select
                                allowClear
                                placeholder="Todos"
                                value={draftStatus || undefined}
                                onChange={(v) => setDraftStatus(v ?? '')}
                                options={STATUS_OPTIONS}
                            />
                        </Form.Item>
                        <Form.Item label="Prioridade">
                            <Select
                                allowClear
                                placeholder="Todas"
                                value={draftPrioridade || undefined}
                                onChange={(v) => setDraftPrioridade(v ?? '')}
                                options={PRIORIDADE_OPTIONS}
                            />
                        </Form.Item>
                        <Form.Item label="Módulo">
                            <Select
                                allowClear
                                showSearch
                                optionFilterProp="label"
                                placeholder="Todos"
                                value={draftModuloId || undefined}
                                onChange={(v) => setDraftModuloId(v != null ? String(v) : '')}
                                options={modulos.map((m) => ({
                                    label: m.nome,
                                    value: String(m.id),
                                }))}
                            />
                        </Form.Item>
                        <ListingSavedFiltersSection
                            moduleKey={PROJETOS_SOFTWARE_FUNCIONALIDADES_LIST_MODULE_KEY}
                            enabled
                            snapshotKey={`${draftBusca}|${draftStatus}|${draftPrioridade}|${draftModuloId}`}
                            buildPayload={() =>
                                softwareFuncionalidadesFiltrosToPayload({
                                    busca: draftBusca,
                                    status: draftStatus,
                                    prioridade: draftPrioridade,
                                    projeto_modulo_id: draftModuloId,
                                })
                            }
                            dataTestIdPrefix="software-funcionalidades"
                        />
                    </Form>
                ) : (
                    <ListingFiltersTab
                        moduleKey={PROJETOS_SOFTWARE_FUNCIONALIDADES_LIST_MODULE_KEY}
                        enabled
                        onApplySaved={(payload, meta) => {
                            const next = softwareFuncionalidadesFiltrosFromPayload(payload);
                            setAppliedBusca(next.busca);
                            setAppliedStatus(next.status);
                            setAppliedPrioridade(next.prioridade);
                            setAppliedModuloId(next.projeto_modulo_id);
                            setPage(1);
                            setFiltrosModalOpen(false);
                            setFiltroSalvoAtivo(meta.nome);
                        }}
                        dataTestId="software-funcionalidades-filtros-meus-filtros-tab"
                    />
                )}
            </Modal>

            <Modal
                title={opcoesItem ? `Opções — ${opcoesItem.nome}` : 'Opções'}
                open={!!opcoesItem}
                onCancel={() => setOpcoesItem(null)}
                footer={null}
                data-testid="software-funcionalidades-row-opcoes-modal"
            >
                {opcoesItem ? (
                    <Space direction="vertical" style={{ width: '100%' }}>
                        <Button
                            block
                            disabled={!canEditar}
                            onClick={() => openEdit(opcoesItem)}
                        >
                            Editar
                        </Button>
                        <Button
                            block
                            danger
                            disabled={!canEditar}
                            onClick={() => handleDelete(opcoesItem)}
                        >
                            Excluir
                        </Button>
                    </Space>
                ) : null}
            </Modal>

            <Modal
                {...formModalLayout}
                open={modalOpen}
                title={editing ? 'Editar funcionalidade' : 'Nova funcionalidade'}
                onCancel={() => {
                    setModalOpen(false);
                    setEditing(null);
                }}
                footer={
                    <div className={waygestFormModalFooterClassName}>
                        <Button onClick={() => setModalOpen(false)}>Cancelar</Button>
                        <Tooltip title={tooltipSemEdicao}>
                            <Button
                                type="primary"
                                htmlType="submit"
                                form={FORM_ID}
                                icon={<Save size={ICON_SIZE_MD} aria-hidden />}
                                loading={saveMutation.isPending}
                                disabled={!canEditar}
                            >
                                Salvar
                            </Button>
                        </Tooltip>
                    </div>
                }
            >
                <Form
                    id={FORM_ID}
                    form={form}
                    layout="vertical"
                    onFinish={(v) => saveMutation.mutate(v)}
                    scrollToFirstError
                >
                    <Form.Item name="codigo" label="Código">
                        <Input placeholder="FN-001" />
                    </Form.Item>
                    <Form.Item
                        name="nome"
                        label="Nome"
                        rules={[{ required: true, message: 'Informe o nome' }]}
                    >
                        <Input />
                    </Form.Item>
                    <Form.Item name="projeto_modulo_id" label="Módulo">
                        <Select
                            allowClear
                            showSearch
                            optionFilterProp="label"
                            options={modulos.map((m) => ({ label: m.nome, value: m.id }))}
                        />
                    </Form.Item>
                    <Form.Item name="descricao" label="Descrição">
                        <FormTextarea rows={3} />
                    </Form.Item>
                    <Form.Item name="status" label="Status">
                        <Select options={STATUS_OPTIONS} />
                    </Form.Item>
                    <Form.Item name="prioridade" label="Prioridade">
                        <Select allowClear options={PRIORIDADE_OPTIONS} />
                    </Form.Item>
                    <Form.Item name="criticidade" label="Criticidade">
                        <Select allowClear options={PRIORIDADE_OPTIONS} />
                    </Form.Item>
                    <Form.Item name="responsavel" label="Responsável">
                        <Input />
                    </Form.Item>
                    <Form.Item name="versao" label="Versão">
                        <Input />
                    </Form.Item>
                    <Form.Item name="observacoes" label="Observações">
                        <FormTextarea rows={2} />
                    </Form.Item>
                </Form>
            </Modal>
        </ProjetoLayout>
    );
}
