'use client';

/**
 * UAT sign-off key user por módulo — TASK-PSC-035.
 * Lista módulos do projeto e registra sign-off via POST …/modulos/{id}/uat-signoff.
 */

import { keepPreviousData } from '@tanstack/react-query';
import {
    CheckCircle2,
    ClipboardCheck,
    Filter,
    RotateCcw,
    XCircle,
} from 'lucide-react';
import {
    Alert,
    Badge,
    Button,
    Form,
    Modal,
    Space,
    Tag,
    Tooltip,
    Typography,
} from 'antd';
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { usePathname, useRouter, useSearchParams } from 'next/navigation';
import type { ColumnsType } from 'antd/es/table';
import type { ModalOpcaoAction } from '@/components/ModalOpcoesBase';

import { ICON_SIZE_MD, iconTokenSize } from '@/components/icons';
import { FormTextarea } from '@/components/form';
import { ButtonHeaderIcon } from '@/components/ui';
import MetricCard from '@/components/layouts/MetricCard';
import MetricsGrid from '@/components/layouts/MetricsGrid';
import ProjetoLayout from '@/components/layouts/ProjetoLayout';
import { LazyDataTable, LazyExportButton } from '@/components/lazy';
import { TableScrollWrapper } from '@/components/tables/TableScrollWrapper';
import { MobilePageActionBar } from '@/components/filters/MobilePageActionBar';
import { useListingMobileChrome } from '@/components/mobile';
import {
    ListPageCreateFloatButton,
    ListagemEmptyState,
    ListagemListaError,
    ListingActionsColumnCell,
    ListingBulkFabModal,
    ListingColumnCustomizeModal,
    ListingPageOptionsButton,
    ListingPageOptionsModal,
    SavedFilterActiveTag,
    buildListingRowInteractiveProps,
    filterTableColumnsByVisibleKeys,
    listingServerSortNoOp,
    useListingMobileScrollHint,
    useListingVisibleColumns,
} from '@/components/listings';
import { useProjetoWriteGates } from '@/features/projetos/hooks/useProjetoWriteGates';
import {
    ProjetoTipologicoSyncCtas,
    tipologicoEmptyDescription,
    TIPOLOGICO_EMPTY_DOMAIN,
} from '@/features/projetos/projeto-tipologico-empty-state';
import btnHeaderStyles from '@/components/ui/buttons/ButtonHeaderIcon/ButtonHeaderIcon.module.scss';
import { useListingFilteredRowSelection } from '@/hooks/useListingFilteredRowSelection';
import { useMutationCache } from '@/hooks/useMutationCache';
import { usePaginatedResponseFallback } from '@/hooks/usePaginatedResponseFallback';
import { useQueryCache } from '@/hooks/useQueryCache';
import {
    listingSortColumnUi,
    useServerSideListingTableChange,
    type ServerSideSortState,
} from '@/hooks/useServerSideListingTableChange';
import {
    mergeWaygestFormModalBodyStyles,
    useWaygestFormModalProps,
    waygestFormModalFooterClassName,
} from '@/hooks/useWaygestFormModalProps';
import { API_ENDPOINTS } from '@/lib/api/endpoints';
import apiClient from '@/lib/api/client';
import { queryKeys } from '@/lib/cache/queryKeys';
import { confirmDialog } from '@/lib/feedback/confirmDialog';
import { message } from '@/lib/feedback/message';
import type { PaginatedResponse, Projeto } from '@/types';
import { ModalFiltrosUatSignOff } from './components/ModalFiltrosUatSignOff';
import { ModalOpcoesUatModulo } from './ModalOpcoesUatModulo';
import { useUatSignOffListaUrlSync } from './hooks/useUatSignOffListaUrlSync';
import {
    getUatSignOffAcaoLabel,
    getUatSignOffAcoesDisponiveis,
    getUatSignOffActorNome,
    getUatSignOffErrorMessage,
    getUatSignOffStatusColor,
    getUatSignOffStatusLabel,
    normalizeUatSignOffStatus,
    uatSignOffAcaoToStatus,
} from './uatSignOffDisplay';
import type { UatSignOffAcao, UatSignOffAcaoPayload, UatSignOffModulo } from './types';
import { UAT_SIGNOFF_STATUS_OPTIONS } from './types';
import {
    UAT_SIGNOFF_LIST_MODULE_KEY,
    uatSignOffApplySavedPayload,
} from './utils/uatSignOffFiltrosPayload';
import { UAT_SIGNOFF_LIST_COLUMN_CATALOG } from './utils/uatSignOffListColumnCatalog';
import {
    UAT_SIGNOFF_LISTA_URL_DEFAULTS,
    type UatSignOffListaFiltrosApi,
    type UatSignOffListaUrlSnapshot,
} from './utils/uatSignOffListaFiltersUrl';

const { Text, Paragraph } = Typography;
const FORM_ID = 'projeto-uat-signoff-acao-form';
const EMPTY_MODULOS: UatSignOffModulo[] = [];
const BULK_CONFIRM_OPEN_DELAY_MS = 120;
const EXPORT_HELP =
    'Exporta apenas os módulos visíveis nesta página (listagem paginada no servidor).';

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

export type ProjetoUatSignOffScreenProps = {
    projetoId: string;
};

type AcaoModalState = {
    modulo: UatSignOffModulo;
    acao: UatSignOffAcao;
};

function formatWhen(iso: string | null | undefined): string {
    if (!iso) return '—';
    try {
        return new Date(iso).toLocaleString('pt-BR');
    } catch {
        return iso;
    }
}

function rotuloAriaOpcoesModulo(record: UatSignOffModulo): string {
    const rotulo = record.nome?.trim();
    return rotulo ? `Opções: ${rotulo}` : `Opções: módulo ${record.id}`;
}

/**
 * Tela de homologação UAT por módulo com sign-off auditado.
 */
export function ProjetoUatSignOffScreen({ projetoId: id }: ProjetoUatSignOffScreenProps) {
    const pathname = usePathname() ?? '';
    const searchParams = useSearchParams();
    const router = useRouter();
    const { isMobile } = useListingMobileChrome();
    const { canEditar, permsLoading } = useProjetoWriteGates();
    const [form] = Form.useForm();
    const formModalLayout = useWaygestFormModalProps();
    const filtrosModalLayout = useWaygestFormModalProps();

    const [currentPage, setCurrentPage] = useState(UAT_SIGNOFF_LISTA_URL_DEFAULTS.page);
    const [pageSize, setPageSize] = useState(UAT_SIGNOFF_LISTA_URL_DEFAULTS.perPage);
    const [tableSort, setTableSort] = useState<ServerSideSortState>(UAT_SIGNOFF_LIST_DEFAULT_SORT);
    const [filtros, setFiltros] = useState<UatSignOffListaFiltrosApi>({});
    const [filtrosModalOpen, setFiltrosModalOpen] = useState(false);
    const [modalFiltrosDraft, setModalFiltrosDraft] = useState<UatSignOffListaFiltrosApi>({});
    const [filtroSalvoAtivo, setFiltroSalvoAtivo] = useState<{ nome: string } | null>(null);
    const skipClearFiltroSalvoOnNextUrlHydrateRef = useRef(false);
    const [listaMaisOpcoesOpen, setListaMaisOpcoesOpen] = useState(false);
    const [colunasVisiveisModalOpen, setColunasVisiveisModalOpen] = useState(false);
    const [modalAcoesMassaOpen, setModalAcoesMassaOpen] = useState(false);
    const [bulkBusy, setBulkBusy] = useState(false);
    const [opcoesItem, setOpcoesItem] = useState<UatSignOffModulo | null>(null);
    const [acaoModal, setAcaoModal] = useState<AcaoModalState | null>(null);
    const [bulkRejeitarOpen, setBulkRejeitarOpen] = useState(false);

    const { visibleKeys: visibleColumnKeys, columnOrder, setVisibleKeys: setVisibleColumnKeys } =
        useListingVisibleColumns(UAT_SIGNOFF_LIST_MODULE_KEY, UAT_SIGNOFF_LIST_COLUMN_CATALOG);

    const { data: projeto } = useQueryCache<Projeto>({
        queryKey: queryKeys.projetos.detail(id),
        endpoint: API_ENDPOINTS.projetos.show(id),
        enabled: !!id,
        staleTime: 60_000,
    });

    const listParams = useMemo(() => {
        const sortColumn = tableSort?.columnKey ?? UAT_SIGNOFF_LIST_DEFAULT_SORT.columnKey;
        const sortDirection =
            (tableSort?.order ?? UAT_SIGNOFF_LIST_DEFAULT_SORT.order) === 'descend' ? 'desc' : 'asc';

        return {
            page: currentPage,
            per_page: pageSize,
            sort_by: sortColumn,
            sort_direction: sortDirection,
            ...(filtros.uat_signoff_status && { uat_signoff_status: filtros.uat_signoff_status }),
            ...(filtros.search?.trim() && { busca: filtros.search.trim() }),
        };
    }, [currentPage, pageSize, tableSort, filtros]);

    const metricParamsBase = useMemo(
        () => ({
            per_page: 1,
            page: 1,
            ...(filtros.search?.trim() && { busca: filtros.search.trim() }),
        }),
        [filtros.search],
    );

    const {
        data: listData,
        isLoading,
        isError,
        error,
        refetch,
        isFetching,
    } = useQueryCache<PaginatedResponse<UatSignOffModulo>>({
        queryKey: queryKeys.projetos.modulosUatList(id, listParams),
        endpoint: API_ENDPOINTS.projetos.modulos.index(id),
        params: listParams,
        enabled: !!id,
        staleTime: 30_000,
        retry: false,
        config: { timeout: 12_000 },
        placeholderData: keepPreviousData,
    });

    const { data: pendentesPage, isLoading: pendentesLoading } = useQueryCache<
        PaginatedResponse<UatSignOffModulo>
    >({
        queryKey: queryKeys.projetos.modulosUatMetric(id, 'metric-pendente', metricParamsBase),
        endpoint: API_ENDPOINTS.projetos.modulos.index(id),
        params: { ...metricParamsBase, uat_signoff_status: 'pendente' },
        enabled: !!id,
        staleTime: 30_000,
    });

    const { data: aprovadosPage, isLoading: aprovadosLoading } = useQueryCache<
        PaginatedResponse<UatSignOffModulo>
    >({
        queryKey: queryKeys.projetos.modulosUatMetric(id, 'metric-aprovado', metricParamsBase),
        endpoint: API_ENDPOINTS.projetos.modulos.index(id),
        params: { ...metricParamsBase, uat_signoff_status: 'aprovado' },
        enabled: !!id,
        staleTime: 30_000,
    });

    const { data: rejeitadosPage, isLoading: rejeitadosLoading } = useQueryCache<
        PaginatedResponse<UatSignOffModulo>
    >({
        queryKey: queryKeys.projetos.modulosUatMetric(id, 'metric-rejeitado', metricParamsBase),
        endpoint: API_ENDPOINTS.projetos.modulos.index(id),
        params: { ...metricParamsBase, uat_signoff_status: 'rejeitado' },
        enabled: !!id,
        staleTime: 30_000,
    });

    const paginatedData = usePaginatedResponseFallback(listData, pageSize, EMPTY_MODULOS);
    const rows = paginatedData.data;
    const total = paginatedData.meta.total ?? 0;

    const paginatedPendentes = usePaginatedResponseFallback(pendentesPage, 1, EMPTY_MODULOS);
    const paginatedAprovados = usePaginatedResponseFallback(aprovadosPage, 1, EMPTY_MODULOS);
    const paginatedRejeitados = usePaginatedResponseFallback(rejeitadosPage, 1, EMPTY_MODULOS);

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

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

    const urlSnapshot = useMemo(
        (): UatSignOffListaUrlSnapshot => ({
            page: currentPage,
            perPage: pageSize,
            filtros,
            sortColumn:
                (tableSort?.columnKey as UatSignOffListaUrlSnapshot['sortColumn']) ??
                UAT_SIGNOFF_LIST_DEFAULT_SORT.columnKey,
            sortDesc: (tableSort?.order ?? UAT_SIGNOFF_LIST_DEFAULT_SORT.order) === 'descend',
        }),
        [currentPage, pageSize, filtros, tableSort],
    );

    const onHydrateFromUrl = useCallback((snapshot: UatSignOffListaUrlSnapshot) => {
        setCurrentPage(snapshot.page);
        setPageSize(snapshot.perPage);
        setFiltros(snapshot.filtros);
        setTableSort({
            columnKey: snapshot.sortColumn,
            order: snapshot.sortDesc ? 'descend' : 'ascend',
        });
        if (!skipClearFiltroSalvoOnNextUrlHydrateRef.current) {
            setFiltroSalvoAtivo(null);
        }
        skipClearFiltroSalvoOnNextUrlHydrateRef.current = false;
    }, []);

    useUatSignOffListaUrlSync({
        pathname,
        searchParams,
        snapshot: urlSnapshot,
        onHydrateFromUrl,
    });

    useEffect(() => {
        clearSelection();
    }, [filtros, clearSelection]);

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

    const handleTableChange = useServerSideListingTableChange<UatSignOffModulo>({
        sortState: tableSort,
        setSortState: setTableSort,
        setPage: setCurrentPage,
        setPerPage: setPageSize,
    });

    const sortColumnUi = listingSortColumnUi(tableSort, UAT_SIGNOFF_LIST_DEFAULT_SORT);

    const acaoMutation = useMutationCache<unknown, UatSignOffAcaoPayload & { moduloId: number }>({
        endpoint: (vars) => API_ENDPOINTS.projetos.modulos.uatSignoff(id, vars.moduloId),
        method: 'POST',
        buildBody: ({ status, notas }) => ({ status, notas }),
        invalidateQueries: [queryKeys.projetos.modulos(id)],
        onSuccess: () => {
            message.success('Sign-off registrado.');
            setAcaoModal(null);
            form.resetFields();
            void refetch();
        },
        onError: (err: unknown) => {
            message.error(getUatSignOffErrorMessage(err, 'Não foi possível registrar a ação.'));
        },
    });

    const openAcao = useCallback((modulo: UatSignOffModulo, acao: UatSignOffAcao) => {
        setAcaoModal({ modulo, acao });
        form.resetFields();
        form.setFieldsValue({ notas: '' });
    }, [form]);

    const execBulkStatus = useCallback(
        async (status: 'aprovado' | 'pendente' | 'rejeitado', notas?: string | null) => {
            if (selectedIds.length === 0) return;
            setBulkBusy(true);
            try {
                const results = await Promise.allSettled(
                    selectedIds.map((moduloId) =>
                        apiClient.post(API_ENDPOINTS.projetos.modulos.uatSignoff(id, moduloId), {
                            status,
                            notas: notas ?? null,
                        }),
                    ),
                );
                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 ? 'Sign-off atualizado.' : `${ok} módulos atualizados.`,
                    );
                    return;
                }
                if (ok > 0 && fail > 0) {
                    message.warning(`${ok} atualizado(s), ${fail} falharam (permissão ou estado).`);
                    return;
                }
                message.error('Não foi possível atualizar os módulos selecionados.');
            } finally {
                setBulkBusy(false);
            }
        },
        [selectedIds, id, clearSelection, refetch],
    );

    const promptBulkAprovar = useCallback(() => {
        const n = selectedIds.length;
        if (n === 0) {
            message.warning('Selecione pelo menos um módulo.');
            return;
        }
        confirmDialog({
            title: 'Aprovar módulos selecionados',
            content: `Registrar sign-off aprovado em ${n} módulo(s)? Esta ação fica no rasto comercial.`,
            okText: 'Aprovar',
            cancelText: 'Cancelar',
            onOk: () => execBulkStatus('aprovado'),
        });
    }, [selectedIds.length, execBulkStatus]);

    const promptBulkReabrir = useCallback(() => {
        const n = selectedIds.length;
        if (n === 0) {
            message.warning('Selecione pelo menos um módulo.');
            return;
        }
        confirmDialog({
            title: 'Reabrir módulos selecionados',
            content: `Voltar ${n} módulo(s) para pendente? O rasto de assinatura desses módulos será limpo.`,
            okText: 'Reabrir',
            cancelText: 'Cancelar',
            onOk: () => execBulkStatus('pendente'),
        });
    }, [selectedIds.length, execBulkStatus]);

    const acoesMassaModal = useMemo((): ModalOpcaoAction[] => {
        const n = selectedIds.length;
        return [
            {
                key: 'aprovar',
                label: `Aprovar selecionados${n > 0 ? ` (${n})` : ''}`,
                icon: <CheckCircle2 size={ICON_SIZE_MD} aria-hidden />,
                disabled: bulkBusy || n === 0,
                onClick: () => {
                    setModalAcoesMassaOpen(false);
                    window.setTimeout(() => promptBulkAprovar(), BULK_CONFIRM_OPEN_DELAY_MS);
                },
            },
            {
                key: 'rejeitar',
                label: `Rejeitar selecionados${n > 0 ? ` (${n})` : ''}`,
                icon: <XCircle size={ICON_SIZE_MD} aria-hidden />,
                danger: true,
                disabled: bulkBusy || n === 0,
                onClick: () => {
                    setModalAcoesMassaOpen(false);
                    window.setTimeout(() => setBulkRejeitarOpen(true), BULK_CONFIRM_OPEN_DELAY_MS);
                },
            },
            {
                key: 'reabrir',
                label: `Reabrir selecionados${n > 0 ? ` (${n})` : ''}`,
                icon: <RotateCcw size={ICON_SIZE_MD} aria-hidden />,
                disabled: bulkBusy || n === 0,
                onClick: () => {
                    setModalAcoesMassaOpen(false);
                    window.setTimeout(() => promptBulkReabrir(), BULK_CONFIRM_OPEN_DELAY_MS);
                },
            },
        ];
    }, [bulkBusy, selectedIds.length, promptBulkAprovar, promptBulkReabrir]);

    const limparTodosFiltros = useCallback(() => {
        setFiltros({});
        setFiltroSalvoAtivo(null);
        setCurrentPage(1);
        setPageSize(UAT_SIGNOFF_LISTA_URL_DEFAULTS.perPage);
        setTableSort(UAT_SIGNOFF_LIST_DEFAULT_SORT);
        setFiltrosModalOpen(false);
        clearSelection();
    }, [clearSelection]);

    const filtrosAtivosCount = useMemo(() => {
        let n = 0;
        if (filtros.uat_signoff_status) n += 1;
        if (filtros.search?.trim()) n += 1;
        return n;
    }, [filtros]);
    const filtrosComAlgumAtivo = filtrosAtivosCount > 0;

    const resumoFiltrosAplicados = useMemo(() => {
        const partes: string[] = [];
        if (filtros.uat_signoff_status) {
            partes.push(
                `Estado UAT: ${
                    UAT_SIGNOFF_STATUS_OPTIONS.find((o) => o.value === filtros.uat_signoff_status)
                        ?.label ?? filtros.uat_signoff_status
                }`,
            );
        }
        const q = filtros.search?.trim();
        if (q) partes.push(`Pesquisa: "${q}"`);
        return partes.length ? partes.join(' · ') : '';
    }, [filtros]);

    const abrirModalFiltros = useCallback(() => {
        setModalFiltrosDraft({ ...filtros });
        setFiltrosModalOpen(true);
    }, [filtros]);

    const aplicarFiltrosModal = useCallback(() => {
        setFiltros({ ...modalFiltrosDraft });
        setCurrentPage(1);
        setFiltrosModalOpen(false);
        clearSelection();
    }, [modalFiltrosDraft, clearSelection]);

    const limparRascunhoFiltros = useCallback(() => {
        setModalFiltrosDraft({});
    }, []);

    const handleApplySavedFilter = useCallback(
        (payload: unknown, meta: { nome: string; id: number }) => {
            const parsed = uatSignOffApplySavedPayload(payload);
            if (!parsed) {
                message.error('Não foi possível aplicar o filtro salvo.');
                return;
            }
            setFiltros(parsed);
            setModalFiltrosDraft(parsed);
            setFiltroSalvoAtivo({ nome: meta.nome });
            setCurrentPage(1);
            clearSelection();
            setFiltrosModalOpen(false);
            skipClearFiltroSalvoOnNextUrlHydrateRef.current = true;
        },
        [clearSelection],
    );

    const abrirOpcoesModulo = useCallback((record: UatSignOffModulo) => {
        setOpcoesItem(record);
    }, []);

    const handleRowProps = useCallback(
        (record: UatSignOffModulo) =>
            buildListingRowInteractiveProps(record, {
                onAtivate: abrirOpcoesModulo,
                getRowSummary: (row) => row.nome?.trim() || `Módulo ${row.id}`,
                ariaLabelWithSummary: (summary) =>
                    `Módulo: ${summary}. Enter ou espaço abre o menu de opções.`,
                ariaLabelFallback: 'Módulo. Enter ou espaço abre o menu de opções.',
            }),
        [abrirOpcoesModulo],
    );

    const tabelaScrollHint = useListingMobileScrollHint(
        'Deslize horizontalmente para ver todas as colunas.',
    );

    const columns: ColumnsType<UatSignOffModulo> = useMemo(() => {
        const allColumns: ColumnsType<UatSignOffModulo> = [
            {
                title: '',
                key: 'menu',
                width: 52,
                align: 'center',
                fixed: 'left',
                onCell: () => ({ onClick: (e: React.MouseEvent) => e.stopPropagation() }),
                render: (_: unknown, record: UatSignOffModulo) => (
                    <ListingActionsColumnCell
                        ariaLabel={rotuloAriaOpcoesModulo(record)}
                        onOpen={() => setOpcoesItem(record)}
                    />
                ),
            },
            {
                title: 'Módulo',
                dataIndex: 'nome',
                key: 'nome',
                ellipsis: true,
                sorter: listingServerSortNoOp,
                sortOrder: sortColumnUi.columnKey === 'nome' ? sortColumnUi.order : undefined,
                render: (_: unknown, record) => <Text strong>{record.nome}</Text>,
            },
            {
                title: 'Estado UAT',
                key: 'uat_signoff_status',
                width: 150,
                sorter: listingServerSortNoOp,
                sortOrder:
                    sortColumnUi.columnKey === 'uat_signoff_status' ? sortColumnUi.order : undefined,
                render: (_: unknown, record) => {
                    const st = normalizeUatSignOffStatus(record.uat_signoff_status);
                    return (
                        <Tag color={getUatSignOffStatusColor(st)}>{getUatSignOffStatusLabel(st)}</Tag>
                    );
                },
            },
            {
                title: 'Sign-off em',
                dataIndex: 'uat_signoff_em',
                key: 'uat_signoff_em',
                width: 180,
                sorter: listingServerSortNoOp,
                sortOrder: sortColumnUi.columnKey === 'uat_signoff_em' ? sortColumnUi.order : undefined,
                render: (v: string | null | undefined, record) => {
                    const actor = getUatSignOffActorNome(record);
                    if (!v && !actor) return <Text type="secondary">—</Text>;
                    return (
                        <div>
                            <div>{formatWhen(v)}</div>
                            {actor ? (
                                <Text type="secondary" style={{ fontSize: 12 }}>
                                    por {actor}
                                </Text>
                            ) : null}
                        </div>
                    );
                },
            },
            {
                title: 'Notas',
                dataIndex: 'uat_signoff_notas',
                key: 'uat_signoff_notas',
                ellipsis: true,
                render: (v: string | null | undefined) =>
                    v ? (
                        <Text type="secondary" style={{ fontSize: 12 }}>
                            {v}
                        </Text>
                    ) : (
                        <Text type="secondary">—</Text>
                    ),
            },
        ];

        return filterTableColumnsByVisibleKeys(allColumns, visibleColumnKeys, ['menu']);
    }, [sortColumnUi, visibleColumnKeys]);

    const exportRows = useMemo(
        () =>
            rows.map((r: any) => ({
                modulo: r.nome ?? '',
                estado_uat: getUatSignOffStatusLabel(r.uat_signoff_status),
                signoff_em: r.uat_signoff_em ? formatWhen(r.uat_signoff_em) : '',
                actor: getUatSignOffActorNome(r) ?? '',
                notas: r.uat_signoff_notas ?? '',
            })),
        [rows],
    );

    const headerActions = (
        <Space wrap size={8} align="center">
            {filtroSalvoAtivo ? (
                <SavedFilterActiveTag
                    nome={filtroSalvoAtivo.nome}
                    dataTestId="projeto-uat-signoff-filtro-salvo-ativo"
                />
            ) : null}
            <ListingPageOptionsButton
                data-testid="projeto-uat-signoff-lista-mais-opcoes"
                expanded={listaMaisOpcoesOpen}
                ariaLabel="Opções"
                tooltipTitle="Colunas visíveis da listagem"
                onClick={() => setListaMaisOpcoesOpen(true)}
            />
            {!isMobile ? (
                <Tooltip
                    title={
                        filtrosComAlgumAtivo
                            ? `Filtros ativos (${filtrosAtivosCount}) — sincronizam com a URL`
                            : 'Filtrar módulos por estado UAT ou nome'
                    }
                >
                    <span style={{ display: 'inline-block' }}>
                        <Badge dot={filtrosComAlgumAtivo} color="geekblue">
                            <ButtonHeaderIcon
                                data-testid="projeto-uat-signoff-abrir-filtros"
                                icon={<Filter size={ICON_SIZE_MD} aria-hidden />}
                                title={filtrosAtivosCount > 0 ? `Filtros (${filtrosAtivosCount})` : 'Filtros'}
                                aria-label="Abrir filtros de UAT"
                                aria-expanded={filtrosModalOpen}
                                aria-haspopup="dialog"
                                onClick={abrirModalFiltros}
                                className={btnHeaderStyles.btnHeaderIcon}
                            />
                        </Badge>
                    </span>
                </Tooltip>
            ) : null}
            {!isMobile ? (
                <Tooltip title={EXPORT_HELP}>
                    <span style={{ display: 'inline-block' }}>
                        <LazyExportButton
                            data={exportRows as unknown as Record<string, unknown>[]}
                            columns={[
                                { key: 'modulo', label: 'Módulo' },
                                { key: 'estado_uat', label: 'Estado UAT' },
                                { key: 'signoff_em', label: 'Sign-off em' },
                                { key: 'actor', label: 'Registrado por' },
                                { key: 'notas', label: 'Notas' },
                            ]}
                            filename={`projeto-${id}-uat-modulos`}
                            title="Exportar UAT por módulo"
                            iconOnly
                            size="large"
                            exportMenuMode="modal"
                            exportHelpText={EXPORT_HELP}
                            className={btnHeaderStyles.btnHeaderIcon}
                        />
                    </span>
                </Tooltip>
            ) : null}
        </Space>
    );

    const acaoTitulo = acaoModal
        ? `${getUatSignOffAcaoLabel(acaoModal.acao)} — ${acaoModal.modulo.nome}`
        : '';

    const showEmptyState = !isLoading && !isError && rows.length === 0;
    const showTableBlock = !isError && rows.length > 0;
    const metricasLoading =
        (isLoading && rows.length === 0) || pendentesLoading || aprovadosLoading || rejeitadosLoading;

    const irParaModulos = useCallback(() => {
        router.push(`/projetos/${id}/estrutura/modulos`);
    }, [router, id]);

    if (!id) return null;

    return (
        <>
            <ProjetoLayout
                projetoId={id}
                pageTitle="UAT por módulo"
                showPageTitleIcon={false}
                titleSection="UAT por módulo"
                breadcrumbItems={[
                    { title: 'Projetos', path: '/projetos' },
                    { title: projeto?.nome || 'Projeto', path: `/projetos/${id}` },
                    { title: 'Desenvolvimento', path: `/projetos/${id}/estrutura/modulos` },
                    { title: 'UAT por módulo' },
                ]}
                headerAction={headerActions}
            >
                <div data-testid="projeto-uat-signoff">
                    <MetricsGrid columns={4} style={{ marginBottom: 15, gap: 15 }}>
                        <MetricCard
                            icon={<ClipboardCheck size={ICON_SIZE_MD} aria-hidden />}
                            label="Total de módulos"
                            value={String(total)}
                            loading={metricasLoading}
                            variant="projetos"
                        />
                        <MetricCard
                            icon={<ClipboardCheck size={ICON_SIZE_MD} aria-hidden />}
                            label="Pendentes"
                            value={String(paginatedPendentes.meta.total ?? 0)}
                            loading={metricasLoading}
                            variant="emAndamento"
                        />
                        <MetricCard
                            icon={<CheckCircle2 size={ICON_SIZE_MD} aria-hidden />}
                            label="Aprovados"
                            value={String(paginatedAprovados.meta.total ?? 0)}
                            loading={metricasLoading}
                            variant="concluidos"
                        />
                        <MetricCard
                            icon={<XCircle size={ICON_SIZE_MD} aria-hidden />}
                            label="Rejeitados"
                            value={String(paginatedRejeitados.meta.total ?? 0)}
                            loading={metricasLoading}
                            variant="bugs"
                        />
                    </MetricsGrid>

                    <ModalFiltrosUatSignOff
                        open={filtrosModalOpen}
                        onClose={() => setFiltrosModalOpen(false)}
                        draft={modalFiltrosDraft}
                        onDraftChange={setModalFiltrosDraft}
                        onAplicar={aplicarFiltrosModal}
                        onLimparRascunho={limparRascunhoFiltros}
                        onLimparTodosFiltros={limparTodosFiltros}
                        onApplySaved={handleApplySavedFilter}
                        modalWidth={filtrosModalLayout.width ?? 640}
                        modalCentered={filtrosModalLayout.centered ?? true}
                        modalClassName={filtrosModalLayout.className}
                        modalZIndex={filtrosModalLayout.zIndex}
                        modalStyles={mergeWaygestFormModalBodyStyles(filtrosModalLayout, {
                            body: { maxHeight: 'min(70vh, calc(100vh - 200px))' },
                        })}
                    />

                    {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="Não foi possível carregar o UAT"
                            description={getUatSignOffErrorMessage(
                                error,
                                'Tente novamente. Se o erro persistir, contate o suporte.',
                            )}
                            onRetry={() => void refetch()}
                            data-testid="projeto-uat-signoff-load-error"
                        />
                    ) : null}

                    {showEmptyState ? (
                        <ListagemEmptyState
                            type={filtrosComAlgumAtivo ? 'warning' : 'info'}
                            icon={<ClipboardCheck size={iconTokenSize.xl} aria-hidden />}
                            message={
                                filtrosComAlgumAtivo
                                    ? 'Nenhum resultado para os filtros'
                                    : 'Não há módulos neste projeto'
                            }
                            description={
                                filtrosComAlgumAtivo
                                    ? 'Ajuste os critérios ou limpe os filtros para voltar a ver os módulos.'
                                    : tipologicoEmptyDescription(
                                          canEditar
                                              ? TIPOLOGICO_EMPTY_DOMAIN.uatSignoff
                                              : 'Não há módulos nesta listagem. Peça acesso para cadastrar se precisar incluir um registro.',
                                      )
                            }
                            ctaLabel={
                                filtrosComAlgumAtivo
                                    ? 'Limpar filtros'
                                    : canEditar
                                      ? 'Ir para módulos'
                                      : undefined
                            }
                            onCta={
                                filtrosComAlgumAtivo
                                    ? limparTodosFiltros
                                    : canEditar
                                      ? irParaModulos
                                      : undefined
                            }
                            extraActions={
                                !filtrosComAlgumAtivo ? (
                                    <ProjetoTipologicoSyncCtas projetoId={id} size="small" />
                                ) : undefined
                            }
                            data-testid="projeto-uat-signoff-empty"
                        />
                    ) : null}

                    {showTableBlock ? (
                        <TableScrollWrapper hint={tabelaScrollHint}>
                            <LazyDataTable
                                rowKey="id"
                                columns={columns}
                                data={rows}
                                paginatedData={paginatedData}
                                loading={isLoading}
                                fetching={isFetching}
                                onRefresh={() => void refetch()}
                                rowSelection={rowSelection}
                                onChange={handleTableChange}
                                onRow={handleRowProps}
                                autoMobileFromColumns={{
                                    testIdPrefix: 'projeto-uat-signoff',
                                    listHeading: 'Lista de módulos UAT',
                                    getFallbackTitle: (record: any) =>
                                        record.nome?.trim() || `Módulo ${record.id}`,
                                    getSubtitle: (record: any) =>
                                        getUatSignOffStatusLabel(
                                            normalizeUatSignOffStatus(record.uat_signoff_status),
                                        ),
                                    excludeFieldKeys: ['nome', 'uat_signoff_status', 'menu', 'acoes'],
                                    onCardClick: (item) => setOpcoesItem(item),
                                    onOpenOptions: (item) => setOpcoesItem(item),
                                }}
                            />
                        </TableScrollWrapper>
                    ) : null}

                    <ModalOpcoesUatModulo
                        open={opcoesItem !== null}
                        onClose={() => setOpcoesItem(null)}
                        item={opcoesItem}
                        onAcao={openAcao}
                        onVerModulo={(modulo) => {
                            router.push(`/projetos/${id}/estrutura/modulos/${modulo.id}`);
                        }}
                    />

                    <Modal
                        title={acaoTitulo}
                        open={acaoModal !== null}
                        onCancel={() => {
                            setAcaoModal(null);
                            form.resetFields();
                        }}
                        footer={
                            <div className={waygestFormModalFooterClassName}>
                                <Button
                                    onClick={() => {
                                        setAcaoModal(null);
                                        form.resetFields();
                                    }}
                                >
                                    Cancelar
                                </Button>
                                <Button
                                    type="primary"
                                    danger={acaoModal?.acao === 'rejeitar'}
                                    htmlType="submit"
                                    form={FORM_ID}
                                    loading={acaoMutation.isPending}
                                >
                                    Confirmar
                                </Button>
                            </div>
                        }
                        width={formModalLayout.width ?? 520}
                        centered={formModalLayout.centered ?? true}
                        className={formModalLayout.className}
                        styles={formModalLayout.styles}
                        zIndex={formModalLayout.zIndex}
                        destroyOnHidden
                        data-testid="projeto-uat-signoff-acao-modal"
                    >
                        {acaoModal ? (
                            <>
                                <Paragraph type="secondary" style={{ marginBottom: 16 }}>
                                    Estado atual:{' '}
                                    <Tag
                                        color={getUatSignOffStatusColor(
                                            normalizeUatSignOffStatus(
                                                acaoModal.modulo.uat_signoff_status,
                                            ),
                                        )}
                                    >
                                        {getUatSignOffStatusLabel(
                                            normalizeUatSignOffStatus(
                                                acaoModal.modulo.uat_signoff_status,
                                            ),
                                        )}
                                    </Tag>
                                    {acaoModal.acao === 'aprovar'
                                        ? ' — confirme que o key user homologou o módulo.'
                                        : null}
                                    {acaoModal.acao === 'reabrir'
                                        ? ' — o rasto de assinatura será limpo e o estado volta a pendente.'
                                        : null}
                                </Paragraph>
                                <Form
                                    id={FORM_ID}
                                    form={form}
                                    layout="vertical"
                                    onFinish={(values) => {
                                        if (!acaoModal) return;
                                        acaoMutation.mutate({
                                            moduloId: acaoModal.modulo.id,
                                            status: uatSignOffAcaoToStatus(acaoModal.acao),
                                            notas: (values.notas as string)?.trim() || null,
                                        });
                                    }}
                                >
                                    <FormTextarea
                                        name="notas"
                                        label="Notas / evidência"
                                        rows={3}
                                        required={acaoModal.acao === 'rejeitar'}
                                        placeholder={
                                            acaoModal.acao === 'rejeitar'
                                                ? 'Motivo da rejeição (obrigatório)'
                                                : 'Observações opcionais para o rasto comercial'
                                        }
                                        maxLength={2000}
                                        showCount
                                    />
                                </Form>
                            </>
                        ) : null}
                    </Modal>

                    <Modal
                        title="Rejeitar módulos selecionados"
                        open={bulkRejeitarOpen}
                        onCancel={() => {
                            setBulkRejeitarOpen(false);
                            form.resetFields();
                        }}
                        footer={
                            <div className={waygestFormModalFooterClassName}>
                                <Button
                                    onClick={() => {
                                        setBulkRejeitarOpen(false);
                                        form.resetFields();
                                    }}
                                >
                                    Cancelar
                                </Button>
                                <Button
                                    type="primary"
                                    danger
                                    htmlType="submit"
                                    form="projeto-uat-signoff-bulk-rejeitar-form"
                                    loading={bulkBusy}
                                >
                                    Rejeitar
                                </Button>
                            </div>
                        }
                        width={formModalLayout.width ?? 520}
                        centered={formModalLayout.centered ?? true}
                        className={formModalLayout.className}
                        styles={formModalLayout.styles}
                        zIndex={formModalLayout.zIndex}
                        destroyOnHidden
                        data-testid="projeto-uat-signoff-bulk-rejeitar-modal"
                    >
                        <Paragraph type="secondary">
                            Informe o motivo da rejeição para {selectedIds.length} módulo(s). O texto
                            entra no rasto comercial de cada módulo.
                        </Paragraph>
                        <Form
                            id="projeto-uat-signoff-bulk-rejeitar-form"
                            form={form}
                            layout="vertical"
                            onFinish={(values) => {
                                const notas = (values.notas as string)?.trim() || '';
                                setBulkRejeitarOpen(false);
                                void execBulkStatus('rejeitado', notas);
                            }}
                        >
                            <FormTextarea
                                name="notas"
                                label="Motivo da rejeição"
                                rows={3}
                                required
                                placeholder="Motivo da rejeição (obrigatório)"
                                maxLength={2000}
                                showCount
                            />
                        </Form>
                    </Modal>
                </div>
            </ProjetoLayout>

            <ListingPageOptionsModal
                open={listaMaisOpcoesOpen}
                onClose={() => setListaMaisOpcoesOpen(false)}
                subtitle="UAT por módulo"
                onColunasVisiveis={() => setColunasVisiveisModalOpen(true)}
                data-testid="projeto-uat-signoff-opcoes-pagina-modal"
                aria-label="Opções da listagem de UAT por módulo"
            />

            <ListingColumnCustomizeModal
                open={colunasVisiveisModalOpen}
                onClose={() => setColunasVisiveisModalOpen(false)}
                catalog={UAT_SIGNOFF_LIST_COLUMN_CATALOG}
                value={visibleColumnKeys}
                order={columnOrder}
                onApply={setVisibleColumnKeys}
                data-testid="projeto-uat-signoff-lista-customizar-colunas-modal"
            />

            <ListingBulkFabModal
                showFab={selectedRowKeys.length > 0}
                modalOpen={modalAcoesMassaOpen}
                onOpenModal={() => setModalAcoesMassaOpen(true)}
                onCloseModal={() => setModalAcoesMassaOpen(false)}
                busy={bulkBusy}
                modalTitle="Ações em massa"
                modalSubtitle={`${selectedRowKeys.length} módulo(s) selecionado(s)`}
                actions={acoesMassaModal}
                fabAriaLabel={`Ações em massa — ${selectedRowKeys.length} módulo(s) selecionado(s)`}
                data-testid-fab="projeto-uat-signoff-fab-selecao-acoes"
                data-testid-modal="projeto-uat-signoff-modal-acoes-massa"
            />

            {selectedRowKeys.length === 0 && !permsLoading && canEditar ? (
                <ListPageCreateFloatButton
                    data-testid="projeto-uat-signoff-fab-novo-modulo"
                    tooltip={{
                        title: 'Cadastrar módulo — o sign-off UAT aplica-se a módulos já existentes',
                    }}
                    onClick={irParaModulos}
                />
            ) : null}

            {isMobile ? (
                <MobilePageActionBar
                    onOpenFilters={abrirModalFiltros}
                    activeFiltersCount={filtrosAtivosCount}
                    filterButtonLabel="Filtros"
                    onRefresh={() => void refetch()}
                    refreshLoading={isFetching}
                    hideOpcoes
                />
            ) : null}
        </>
    );
}
