'use client';

import { confirmDialog } from '@/lib/feedback/confirmDialog';

import { message } from '@/lib/feedback/message';

import React, { useState, useMemo, useCallback, useEffect } from 'react';
import dynamic from 'next/dynamic';
/**
 * Requisitos de planejamento por projeto — extraído de `app/(dashboard)/projetos/[id]/planejamento/requisitos` (FRONT-S2-02).
 *
 * @route /projetos/[id]/planejamento/requisitos
 */

import { CheckCircle2, Eye, FileText, Filter, Pencil, Sparkles, Trash2, Upload } from 'lucide-react';
import {
    Alert,
    Badge,
    Button,
    Col,
    Drawer,
    Form,
    Input,
    Modal,
    Row,
    Select,
    Space,
    Tabs,
    Tag,
    Tooltip,
    Typography,
} from 'antd';
import { usePathname, useRouter, useSearchParams } from 'next/navigation';
import { ICON_SIZE_MD, iconTokenSize } from '@/components/icons';
import { LazyDataTable } from '@/components/lazy';
import { LazyExportButton } from '@/components/lazy';
import type { ColumnsType } from 'antd/es/table';
import type { ModalOpcaoAction } from '@/components/ModalOpcoesBase';
import { useQueryCache } from '@/hooks/useQueryCache';
import { useMutationCache } from '@/hooks/useMutationCache';
import { useListingFilteredRowSelection } from '@/hooks/useListingFilteredRowSelection';
import { useResponsiveModalProps } from '@/hooks/useResponsiveModalProps';
import { useResponsiveDrawerWidth } from '@/hooks/useResponsiveDrawerWidth';
import { useWaygestFormModalProps, waygestFormModalFooterClassName } from '@/hooks/useWaygestFormModalProps';
import { queryKeys } from '@/lib/cache/queryKeys';
import { API_ENDPOINTS } from '@/lib/api/endpoints';
import apiClient from '@/lib/api/client';
import { getLaravelApiErrorMessage } from '@/lib/api/laravelApiErrorMessage';
import { notifyApiError } from '@/lib/feedback/notifyApiError';
import { listingTableVirtualScrollProps } from '@/lib/listings/listingTableVirtualScrollProps';
import { PaginatedResponse } from '@/types';
import { formatDate } from '@/lib/utils/export';
import btnHeaderStyles from '@/components/ui/buttons/ButtonHeaderIcon/ButtonHeaderIcon.module.scss';
import ProjetoLayout from '@/components/layouts/ProjetoLayout';
import MetricsGrid from '@/components/layouts/MetricsGrid';
import MetricCard from '@/components/layouts/MetricCard';
import { FormGroup } from '@/components/form';
import { ButtonHeaderIcon } from '@/components/ui';
import { ModuleRelatedLinksPanel } from '@/components/navigation/ModuleRelatedLinksPanel';
import { TableScrollWrapper } from '@/components/tables/TableScrollWrapper';
import { MobilePageActionBar } from '@/components/filters/MobilePageActionBar';
import {
    FiltrosModalFooterPadrao,
    ListagemEmptyState,
    ListagemListaError,
    ListingActionsColumnCell,
    ListingBulkFabModal,
    ListingSelectionToolbarCard,
    ListPageCreateFloatButton,
    useListingMobileScrollHint,
} from '@/components/listings';
import { useListingMobileChrome } from '@/components/mobile';
import { useProjetoWriteGates } from '@/features/projetos/hooks/useProjetoWriteGates';
import { ProjetoEntidadeImportCsvModal } from '@/features/projetos/importacao-csv';
import {
    ProjetoTipologicoSyncCtas,
    tipologicoEmptyDescription,
    TIPOLOGICO_EMPTY_DOMAIN,
} from '@/features/projetos/projeto-tipologico-empty-state';
import { ProjetoRastreabilidadePanel } from '@/features/projetos/planejamento/rastreabilidade';
import { useScCoberturaRequisitoTeste } from '@/features/projetos/sistema-customizado-prontidao';
import type { Requisito, RequisitosSugerirComIaResponse, RequisitoSugestaoIa } from './types';

type RequisitosAba = 'lista' | 'rastreabilidade';

const ModalOpcoesRequisito = dynamic(
    () => import('./ModalOpcoesRequisito').then((m) => m.ModalOpcoesRequisito),
    { ssr: false },
);

const ModalSugerirRequisitosIa = dynamic(
    () => import('./ModalSugerirRequisitosIa').then((m) => m.ModalSugerirRequisitosIa),
    { ssr: false },
);

const BULK_CONFIRM_OPEN_DELAY_MS = 120;

export interface ProjetoPlanejamentoRequisitosScreenProps {
    projetoId: string;
}

const PLANEJAMENTO_REQUISITOS_RELATED_SURFACE = 'projetos.planejamento.requisitos.list' as const;

const REQUISITOS_SORT_OPTIONS = [
    { value: 'codigo:ascend', label: 'Código (A→Z)' },
    { value: 'codigo:descend', label: 'Código (Z→A)' },
    { value: 'titulo:ascend', label: 'Título (A→Z)' },
    { value: 'titulo:descend', label: 'Título (Z→A)' },
    { value: 'status:ascend', label: 'Status (A→Z)' },
    { value: 'status:descend', label: 'Status (Z→A)' },
    { value: 'prioridade:ascend', label: 'Prioridade (A→Z)' },
    { value: 'prioridade:descend', label: 'Prioridade (Z→A)' },
] as const;

type RequisitosSortKey = 'codigo' | 'titulo' | 'status' | 'prioridade';
type RequisitosSortOrder = 'ascend' | 'descend';

function parseRequisitosSortValue(raw: string | undefined): {
    key: RequisitosSortKey;
    order: RequisitosSortOrder;
} {
    const [keyRaw, orderRaw] = (raw ?? 'codigo:ascend').split(':');
    const key = (['codigo', 'titulo', 'status', 'prioridade'] as const).includes(
        keyRaw as RequisitosSortKey,
    )
        ? (keyRaw as RequisitosSortKey)
        : 'codigo';
    const order: RequisitosSortOrder = orderRaw === 'descend' ? 'descend' : 'ascend';
    return { key, order };
}

export function ProjetoPlanejamentoRequisitosScreen({ projetoId }: ProjetoPlanejamentoRequisitosScreenProps) {
    const { canEditar } = useProjetoWriteGates();
    const { isMobile } = useListingMobileChrome();
    const detalheDrawerWidth = useResponsiveDrawerWidth({ desktopWidth: 560 });
    const router = useRouter();
    const pathname = usePathname() ?? '';
    const searchParams = useSearchParams();
    const {
        data: coberturaData,
        isForbidden: coberturaForbidden,
    } = useScCoberturaRequisitoTeste({ projetoId });
    const cobertura = coberturaData?.cobertura_requisito_teste;

    const abaFromUrl: RequisitosAba =
        searchParams.get('aba') === 'rastreabilidade' ? 'rastreabilidade' : 'lista';
    const [abaAtiva, setAbaAtivaState] = useState<RequisitosAba>(abaFromUrl);

    useEffect(() => {
        setAbaAtivaState(abaFromUrl);
    }, [abaFromUrl]);

    const setAbaAtiva = useCallback(
        (aba: RequisitosAba) => {
            setAbaAtivaState(aba);
            const next = new URLSearchParams(searchParams.toString());
            if (aba === 'rastreabilidade') {
                next.set('aba', 'rastreabilidade');
            } else {
                next.delete('aba');
            }
            const qs = next.toString();
            router.replace(qs ? `${pathname}?${qs}` : pathname, { scroll: false });
        },
        [pathname, router, searchParams],
    );

    const [currentPage, setCurrentPage] = useState(1);
    const [importCsvOpen, setImportCsvOpen] = useState(false);
    const [pageSize, setPageSize] = useState(10);
    const [searchValue, setSearchValue] = useState('');
    const [searchInput, setSearchInput] = useState('');
    const [statusFilter, setStatusFilter] = useState<number | undefined>(undefined);
    const [tipoFilter, setTipoFilter] = useState<number | undefined>(undefined);
    const [prioridadeFilter, setPrioridadeFilter] = useState<number | undefined>(undefined);
    const [fonteFilter, setFonteFilter] = useState<number | undefined>(undefined);
    const [filtrosModalOpen, setFiltrosModalOpen] = useState(false);
    const [draftStatusFilter, setDraftStatusFilter] = useState<number | undefined>(undefined);
    const [draftTipoFilter, setDraftTipoFilter] = useState<number | undefined>(undefined);
    const [draftPrioridadeFilter, setDraftPrioridadeFilter] = useState<number | undefined>(undefined);
    const [draftFonteFilter, setDraftFonteFilter] = useState<number | undefined>(undefined);
    const [draftSearchInput, setDraftSearchInput] = useState('');
    const [listSortValue, setListSortValue] = useState<string>('codigo:ascend');
    const [draftListSortValue, setDraftListSortValue] = useState<string>('codigo:ascend');
    const [opcoesItem, setOpcoesItem] = useState<Requisito | null>(null);
    const [modalOpen, setModalOpen] = useState(false);
    const [editingItem, setEditingItem] = useState<Requisito | null>(null);
    const [drawerVisible, setDrawerVisible] = useState(false);
    const [selectedItem, setSelectedItem] = useState<Requisito | null>(null);
    const [iaModalOpen, setIaModalOpen] = useState(false);
    const [iaSugestoes, setIaSugestoes] = useState<RequisitoSugestaoIa[]>([]);
    const [iaError, setIaError] = useState<string | null>(null);
    const [modalAcoesMassaOpen, setModalAcoesMassaOpen] = useState(false);
    const [bulkBusy, setBulkBusy] = useState(false);
    const [form] = Form.useForm();
    const formModalLayout = useWaygestFormModalProps();
    const filtrosModalLayout = useResponsiveModalProps();

    const { data: statusData } = useQueryCache<{
        data: Array<{ id: number; nome: string; codigo: string }>;
    }>({
        queryKey: queryKeys.requisitoCatalogoStatus.lists(),
        endpoint: API_ENDPOINTS.requisitosCatalogos.status.index,
        staleTime: 30 * 60 * 1000,
        gcTime: 60 * 60 * 1000});

    const { data: tiposData } = useQueryCache<{
        data: Array<{ id: number; nome: string; codigo: string }>;
    }>({
        queryKey: queryKeys.requisitoCatalogoTipos.lists(),
        endpoint: API_ENDPOINTS.requisitosCatalogos.tipos.index,
        staleTime: 30 * 60 * 1000,
        gcTime: 60 * 60 * 1000});

    const { data: prioridadesData } = useQueryCache<{
        data: Array<{ id: number; nome: string; codigo: string }>;
    }>({
        queryKey: queryKeys.requisitoCatalogoPrioridades.lists(),
        endpoint: API_ENDPOINTS.requisitosCatalogos.prioridades.index,
        staleTime: 30 * 60 * 1000,
        gcTime: 60 * 60 * 1000});

    const { data: fontesData } = useQueryCache<{
        data: Array<{ id: number; nome: string; codigo: string }>;
    }>({
        queryKey: queryKeys.requisitoCatalogoFontes.lists(),
        endpoint: API_ENDPOINTS.requisitosCatalogos.fontes.index,
        staleTime: 30 * 60 * 1000,
        gcTime: 60 * 60 * 1000});

    const statusOptions =
        statusData?.data?.map((status) => ({
            label: status.nome,
            value: status.id})) || [];

    const tipoOptions =
        tiposData?.data?.map((tipo) => ({
            label: tipo.nome,
            value: tipo.id})) || [];

    const prioridadeOptions =
        prioridadesData?.data?.map((prioridade) => ({
            label: prioridade.nome,
            value: prioridade.id})) || [];

    const fonteOptions =
        fontesData?.data?.map((fonte) => ({
            label: fonte.nome,
            value: fonte.id})) || [];

    const {
        data: requisitosRaw,
        isLoading,
        isError,
        error: queryError,
        refetch,
    } = useQueryCache<PaginatedResponse<Requisito> | Requisito[]>({
        queryKey: queryKeys.desenvolvimento.requisitos.list({
            projeto_id: projetoId,
            page: currentPage,
            pageSize,
            search: searchValue,
            status: statusFilter,
            tipo: tipoFilter,
            prioridade: prioridadeFilter,
            fonte: fonteFilter}),
        endpoint: API_ENDPOINTS.desenvolvimento.requisitos.index,
        params: {
            ...(projetoId && { projeto_id: projetoId }),
            page: currentPage,
            per_page: pageSize,
            ...(searchValue && { search: searchValue }),
            ...(statusFilter && { status_id: statusFilter }),
            ...(tipoFilter && { tipo_id: tipoFilter }),
            ...(prioridadeFilter && { prioridade_id: prioridadeFilter }),
            ...(fonteFilter && { fonte_id: fonteFilter })},
        staleTime: 1 * 60 * 1000,
        gcTime: 5 * 60 * 1000,
        enabled: !!projetoId});

    /** Com `projeto_id`, a API devolve array cru; sem filtro de projeto, envelope paginado. */
    const requisitos = useMemo((): PaginatedResponse<Requisito> | undefined => {
        if (!requisitosRaw) return undefined;
        if (Array.isArray(requisitosRaw)) {
            const total = requisitosRaw.length;
            return {
                data: requisitosRaw,
                meta: {
                    current_page: 1,
                    from: total > 0 ? 1 : 0,
                    last_page: 1,
                    per_page: Math.max(total, pageSize),
                    to: total,
                    total,
                },
                links: { first: '', last: '', prev: null, next: null },
            };
        }
        const rows = requisitosRaw.data ?? [];
        return {
            ...requisitosRaw,
            data: rows,
            meta: requisitosRaw.meta ?? {
                current_page: currentPage,
                from: rows.length > 0 ? 1 : 0,
                last_page: 1,
                per_page: pageSize,
                to: rows.length,
                total: rows.length,
            },
            links: requisitosRaw.links ?? { first: '', last: '', prev: null, next: null },
        };
    }, [requisitosRaw, currentPage, pageSize]);

    const storeMutation = useMutationCache<Requisito, Record<string, unknown>>({
        endpoint: API_ENDPOINTS.desenvolvimento.requisitos.store,
        method: 'POST',
        invalidateQueries: [queryKeys.desenvolvimento.requisitos.lists()],
        onSuccess: () => {
            message.success('Requisito criado com sucesso!');
            setModalOpen(false);
            form.resetFields();
            refetch();
        },
        onError: (err: unknown) => {
            const e = err as { response?: { data?: { message?: string } } };
            message.error(e?.response?.data?.message || 'Erro ao criar requisito');
        }});

    const updateMutation = useMutationCache<Requisito, { id: number } & Record<string, unknown>>({
        endpoint: (vars) => API_ENDPOINTS.desenvolvimento.requisitos.update(vars.id),
        method: 'PUT',
        invalidateQueries: [queryKeys.desenvolvimento.requisitos.lists()],
        onSuccess: () => {
            message.success('Requisito atualizado com sucesso!');
            setModalOpen(false);
            setEditingItem(null);
            form.resetFields();
            refetch();
        },
        onError: (err: unknown) => {
            const e = err as { response?: { data?: { message?: string } } };
            message.error(e?.response?.data?.message || 'Erro ao atualizar requisito');
        }});

    const destroyMutation = useMutationCache<void, number>({
        endpoint: (id) => API_ENDPOINTS.desenvolvimento.requisitos.destroy(id),
        method: 'DELETE',
        invalidateQueries: [queryKeys.desenvolvimento.requisitos.lists()],
        onSuccess: () => {
            message.success('Requisito excluído com sucesso!');
            refetch();
        },
        onError: (err: unknown) => {
            const e = err as { response?: { data?: { message?: string } } };
            message.error(e?.response?.data?.message || 'Erro ao excluir requisito');
        }});

    const approveMutation = useMutationCache<Record<string, unknown>, number>({
        endpoint: (id) => API_ENDPOINTS.desenvolvimento.requisitos.aprovar(id),
        method: 'POST',
        invalidateQueries: [queryKeys.desenvolvimento.requisitos.lists()],
        onSuccess: () => {
            message.success('Requisito aprovado com sucesso!');
            refetch();
        },
        onError: (err: unknown) => {
            const errorMessage =
                (err as { response?: { data?: { message?: string } } })?.response?.data?.message ||
                'Erro ao aprovar requisito';
            message.error(errorMessage);
        }});

    const sugerirIaMutation = useMutationCache<RequisitosSugerirComIaResponse, Record<string, never>>({
        endpoint: API_ENDPOINTS.projetos.requisitos.sugerirComIa(projetoId),
        method: 'POST',
        onSuccess: (data) => {
            setIaSugestoes(data.sugestoes ?? []);
            setIaError(null);
        },
        onError: (error: unknown) => {
            setIaSugestoes([]);
            const msg =
                (error as { response?: { data?: { message?: string } } })?.response?.data
                    ?.message || 'Não foi possível gerar sugestões de requisitos.';
            setIaError(msg);
            notifyApiError(error, msg, 'planejamento-requisitos-ia');
        },
    });

    const aplicarSugestoesMutation = useMutationCache<
        { message?: string },
        { requisitos: RequisitoSugestaoIa[] }
    >({
        endpoint: API_ENDPOINTS.projetos.requisitos.aplicarSugestoes(projetoId),
        method: 'POST',
        invalidateQueries: [queryKeys.desenvolvimento.requisitos.lists()],
        onSuccess: (data) => {
            message.success(data.message || 'Requisitos inseridos com sucesso!');
            setIaModalOpen(false);
            setIaSugestoes([]);
            refetch();
        },
        onError: (error: unknown) => {
            notifyApiError(error, 'Erro ao inserir os requisitos selecionados.', 'planejamento-requisitos-ia');
        },
    });

    const abrirSugerirIa = () => {
        setIaModalOpen(true);
        setIaError(null);
        setIaSugestoes([]);
        sugerirIaMutation.mutate({});
    };

    const limparTodosFiltros = useCallback(() => {
        setStatusFilter(undefined);
        setTipoFilter(undefined);
        setPrioridadeFilter(undefined);
        setFonteFilter(undefined);
        setSearchValue('');
        setSearchInput('');
        setDraftStatusFilter(undefined);
        setDraftTipoFilter(undefined);
        setDraftPrioridadeFilter(undefined);
        setDraftFonteFilter(undefined);
        setDraftSearchInput('');
        setListSortValue('codigo:ascend');
        setDraftListSortValue('codigo:ascend');
        setCurrentPage(1);
    }, []);

    const handlePageChange = (page: number, size?: number) => {
        setCurrentPage(page);
        if (size) setPageSize(size);
    };

    const handleApprove = async (id: number) => {
        confirmDialog({
            title: 'Aprovar Requisito',
            content: 'Deseja realmente aprovar este requisito?',
            okText: 'Aprovar',
            okType: 'primary',
            cancelText: 'Cancelar',
            onOk: () => approveMutation.mutate(id)});
    };

    const openCreate = () => {
        setEditingItem(null);
        form.setFieldsValue({
            titulo: '',
            descricao: undefined,
            criterios_aceitacao: undefined,
            codigo: undefined,
            status_id: undefined,
            tipo_id: undefined,
            prioridade_id: undefined,
            fonte_id: undefined});
        setModalOpen(true);
    };

    const openEdit = (record: Requisito) => {
        setEditingItem(record);
        form.setFieldsValue({
            titulo: record.titulo,
            descricao: record.descricao || undefined,
            criterios_aceitacao: record.criterios_aceitacao || undefined,
            codigo: record.codigo || undefined,
            status_id: record.status_id ?? undefined,
            tipo_id: record.tipo_id ?? undefined,
            prioridade_id: record.prioridade_id ?? undefined,
            fonte_id: record.fonte_id ?? undefined});
        setModalOpen(true);
    };

    const handleSubmit = () => {
        form.validateFields().then((values) => {
            const payload: Record<string, unknown> = {
                projeto_id: Number(projetoId),
                titulo: values.titulo,
                descricao: values.descricao || null,
                criterios_aceitacao: values.criterios_aceitacao || null,
                codigo: values.codigo || null,
                status_id: values.status_id ?? null,
                tipo_id: values.tipo_id ?? null,
                prioridade_id: values.prioridade_id ?? null,
                fonte_id: values.fonte_id ?? null};
            if (editingItem) {
                updateMutation.mutate({ id: editingItem.id, ...payload });
            } else {
                storeMutation.mutate(payload);
            }
        });
    };

    const handleDelete = (item: Requisito) => {
        confirmDialog({
            title: 'Excluir requisito',
            content: `Deseja realmente excluir "${item.titulo}"?`,
            okText: 'Excluir',
            okType: 'danger',
            cancelText: 'Cancelar',
            onOk: () => destroyMutation.mutate(item.id)});
    };

    const getStatusColor = (status?: string) => {
        const colors: Record<string, string> = {
            rascunho: 'default',
            pendente: 'processing',
            aprovado: 'success',
            rejeitado: 'error'};
        return colors[status || ''] || 'default';
    };

    const getStatusLabel = (status?: string) => {
        const labels: Record<string, string> = {
            rascunho: 'Rascunho',
            pendente: 'Pendente',
            aprovado: 'Aprovado',
            rejeitado: 'Rejeitado'};
        return labels[status || ''] || status || '-';
    };

    const getPrioridadeLabel = (prioridade?: string) => {
        const labels: Record<string, string> = {
            baixa: 'Baixa',
            media: 'Média',
            alta: 'Alta',
            critica: 'Crítica',
        };
        return labels[prioridade || ''] || prioridade || '-';
    };

    const requisitosTabelaScrollHint = useListingMobileScrollHint(
        'Deslize horizontalmente para ver código, status e prioridade.',
    );

    const columns: ColumnsType<Requisito> = [
        {
            title: '',
            key: 'acoes',
            width: 52,
            align: 'center',
            fixed: 'left',
            onCell: () => ({ onClick: (e: React.MouseEvent) => e.stopPropagation() }),
            render: (_: unknown, record: Requisito) => (
                <ListingActionsColumnCell
                    ariaLabel={`Opções do requisito ${record.codigo || record.titulo}`}
                    onOpen={() => setOpcoesItem(record)}
                    data-testid={`planejamento-requisitos-opcoes-${record.id}`}
                />
            ),
        },
        {
            title: 'Código',
            dataIndex: 'codigo',
            key: 'codigo',
            width: 120,
            sorter: (a, b) =>
                String(a.codigo ?? '').localeCompare(String(b.codigo ?? ''), 'pt'),
            render: (text: string) => (text ? <Tag>{text}</Tag> : '-'),
        },
        {
            title: 'Título',
            dataIndex: 'titulo',
            key: 'titulo',
            ellipsis: true,
            sorter: (a, b) =>
                String(a.titulo ?? '').localeCompare(String(b.titulo ?? ''), 'pt'),
            render: (text: string) => <span style={{ fontWeight: 600, color: '#2c3e50' }}>{text}</span>,
        },
        {
            title: 'Status',
            dataIndex: 'status',
            key: 'status',
            width: 130,
            sorter: (a, b) => {
                const byAprov = Number(!!b.aprovado) - Number(!!a.aprovado);
                if (byAprov !== 0) return byAprov;
                return String(a.status ?? '').localeCompare(String(b.status ?? ''), 'pt');
            },
            render: (status: string, record: Requisito) => (
                <Tag color={record.aprovado ? 'success' : getStatusColor(status)}>
                    {record.aprovado ? 'Aprovado' : getStatusLabel(status)}
                </Tag>
            ),
        },
        {
            title: 'Prioridade',
            dataIndex: 'prioridade',
            key: 'prioridade',
            width: 120,
            sorter: (a, b) =>
                String(a.prioridade ?? '').localeCompare(String(b.prioridade ?? ''), 'pt'),
            render: (prioridade: string) => {
                const colors: Record<string, string> = {
                    baixa: 'default',
                    media: 'processing',
                    alta: 'warning',
                    critica: 'error',
                };
                return prioridade ? (
                    <Tag color={colors[prioridade] || 'default'}>{getPrioridadeLabel(prioridade)}</Tag>
                ) : (
                    '-'
                );
            },
        },
    ];

    const requisitosRows = requisitos?.data ?? [];

    const requisitosRowsOrdenados = useMemo(() => {
        const { key, order } = parseRequisitosSortValue(listSortValue);
        const sorted = [...requisitosRows];
        const dir = order === 'descend' ? -1 : 1;
        sorted.sort((a, b) => {
            if (key === 'status') {
                const byAprov = (Number(!!a.aprovado) - Number(!!b.aprovado)) * dir;
                if (byAprov !== 0) return byAprov;
                return (
                    String(a.status ?? '').localeCompare(String(b.status ?? ''), 'pt') * dir
                );
            }
            return (
                String(a[key] ?? '').localeCompare(String(b[key] ?? ''), 'pt', {
                    sensitivity: 'base',
                }) * dir
            );
        });
        return sorted;
    }, [requisitosRows, listSortValue]);

    const {
        selectedRowKeys,
        clearSelection,
        mergeSelectCurrentPageIds,
        rowSelection,
    } = useListingFilteredRowSelection(
        requisitosRowsOrdenados,
        requisitosRowsOrdenados.map((r: any) => r.id),
        bulkBusy || !canEditar,
        {
            serverPaginated: true,
            selectAllAriaLabel: 'Selecionar todos os requisitos desta página',
            getRowCheckboxAriaLabel: (record) =>
                `Selecionar requisito ${record.codigo || record.titulo || record.id}`,
            mobileSelectToggleTestId: 'planejamento-requisitos-selecao-mobile-toggle',
        },
    );

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

    const selectedPendentesAprovacao = useMemo(
        () =>
            requisitosRows.filter(
                (r) => selectedIds.includes(r.id) && !r.aprovado,
            ),
        [requisitosRows, selectedIds],
    );

    useEffect(() => {
        clearSelection();
    }, [
        statusFilter,
        tipoFilter,
        prioridadeFilter,
        fonteFilter,
        searchValue,
        clearSelection,
    ]);

    useEffect(() => {
        if (selectedRowKeys.length === 0) {
            setModalAcoesMassaOpen(false);
        }
    }, [selectedRowKeys.length]);

    const execBulkAprovar = useCallback(async () => {
        const ids = selectedPendentesAprovacao.map((r: any) => r.id);
        if (ids.length === 0) {
            message.warning('Nenhum dos selecionados está pendente de aprovação.');
            return;
        }
        setBulkBusy(true);
        try {
            await apiClient.post(API_ENDPOINTS.desenvolvimento.requisitos.aprovarLote, {
                requisito_ids: ids,
            });
            clearSelection();
            setOpcoesItem(null);
            await refetch();
            message.success(
                ids.length === 1
                    ? 'Requisito aprovado com sucesso.'
                    : `${ids.length} requisitos aprovados com sucesso.`,
            );
        } catch (err: unknown) {
            message.error(getLaravelApiErrorMessage(err, 'Erro ao aprovar os requisitos selecionados.'));
        } finally {
            setBulkBusy(false);
        }
    }, [selectedPendentesAprovacao, clearSelection, refetch]);

    const execBulkExcluir = useCallback(async () => {
        if (selectedIds.length === 0) return;
        setBulkBusy(true);
        try {
            const results = await Promise.allSettled(
                selectedIds.map((id) =>
                    apiClient.delete(API_ENDPOINTS.desenvolvimento.requisitos.destroy(id)),
                ),
            );
            const ok = results.filter((r: any) => r.status === 'fulfilled').length;
            const fail = results.length - ok;
            clearSelection();
            setOpcoesItem(null);
            await refetch();
            if (ok > 0 && fail === 0) {
                message.success(ok === 1 ? 'Requisito excluído.' : `${ok} requisitos excluídos.`);
                return;
            }
            if (ok > 0 && fail > 0) {
                message.warning(`${ok} excluído(s), ${fail} falharam (permissão ou vínculos).`);
                return;
            }
            message.error('Não foi possível excluir os requisitos selecionados.');
        } finally {
            setBulkBusy(false);
        }
    }, [selectedIds, clearSelection, refetch]);

    const promptBulkAprovar = useCallback(() => {
        const n = selectedPendentesAprovacao.length;
        if (n === 0) {
            message.warning('Selecione pelo menos um requisito pendente de aprovação.');
            return;
        }
        confirmDialog({
            title: 'Aprovar requisitos selecionados',
            content: `Confirma aprovar ${n} requisito(s) selecionado(s)?`,
            okText: 'Aprovar',
            cancelText: 'Cancelar',
            onOk: () => execBulkAprovar(),
        });
    }, [selectedPendentesAprovacao.length, execBulkAprovar]);

    const promptBulkExcluir = useCallback(() => {
        const n = selectedIds.length;
        if (n === 0) {
            message.warning('Selecione pelo menos um requisito.');
            return;
        }
        confirmDialog({
            title: 'Excluir requisitos selecionados',
            content: `Excluir permanentemente ${n} requisito(s)? Esta ação não pode ser desfeita.`,
            okText: 'Excluir',
            cancelText: 'Cancelar',
            okButtonProps: { danger: true },
            onOk: () => execBulkExcluir(),
        });
    }, [selectedIds.length, execBulkExcluir]);

    const acoesMassaModal = useMemo((): ModalOpcaoAction[] => {
        const nPendentes = selectedPendentesAprovacao.length;
        const n = selectedIds.length;
        return [
            {
                key: 'aprovar',
                label: `Aprovar selecionados${nPendentes > 0 ? ` (${nPendentes})` : ''}`,
                icon: <CheckCircle2 size={ICON_SIZE_MD} aria-hidden />,
                primary: true,
                disabled: bulkBusy || nPendentes === 0,
                onClick: () => {
                    setModalAcoesMassaOpen(false);
                    window.setTimeout(() => promptBulkAprovar(), BULK_CONFIRM_OPEN_DELAY_MS);
                },
            },
            {
                key: 'excluir',
                label: `Excluir selecionados${n > 0 ? ` (${n})` : ''}`,
                icon: <Trash2 size={ICON_SIZE_MD} aria-hidden />,
                danger: true,
                disabled: bulkBusy || n === 0,
                onClick: () => {
                    setModalAcoesMassaOpen(false);
                    window.setTimeout(() => promptBulkExcluir(), BULK_CONFIRM_OPEN_DELAY_MS);
                },
            },
        ];
    }, [
        bulkBusy,
        selectedIds.length,
        selectedPendentesAprovacao.length,
        promptBulkAprovar,
        promptBulkExcluir,
    ]);

    const aprovados = requisitosRows.filter((r: any) => r.aprovado).length;
    const rascunhos = requisitosRows.filter(
        (r) => !r.aprovado && String(r.status ?? '').toLowerCase() === 'rascunho',
    ).length;
    const pendentesAprovacao = requisitosRows.filter(
        (r) => !r.aprovado && String(r.status ?? '').toLowerCase() === 'pendente',
    ).length;
    /** Epic 5 — KPI honesto: rascunho ≠ pendente; «Não aprovados» cobre ambos. */
    const naoAprovados = requisitosRows.filter((r: any) => !r.aprovado).length;

    const lacunasRequisitos = useMemo(() => {
        const rows = requisitosRows;
        const semDescricao = rows.filter((r: any) => !r.descricao?.trim()).length;
        const semCriterio = rows.filter((r: any) => !r.criterios_aceitacao?.trim()).length;
        const naoAprovados = rows.filter((r: any) => !r.aprovado).length;
        return { semDescricao, semCriterio, naoAprovados, total: rows.length };
    }, [requisitosRows]);

    const filtrosAtivosCount = useMemo(() => {
        let n = 0;
        if (statusFilter !== undefined && statusFilter !== null) n += 1;
        if (tipoFilter !== undefined && tipoFilter !== null) n += 1;
        if (prioridadeFilter !== undefined && prioridadeFilter !== null) n += 1;
        if (fonteFilter !== undefined && fonteFilter !== null) n += 1;
        if (searchValue.trim()) n += 1;
        return n;
    }, [statusFilter, tipoFilter, prioridadeFilter, fonteFilter, searchValue]);
    const filtrosComAlgumAtivo = filtrosAtivosCount > 0;

    const totalRegistos = requisitos?.meta?.total ?? requisitosRows.length;
    const listagemErroMsg = getLaravelApiErrorMessage(
        queryError,
        'Não foi possível carregar os requisitos. Verifique a conexão e tente novamente.',
    );
    const showEmptyState = !isError && totalRegistos === 0 && !isLoading;
    const showTableBlock = !isError && !showEmptyState;

    const resumoFiltrosAplicados = useMemo(() => {
        const partes: string[] = [];
        if (statusFilter !== undefined && statusFilter !== null && statusData?.data) {
            const row = statusData.data.find((s) => s.id === statusFilter);
            if (row) partes.push(`Status: ${row.nome}`);
        }
        if (tipoFilter !== undefined && tipoFilter !== null && tiposData?.data) {
            const row = tiposData.data.find((t) => t.id === tipoFilter);
            if (row) partes.push(`Tipo: ${row.nome}`);
        }
        if (prioridadeFilter !== undefined && prioridadeFilter !== null && prioridadesData?.data) {
            const row = prioridadesData.data.find((p) => p.id === prioridadeFilter);
            if (row) partes.push(`Prioridade: ${row.nome}`);
        }
        if (fonteFilter !== undefined && fonteFilter !== null && fontesData?.data) {
            const row = fontesData.data.find((f) => f.id === fonteFilter);
            if (row) partes.push(`Fonte: ${row.nome}`);
        }
        const q = searchValue.trim();
        if (q) partes.push(`Pesquisa: "${q}"`);
        return partes.length ? partes.join(' · ') : '';
    }, [
        statusFilter,
        tipoFilter,
        prioridadeFilter,
        fonteFilter,
        searchValue,
        statusData,
        tiposData,
        prioridadesData,
        fontesData,
    ]);

    const abrirModalFiltros = useCallback(() => {
        setDraftStatusFilter(statusFilter);
        setDraftTipoFilter(tipoFilter);
        setDraftPrioridadeFilter(prioridadeFilter);
        setDraftFonteFilter(fonteFilter);
        setDraftSearchInput(searchInput);
        setDraftListSortValue(listSortValue);
        setFiltrosModalOpen(true);
    }, [statusFilter, tipoFilter, prioridadeFilter, fonteFilter, searchInput, listSortValue]);

    const reporRascunhoFiltros = useCallback(() => {
        setDraftStatusFilter(undefined);
        setDraftTipoFilter(undefined);
        setDraftPrioridadeFilter(undefined);
        setDraftFonteFilter(undefined);
        setDraftSearchInput('');
        setDraftListSortValue('codigo:ascend');
    }, []);

    const aplicarFiltrosModal = useCallback(() => {
        setStatusFilter(draftStatusFilter);
        setTipoFilter(draftTipoFilter);
        setPrioridadeFilter(draftPrioridadeFilter);
        setFonteFilter(draftFonteFilter);
        const q = draftSearchInput.trim();
        setSearchValue(q);
        setSearchInput(q);
        setListSortValue(draftListSortValue);
        setCurrentPage(1);
        setFiltrosModalOpen(false);
    }, [
        draftStatusFilter,
        draftTipoFilter,
        draftPrioridadeFilter,
        draftFonteFilter,
        draftSearchInput,
        draftListSortValue,
    ]);

    return (
        <ProjetoLayout
            projetoId={projetoId}
            pageTitle="Requisitos"
            showPageTitleIcon={false}
            titleSection="Requisitos"
            headerAction={
                abaAtiva === 'lista' ? (
                <Space wrap size={8} align="center">
                    <Tooltip
                        title={
                            filtrosComAlgumAtivo
                                ? `Filtros ativos (${filtrosAtivosCount}) — abrir para alterar catálogos ou pesquisa`
                                : 'Definir status, tipo, prioridade, fonte e texto de pesquisa na listagem'
                        }
                    >
                        <span style={{ display: 'inline-block' }}>
                            <Badge dot={filtrosComAlgumAtivo} color="geekblue">
                                <ButtonHeaderIcon
                                    data-testid="planejamento-requisitos-abrir-filtros"
                                    icon={<Filter size={ICON_SIZE_MD} aria-hidden />}
                                    title={
                                        filtrosAtivosCount > 0
                                            ? `Filtros (${filtrosAtivosCount})`
                                            : 'Filtros'
                                    }
                                    aria-label="Abrir filtros de requisitos"
                                    aria-expanded={filtrosModalOpen}
                                    aria-haspopup="dialog"
                                    onClick={abrirModalFiltros}
                                    className={btnHeaderStyles.btnHeaderIcon}
                                />
                            </Badge>
                        </span>
                    </Tooltip>
                    <Tooltip title="Exportar requisitos visíveis nesta página (Excel, PDF, CSV ou JSON)">
                        <span style={{ display: 'inline-block' }}>
                            <LazyExportButton
                                data={requisitosRows as unknown as Record<string, unknown>[]}
                                columns={[
                                    { key: 'codigo', label: 'Código' },
                                    { key: 'titulo', label: 'Título' },
                                    { key: 'status', label: 'Status' },
                                    { key: 'prioridade', label: 'Prioridade' },
                                ]}
                                filename="requisitos"
                                title="Exportar requisitos"
                                iconOnly
                                size="large"
                                exportMenuMode="modal"
                                className={btnHeaderStyles.btnHeaderIcon}
                            />
                        </span>
                    </Tooltip>
                    {/* TASK-PSC-044 — AuthZ API = update no projeto (PSC-043: sem 403) */}
                    {canEditar ? (
                        <Tooltip title="Analisar o projeto e sugerir requisitos com IA">
                            <span style={{ display: 'inline-block' }}>
                                <ButtonHeaderIcon
                                    data-testid="planejamento-requisitos-sugerir-ia"
                                    icon={<Sparkles size={ICON_SIZE_MD} aria-hidden />}
                                    title="Sugerir com IA"
                                    aria-label="Sugerir requisitos com IA"
                                    onClick={abrirSugerirIa}
                                    className={btnHeaderStyles.btnHeaderIcon}
                                />
                            </span>
                        </Tooltip>
                    ) : null}
                    {canEditar ? (
                        <Tooltip title="Importar requisitos a partir de arquivo CSV (UTF-8)">
                            <span style={{ display: 'inline-block' }}>
                                <ButtonHeaderIcon
                                    data-testid="planejamento-requisitos-importar-csv"
                                    icon={<Upload size={ICON_SIZE_MD} aria-hidden />}
                                    title="Importar CSV"
                                    aria-label="Importar requisitos via CSV"
                                    onClick={() => setImportCsvOpen(true)}
                                    className={btnHeaderStyles.btnHeaderIcon}
                                />
                            </span>
                        </Tooltip>
                    ) : null}
                </Space>
                ) : null
            }
        >
            <Tabs
                activeKey={abaAtiva}
                onChange={(key) => setAbaAtiva(key === 'rastreabilidade' ? 'rastreabilidade' : 'lista')}
                style={{ marginBottom: 16 }}
                items={[
                    { key: 'lista', label: 'Lista' },
                    { key: 'rastreabilidade', label: 'Rastreabilidade' },
                ]}
                data-testid="planejamento-requisitos-abas"
            />

            {abaAtiva === 'rastreabilidade' ? (
                <ProjetoRastreabilidadePanel projetoId={projetoId} />
            ) : (
            <>
            {lacunasRequisitos.total > 0 &&
                (lacunasRequisitos.semDescricao > 0 ||
                    lacunasRequisitos.semCriterio > 0 ||
                    lacunasRequisitos.naoAprovados > 0) && (
                    <Alert
                        type="warning"
                        showIcon
                        style={{ marginBottom: 24 }}
                        message="Lacunas no recorte atual da lista"
                        description={
                            <ul style={{ marginBottom: 0, paddingLeft: 20 }}>
                                {lacunasRequisitos.semDescricao > 0 && (
                                    <li>
                                        {lacunasRequisitos.semDescricao} requisito(s) sem descrição —
                                        complemente antes de priorizar para sprint.
                                    </li>
                                )}
                                {lacunasRequisitos.semCriterio > 0 && (
                                    <li>
                                        {lacunasRequisitos.semCriterio} requisito(s) sem critério de
                                        aceite — defina como validar a entrega.
                                    </li>
                                )}
                                {lacunasRequisitos.naoAprovados > 0 && (
                                    <li>
                                        {lacunasRequisitos.naoAprovados} ainda não aprovado(s) —
                                        valide com stakeholders antes de comprometer entrega.
                                    </li>
                                )}
                            </ul>
                        }
                    />
                )}

            {!coberturaForbidden && cobertura && cobertura.sem_teste > 0 ? (
                <Alert
                    type="warning"
                    showIcon
                    style={{ marginBottom: 24 }}
                    data-testid="planejamento-requisitos-sem-teste"
                    message={`${cobertura.sem_teste} requisito(s) elegível(is) sem teste associado`}
                    description={`Cobertura requisito→teste: ${cobertura.percentual ?? 0}% (${cobertura.cobertos} de ${cobertura.elegiveis}). Associe testes para reduzir risco de regressão.`}
                    action={
                        <Button
                            size="small"
                            onClick={() => router.push(`/projetos/${projetoId}/qualidade/testes`)}
                        >
                            Abrir testes
                        </Button>
                    }
                />
            ) : null}

            {requisitos && (
                <MetricsGrid columns={4} style={{ marginBottom: 24 }}>
                    <MetricCard
                        icon={<FileText size={ICON_SIZE_MD} aria-hidden />}
                        label="Total de Requisitos"
                        value={requisitos.meta?.total ?? requisitosRows.length}
                        variant="projetos"
                    />
                    <MetricCard
                        icon={<CheckCircle2 size={ICON_SIZE_MD} aria-hidden />}
                        label="Aprovados"
                        value={aprovados}
                        variant="concluidos"
                    />
                    <MetricCard
                        icon={<Eye size={ICON_SIZE_MD} aria-hidden />}
                        label="Não aprovados"
                        value={naoAprovados}
                        subvalue={
                            rascunhos + pendentesAprovacao > 0
                                ? `${rascunhos} rascunho(s) · ${pendentesAprovacao} aguardando aprovação`
                                : undefined
                        }
                        variant="planejamento"
                    />
                    <MetricCard
                        icon={<CheckCircle2 size={ICON_SIZE_MD} aria-hidden />}
                        label="Cobertura → teste"
                        value={
                            coberturaForbidden || !cobertura
                                ? '—'
                                : cobertura.elegiveis === 0
                                  ? 'N/A'
                                  : `${cobertura.percentual ?? 0}%`
                        }
                        variant="projetos"
                    />
                </MetricsGrid>
            )}

            <Modal
                title="Filtrar e pesquisar"
                data-testid="planejamento-requisitos-filtros-modal"
                open={filtrosModalOpen}
                onCancel={() => setFiltrosModalOpen(false)}
                width={filtrosModalLayout.width ?? 720}
                centered={filtrosModalLayout.centered}
                styles={filtrosModalLayout.styles}
                footer={
                    <FiltrosModalFooterPadrao
                        onLimparTodos={reporRascunhoFiltros}
                        onFechar={() => setFiltrosModalOpen(false)}
                        showFiltrarPrimary
                        onFiltrar={aplicarFiltrosModal}
                        dataTestIdLimparTodos="planejamento-requisitos-filtros-modal-limpar-todos"
                    />
                }
                destroyOnHidden
                keyboard
                focusTriggerAfterClose
            >
                <Row gutter={16}>
                    <Col xs={24}>
                        <FormGroup label="Pesquisa">
                            <Input.Search
                                placeholder={'Buscar requisitos (código, título…) — confirme com "Filtrar" ou Enter em "Pesquisar"'}
                                allowClear
                                style={{ width: '100%' }}
                                value={draftSearchInput}
                                onChange={(e) => setDraftSearchInput(e.target.value)}
                                onSearch={() => aplicarFiltrosModal()}
                                enterButton="Pesquisar"
                                aria-label="Pesquisar requisitos na listagem"
                            />
                        </FormGroup>
                    </Col>
                </Row>
                <Row gutter={16} style={{ marginTop: 16 }}>
                    <Col xs={24} sm={12} md={6}>
                        <FormGroup label="Status">
                            <Select
                                placeholder="Todos"
                                allowClear
                                style={{ width: '100%' }}
                                value={draftStatusFilter}
                                onChange={(value) => setDraftStatusFilter(value)}
                                options={statusOptions}
                            />
                        </FormGroup>
                    </Col>
                    <Col xs={24} sm={12} md={6}>
                        <FormGroup label="Tipo">
                            <Select
                                placeholder="Todos"
                                allowClear
                                style={{ width: '100%' }}
                                value={draftTipoFilter}
                                onChange={(value) => setDraftTipoFilter(value)}
                                options={tipoOptions}
                            />
                        </FormGroup>
                    </Col>
                    <Col xs={24} sm={12} md={6}>
                        <FormGroup label="Prioridade">
                            <Select
                                placeholder="Todas"
                                allowClear
                                style={{ width: '100%' }}
                                value={draftPrioridadeFilter}
                                onChange={(value) => setDraftPrioridadeFilter(value)}
                                options={prioridadeOptions}
                            />
                        </FormGroup>
                    </Col>
                    <Col xs={24} sm={12} md={6}>
                        <FormGroup label="Fonte">
                            <Select
                                placeholder="Todas"
                                allowClear
                                style={{ width: '100%' }}
                                value={draftFonteFilter}
                                onChange={(value) => setDraftFonteFilter(value)}
                                options={fonteOptions}
                            />
                        </FormGroup>
                    </Col>
                </Row>
                <Row gutter={16} style={{ marginTop: 16 }}>
                    <Col xs={24} sm={12}>
                        <FormGroup label="Ordenação">
                            <Select
                                style={{ width: '100%' }}
                                value={draftListSortValue}
                                onChange={(value) => setDraftListSortValue(value)}
                                options={[...REQUISITOS_SORT_OPTIONS]}
                                aria-label="Ordenar listagem de requisitos"
                            />
                        </FormGroup>
                    </Col>
                </Row>
            </Modal>

            {filtrosComAlgumAtivo && showTableBlock ? (
                <Alert
                    type="info"
                    showIcon
                    style={{ marginBottom: 16 }}
                    message={`Filtros aplicados (${filtrosAtivosCount})`}
                    description={
                        <>
                            {resumoFiltrosAplicados}
                            <Button type="link" onClick={limparTodosFiltros} style={{ paddingLeft: 8 }}>
                                Limpar filtros
                            </Button>
                        </>
                    }
                />
            ) : null}

            {isError ? (
                <ListagemListaError
                    message="Falha ao carregar requisitos"
                    description={listagemErroMsg}
                    onRetry={() => void refetch()}
                    data-testid="planejamento-requisitos-lista-retry"
                />
            ) : null}

            {showEmptyState ? (
                <ListagemEmptyState
                    type={filtrosComAlgumAtivo ? 'warning' : 'info'}
                    compact={isMobile}
                    icon={<FileText size={iconTokenSize.xl} aria-hidden />}
                    message={
                        filtrosComAlgumAtivo
                            ? 'Nenhum resultado para os filtros'
                            : 'Nenhum requisito cadastrado'
                    }
                    description={
                        filtrosComAlgumAtivo
                            ? 'Ajuste os critérios ou limpe os filtros para voltar a ver requisitos deste projeto.'
                            : tipologicoEmptyDescription(
                                  canEditar
                                      ? TIPOLOGICO_EMPTY_DOMAIN.requisitos
                                      : 'Ainda não há requisitos neste projeto. Quem tiver permissão de edição pode cadastrar o primeiro.',
                              )
                    }
                    {...(filtrosComAlgumAtivo
                        ? {
                              ctaLabel: 'Limpar filtros',
                              onCta: limparTodosFiltros,
                          }
                        : canEditar
                          ? {
                                ctaLabel: 'Novo requisito',
                                onCta: openCreate,
                                secondaryCtaLabel: 'Sugerir com IA',
                                onSecondaryCta: abrirSugerirIa,
                            }
                          : {})}
                    extraActions={
                        !filtrosComAlgumAtivo ? (
                            <ProjetoTipologicoSyncCtas projetoId={projetoId} size="small" />
                        ) : undefined
                    }
                    data-testid="planejamento-requisitos-lista-empty"
                />
            ) : null}

            {showTableBlock ? (
                <>
                    {selectedRowKeys.length > 0 ? (
                        <ListingSelectionToolbarCard
                            elevatedStyle
                            titleIcon={<CheckCircle2 size={ICON_SIZE_MD} aria-hidden />}
                            summary={
                                selectedRowKeys.length === 1
                                    ? '1 requisito selecionado'
                                    : `${selectedRowKeys.length} requisitos selecionados`
                            }
                            selectedCount={selectedRowKeys.length}
                            onSelectAllOnPage={mergeSelectCurrentPageIds}
                            selectAllPageLabel="Selecionar página"
                            onClearAll={clearSelection}
                            clearAllLabel="Limpar seleção"
                        />
                    ) : null}
                    <TableScrollWrapper hint={requisitosTabelaScrollHint}>
                        <LazyDataTable
                            rowKey="id"
                            columns={columns}
                            data={requisitosRowsOrdenados}
                            paginatedData={
                                requisitos
                                    ? { ...requisitos, data: requisitosRowsOrdenados }
                                    : undefined
                            }
                            loading={isLoading}
                            onRefresh={refetch}
                            onPageChange={handlePageChange}
                            rowSelection={rowSelection}
                            {...listingTableVirtualScrollProps(requisitosRowsOrdenados.length)}
                            onRow={(record: unknown) => ({
                                onClick: () => setOpcoesItem(record as Requisito),
                                style: { cursor: 'pointer' },
                            })}
                            autoMobileFromColumns={{
                                testIdPrefix: 'planejamento-requisitos',
                                listHeading: 'Lista de requisitos',
                                getFallbackTitle: (record: any) =>
                                    record.titulo?.trim() || `Requisito ${record.id}`,
                                getSubtitle: (record: any) =>
                                    [record.codigo, record.prioridade ? getPrioridadeLabel(record.prioridade) : null]
                                        .filter(Boolean)
                                        .join(' · ') || undefined,
                                excludeFieldKeys: ['titulo', 'codigo'],
                                onCardClick: (item) => setOpcoesItem(item),
                                onOpenOptions: (item) => setOpcoesItem(item),
                            }}
                        />
                    </TableScrollWrapper>
                </>
            ) : null}

            {!isLoading ? (
                <ModuleRelatedLinksPanel
                    surfaceKey={PLANEJAMENTO_REQUISITOS_RELATED_SURFACE}
                    variant="footer"
                    pagePrefix="projeto-planejamento-requisitos"
                />
            ) : null}
            </>
            )}

            <ModalOpcoesRequisito
                open={opcoesItem !== null}
                onClose={() => setOpcoesItem(null)}
                item={opcoesItem}
                onVer={(item) => {
                    setOpcoesItem(null);
                    const full = requisitosRows.find((r: any) => r.id === item.id);
                    if (full) {
                        setSelectedItem(full);
                        setDrawerVisible(true);
                    }
                }}
                onAprovar={(item) => {
                    setOpcoesItem(null);
                    handleApprove(item.id);
                }}
                onEditar={(item) => {
                    setOpcoesItem(null);
                    const full = requisitosRows.find((r: any) => r.id === item.id);
                    if (full) openEdit(full);
                }}
                onExcluir={(item) => {
                    setOpcoesItem(null);
                    const full = requisitosRows.find((r: any) => r.id === item.id);
                    if (full) handleDelete(full);
                }}
                hideAprovar={opcoesItem?.aprovado === true}
            />

            <Modal
                title={editingItem ? 'Editar requisito' : 'Novo requisito'}
                open={modalOpen}
                onCancel={() => {
                    setModalOpen(false);
                    setEditingItem(null);
                    form.resetFields();
                }}
                footer={
                    <div className={waygestFormModalFooterClassName}>
                        <Button
                            onClick={() => {
                                setModalOpen(false);
                                setEditingItem(null);
                                form.resetFields();
                            }}
                        >
                            Cancelar
                        </Button>
                        <Button
                            type="primary"
                            loading={storeMutation.isPending || updateMutation.isPending}
                            onClick={() => form.submit()}
                        >
                            {editingItem ? 'Salvar' : 'Criar'}
                        </Button>
                    </div>
                }
                width={formModalLayout.width ?? 560}
                centered={formModalLayout.centered ?? true}
                className={formModalLayout.className}

                styles={formModalLayout.styles ?? {}}
                destroyOnHidden
                keyboard
                focusTriggerAfterClose
                data-testid="projeto-planejamento-requisitos-form-modal"
            >
                <Form form={form} layout="vertical" onFinish={handleSubmit} scrollToFirstError>
                    <FormGroup>
                        <Form.Item
                            name="titulo"
                            label="Título"
                            rules={[{ required: true, message: 'Informe o título' }]}
                        >
                            <Input placeholder="Título do requisito" />
                        </Form.Item>
                    </FormGroup>
                    <FormGroup>
                        <Form.Item name="codigo" label="Código">
                            <Input placeholder="Código" />
                        </Form.Item>
                    </FormGroup>
                    <FormGroup>
                        <Form.Item name="descricao" label="Descrição">
                            <Input.TextArea rows={3} placeholder="Descrição" />
                        </Form.Item>
                    </FormGroup>
                    <FormGroup>
                        <Form.Item
                            name="criterios_aceitacao"
                            label="Critérios de aceite"
                            extra="Como validar que o requisito foi atendido (UAT / DoD)."
                        >
                            <Input.TextArea
                                rows={3}
                                placeholder="Ex.: dado X, quando Y, então Z…"
                            />
                        </Form.Item>
                    </FormGroup>
                    <Row gutter={16}>
                        <Col xs={24} md={12}>
                            <Form.Item name="status_id" label="Status">
                                <Select placeholder="Status" allowClear options={statusOptions} />
                            </Form.Item>
                        </Col>
                        <Col xs={24} md={12}>
                            <Form.Item name="tipo_id" label="Tipo">
                                <Select placeholder="Tipo" allowClear options={tipoOptions} />
                            </Form.Item>
                        </Col>
                    </Row>
                    <Row gutter={16}>
                        <Col xs={24} md={12}>
                            <Form.Item name="prioridade_id" label="Prioridade">
                                <Select
                                    placeholder="Prioridade"
                                    allowClear
                                    options={prioridadeOptions}
                                />
                            </Form.Item>
                        </Col>
                        <Col xs={24} md={12}>
                            <Form.Item name="fonte_id" label="Fonte">
                                <Select placeholder="Fonte" allowClear options={fonteOptions} />
                            </Form.Item>
                        </Col>
                    </Row>
                </Form>
            </Modal>

            <Drawer
                title={selectedItem?.titulo}
                placement="right"
                onClose={() => {
                    setDrawerVisible(false);
                    setSelectedItem(null);
                }}
                open={drawerVisible}
                width={detalheDrawerWidth}
            >
                {selectedItem && (
                    <div>
                        <Row gutter={16} style={{ marginBottom: 16 }}>
                            <Col xs={24} md={12}>
                                <Typography.Text strong>Código:</Typography.Text>
                                <div style={{ marginTop: 4 }}>{selectedItem.codigo || '-'}</div>
                            </Col>
                            <Col xs={24} md={12}>
                                <Typography.Text strong>Status:</Typography.Text>
                                <div style={{ marginTop: 4 }}>
                                    <Tag
                                        color={
                                            selectedItem.aprovado
                                                ? 'success'
                                                : getStatusColor(selectedItem.status)
                                        }
                                    >
                                        {selectedItem.aprovado
                                            ? 'Aprovado'
                                            : getStatusLabel(selectedItem.status)}
                                    </Tag>
                                </div>
                            </Col>
                        </Row>
                        {selectedItem.prioridade && (
                            <div style={{ marginBottom: 16 }}>
                                <Typography.Text strong>Prioridade:</Typography.Text>
                                <div style={{ marginTop: 4 }}>
                                    <Tag>{selectedItem.prioridade.toUpperCase()}</Tag>
                                </div>
                            </div>
                        )}
                        {selectedItem.projeto && (
                            <div style={{ marginBottom: 16 }}>
                                <Typography.Text strong>Projeto:</Typography.Text>
                                <div style={{ marginTop: 4 }}>{selectedItem.projeto.nome}</div>
                            </div>
                        )}
                        {selectedItem.descricao && (
                            <div style={{ marginBottom: 16 }}>
                                <Typography.Text strong>Descrição:</Typography.Text>
                                <div style={{ marginTop: 4, whiteSpace: 'pre-wrap' }}>
                                    {selectedItem.descricao}
                                </div>
                            </div>
                        )}
                        <div style={{ marginTop: 24 }}>
                            <Typography.Text type="secondary" style={{ fontSize: 12 }}>
                                Criado em: {formatDate(selectedItem.created_at)}
                            </Typography.Text>
                            <br />
                            <Typography.Text type="secondary" style={{ fontSize: 12 }}>
                                Atualizado em: {formatDate(selectedItem.updated_at)}
                            </Typography.Text>
                        </div>
                        <div style={{ marginTop: 16 }}>
                            <Space>
                                <Button
                                    type="primary"
                                    onClick={() => {
                                        setDrawerVisible(false);
                                        openEdit(selectedItem);
                                    }}
                                >
                                    <Pencil size={ICON_SIZE_MD} style={{ marginRight: 8 }} aria-hidden />
                                    Editar
                                </Button>
                                <Button
                                    danger
                                    onClick={() => {
                                        setDrawerVisible(false);
                                        handleDelete(selectedItem);
                                    }}
                                >
                                    <Trash2 size={ICON_SIZE_MD} style={{ marginRight: 8 }} aria-hidden />
                                    Excluir
                                </Button>
                            </Space>
                        </div>
                    </div>
                )}
            </Drawer>

            <ListingBulkFabModal
                showFab={abaAtiva === 'lista' && selectedRowKeys.length > 0 && canEditar}
                modalOpen={modalAcoesMassaOpen}
                onOpenModal={() => setModalAcoesMassaOpen(true)}
                onCloseModal={() => setModalAcoesMassaOpen(false)}
                busy={bulkBusy}
                modalTitle="Ações em massa"
                modalSubtitle={`${selectedRowKeys.length} requisito(s) selecionado(s)`}
                actions={acoesMassaModal}
                fabAriaLabel={`Ações em massa — ${selectedRowKeys.length} requisito(s) selecionado(s)`}
                data-testid-fab="planejamento-requisitos-fab-selecao-acoes"
                data-testid-modal="planejamento-requisitos-modal-acoes-massa"
            />

            {abaAtiva === 'lista' && selectedRowKeys.length === 0 && canEditar ? (
                <ListPageCreateFloatButton
                    data-testid="projeto-planejamento-requisitos-fab-novo"
                    tooltip={{
                        title: 'Novo requisito — refine a listagem com Filtros no cabeçalho',
                    }}
                    onClick={openCreate}
                />
            ) : null}

            {isMobile && abaAtiva === 'lista' ? (
                <MobilePageActionBar
                    onOpenFilters={abrirModalFiltros}
                    activeFiltersCount={filtrosAtivosCount}
                    filterButtonLabel="Filtros"
                    onRefresh={() => void refetch()}
                    refreshLoading={isLoading}
                    hideOpcoes
                />
            ) : null}

            <ProjetoEntidadeImportCsvModal
                open={importCsvOpen}
                onClose={() => setImportCsvOpen(false)}
                onSuccess={() => {
                    void refetch();
                }}
                projetoId={projetoId}
                kind="requisitos"
            />

            <ModalSugerirRequisitosIa
                open={iaModalOpen}
                loadingSugestoes={sugerirIaMutation.isPending}
                applying={aplicarSugestoesMutation.isPending}
                sugestoes={iaSugestoes}
                errorMessage={iaError}
                onClose={() => {
                    setIaModalOpen(false);
                    setIaSugestoes([]);
                    setIaError(null);
                }}
                onRetry={abrirSugerirIa}
                onAplicar={(selecionados) => {
                    aplicarSugestoesMutation.mutate({ requisitos: selecionados });
                }}
            />
        </ProjetoLayout>
    );
}
