'use client';

import { keepPreviousData } from '@tanstack/react-query';
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { usePathname, useRouter, useSearchParams } from 'next/navigation';
import { Alert, Badge, Button, Space, Tag, Tooltip, Typography } from 'antd';
import type { ColumnsType } from 'antd/es/table';
import { Ban, BookOpen, CheckCircle2, FileText, Filter, GitBranch, Pencil, Sparkles, Trash2 } from 'lucide-react';
import { ICON_SIZE_MD, iconTokenSize } from '@/components/icons';
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 {
    ListPageCreateFloatButton,
    ListagemEmptyState,
    ListagemListaError,
    ListingActionsColumnCell,
    ListingBulkFabModal,
    ListingColumnCustomizeModal,
    ListingPageOptionsButton,
    ListingPageOptionsModal,
    SavedFilterActiveTag,
    buildListingRowInteractiveProps,
    filterTableColumnsByVisibleKeys,
    listingServerSortNoOp,
    useListingMobileScrollHint,
    useListingVisibleColumns,
} from '@/components/listings';
import type { ModalOpcaoAction } from '@/components/ModalOpcoesBase';
import btnHeaderStyles from '@/components/ui/buttons/ButtonHeaderIcon/ButtonHeaderIcon.module.scss';
import { ModuleRelatedLinksPanel } from '@/components/navigation/ModuleRelatedLinksPanel';
import {
    ProjetoTipologicoSyncCtas,
    tipologicoEmptyDescription,
    TIPOLOGICO_EMPTY_DOMAIN,
} from '@/features/projetos/projeto-tipologico-empty-state';
import { useListingFilteredRowSelection } from '@/hooks/useListingFilteredRowSelection';
import { useListingMobileChrome } from '@/components/mobile';
import { useModuleRelatedLinks } from '@/hooks/useModuleRelatedLinks';
import { useMutationCache } from '@/hooks/useMutationCache';
import { useQueryCache } from '@/hooks/useQueryCache';
import {
    listingSortColumnUi,
    useServerSideListingTableChange,
    type ServerSideSortState,
} from '@/hooks/useServerSideListingTableChange';
import {
    mergeWaygestFormModalBodyStyles,
    useWaygestFormModalProps,
} from '@/hooks/useWaygestFormModalProps';
import { API_ENDPOINTS } from '@/lib/api/endpoints';
import apiClient from '@/lib/api/client';
import { queryKeys } from '@/lib/cache/queryKeys';
import { getLaravelApiErrorMessage } from '@/lib/api/laravelApiErrorMessage';
import { confirmDialog } from '@/lib/feedback/confirmDialog';
import { message } from '@/lib/feedback/message';
import { notifyApiError } from '@/lib/feedback/notifyApiError';
import { projetosProjetoCanonical } from '@/lib/routes/projetosProjetoCanonical';
import { listingTableVirtualScrollProps } from '@/lib/listings/listingTableVirtualScrollProps';
import { useProjetoWriteGates } from '@/features/projetos/hooks/useProjetoWriteGates';
import { ModalCasoUsoForm } from './ModalCasoUsoForm';
import { ModalSugerirCasosUsoIa } from './ModalSugerirCasosUsoIa';
import { ModalFiltrosCasosUso } from './components/ModalFiltrosCasosUso';
import { ModalOpcoesCasoUso } from './ModalOpcoesCasoUso';
import {
    CASO_USO_STATUS_COLOR,
    labelCasoUsoNivel,
    labelCasoUsoPrioridade,
    labelCasoUsoStatus,
} from './casoUsoDisplay';
import { useCasosUsoListaUrlSync } from './hooks/useCasosUsoListaUrlSync';
import {
    CASOS_USO_LIST_MODULE_KEY,
    casosUsoApplySavedPayload,
} from './utils/casosUsoFiltrosPayload';
import { CASOS_USO_LIST_COLUMN_CATALOG } from './utils/casosUsoListColumnCatalog';
import {
    CASOS_USO_LISTA_URL_DEFAULTS,
    type CasosUsoListaFiltrosApi,
    type CasosUsoListaSortKey,
    type CasosUsoListaUrlSnapshot,
} from './utils/casosUsoListaFiltersUrl';
import type { CasoUso, CasoUsoSugestaoIa, CasosUsoSugerirComIaResponse } from './types';

const PLANEJAMENTO_CASOS_USO_RELATED_SURFACE = 'projetos.planejamento.casos-uso.list' as const;
const BULK_CONFIRM_OPEN_DELAY_MS = 120;
const EXPORT_HELP =
    'Exporta apenas os casos de uso visíveis nesta página (listagem paginada no servidor).';

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

type Envelope = { data: CasoUso[]; meta?: { total?: number; current_page?: number; per_page?: number; last_page?: number } };
type Resumo = {
    total: number;
    rascunho: number;
    em_revisao: number;
    aprovado: number;
    obsoleto: number;
    sem_passos: number;
};

export type ProjetoCasosUsoListScreenProps = {
    projetoId: string;
    initialCreate?: boolean;
};

function rotuloAriaOpcoes(record: CasoUso): string {
    const titulo = record.titulo?.trim();
    return titulo ? `Opções: ${record.codigo} — ${titulo}` : `Opções: ${record.codigo}`;
}

export function ProjetoCasosUsoListScreen({
    projetoId,
    initialCreate = false,
}: ProjetoCasosUsoListScreenProps) {
    const pathname = usePathname() ?? '';
    const searchParams = useSearchParams();
    const router = useRouter();
    const { canCriar, canEditar, tooltipSemPermissao } = useProjetoWriteGates();
    const { isMobile } = useListingMobileChrome();
    const filtrosModalLayout = useWaygestFormModalProps();
    const { modalActions: relatedNavActions } = useModuleRelatedLinks({
        surfaceKey: PLANEJAMENTO_CASOS_USO_RELATED_SURFACE,
        pagePrefix: 'projeto-planejamento-casos-uso',
        projetoId,
    });

    const [currentPage, setCurrentPage] = useState(CASOS_USO_LISTA_URL_DEFAULTS.page);
    const [pageSize, setPageSize] = useState(CASOS_USO_LISTA_URL_DEFAULTS.perPage);
    const [tableSort, setTableSort] = useState<ServerSideSortState>(CASOS_USO_LIST_DEFAULT_SORT);
    const [filtros, setFiltros] = useState<CasosUsoListaFiltrosApi>({});
    const [filtrosModalOpen, setFiltrosModalOpen] = useState(false);
    const [modalFiltrosDraft, setModalFiltrosDraft] = useState<CasosUsoListaFiltrosApi>({});
    const [draftSortColumn, setDraftSortColumn] = useState<CasosUsoListaSortKey>(
        CASOS_USO_LISTA_URL_DEFAULTS.sortColumn,
    );
    const [draftSortDesc, setDraftSortDesc] = useState(CASOS_USO_LISTA_URL_DEFAULTS.sortDesc);
    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<CasoUso | null>(null);
    const [formOpen, setFormOpen] = useState(false);
    const [iaModalOpen, setIaModalOpen] = useState(false);
    const [iaSugestoes, setIaSugestoes] = useState<CasoUsoSugestaoIa[]>([]);
    const [iaError, setIaError] = useState<string | null>(null);

    const { visibleKeys: visibleColumnKeys, columnOrder, setVisibleKeys: setVisibleColumnKeys } =
        useListingVisibleColumns(CASOS_USO_LIST_MODULE_KEY, CASOS_USO_LIST_COLUMN_CATALOG);

    const listParams = useMemo(() => {
        const sortColumn = tableSort?.columnKey ?? CASOS_USO_LIST_DEFAULT_SORT.columnKey;
        const sortDirection =
            (tableSort?.order ?? CASOS_USO_LIST_DEFAULT_SORT.order) === 'descend' ? 'desc' : 'asc';
        return {
            page: currentPage,
            per_page: pageSize,
            sort_by: sortColumn,
            sort_direction: sortDirection,
            ...(filtros.status && { status: filtros.status }),
            ...(filtros.prioridade && { prioridade: filtros.prioridade }),
            ...(filtros.nivel && { nivel: filtros.nivel }),
            ...(filtros.search?.trim() && { search: filtros.search.trim() }),
        };
    }, [currentPage, pageSize, tableSort, filtros]);

    const {
        data,
        isLoading,
        isError,
        refetch,
        isFetching,
    } = useQueryCache<Envelope>({
        queryKey: queryKeys.projetos.casosUso(projetoId, listParams),
        endpoint: API_ENDPOINTS.projetos.casosUso.index(projetoId),
        params: listParams,
        staleTime: 30_000,
        placeholderData: keepPreviousData,
    });

    const { data: resumo } = useQueryCache<Resumo>({
        queryKey: queryKeys.projetos.casosUsoResumo(projetoId),
        endpoint: API_ENDPOINTS.projetos.casosUso.resumo(projetoId),
        unwrapApiEnvelope: true,
    });

    const rows = data?.data ?? [];
    const total = data?.meta?.total ?? 0;
    const paginatedData = useMemo(
        () => ({
            data: rows,
            meta: {
                current_page: data?.meta?.current_page ?? currentPage,
                last_page: data?.meta?.last_page ?? 1,
                per_page: data?.meta?.per_page ?? pageSize,
                total,
            },
        }),
        [rows, data?.meta, currentPage, pageSize, total],
    );

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

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

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

    const onHydrateFromUrl = useCallback((snapshot: CasosUsoListaUrlSnapshot) => {
        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;
    }, []);

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

    /** Deep link create: `initialCreate`, `?openModal=create` ou `?novo=1` — respeita `canCriar`. */
    useEffect(() => {
        const novo = searchParams?.get('novo');
        const wantsFromQuery =
            searchParams?.get('openModal') === 'create' ||
            novo === '1' ||
            novo === 'true';
        const wantsCreate = Boolean(initialCreate) || wantsFromQuery;
        if (!wantsCreate) {
            return;
        }

        const clearCreateQuery = () => {
            if (!wantsFromQuery) {
                return;
            }
            const p = new URLSearchParams(searchParams?.toString() ?? '');
            p.delete('openModal');
            p.delete('novo');
            const qs = p.toString();
            const listPath = pathname.replace(/\/novo\/?$/, '');
            router.replace(qs ? `${listPath}?${qs}` : listPath, { scroll: false });
        };

        if (!canCriar) {
            clearCreateQuery();
            return;
        }

        setFormOpen(true);
        clearCreateQuery();
    }, [initialCreate, searchParams, canCriar, pathname, router]);

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

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

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

    const sortColumnUi = listingSortColumnUi(tableSort, CASOS_USO_LIST_DEFAULT_SORT);

    const { mutateAsync: bulk } = useMutationCache<
        { data: { processados: number; erros: string[] } },
        { acao: string; ids: number[] }
    >({
        endpoint: API_ENDPOINTS.projetos.casosUso.bulk(projetoId),
        method: 'POST',
        invalidateQueries: [queryKeys.projetos.casosUso(projetoId), queryKeys.projetos.casosUsoResumo(projetoId)],
    });

    const sugerirIaMutation = useMutationCache<CasosUsoSugerirComIaResponse, Record<string, never>>({
        endpoint: API_ENDPOINTS.projetos.casosUso.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 casos de uso.';
            setIaError(msg);
            notifyApiError(error, msg, 'planejamento-casos-uso-ia');
        },
    });

    const aplicarSugestoesMutation = useMutationCache<
        { message?: string },
        { casos_uso: CasoUsoSugestaoIa[] }
    >({
        endpoint: API_ENDPOINTS.projetos.casosUso.aplicarSugestoes(projetoId),
        method: 'POST',
        invalidateQueries: [queryKeys.projetos.casosUso(projetoId), queryKeys.projetos.casosUsoResumo(projetoId)],
        onSuccess: (data) => {
            message.success(data.message || 'Casos de uso inseridos com sucesso!');
            setIaModalOpen(false);
            setIaSugestoes([]);
            void refetch();
        },
        onError: (error: unknown) => {
            notifyApiError(error, 'Erro ao inserir os casos de uso selecionados.', 'planejamento-casos-uso-ia');
        },
    });

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

    const irParaGestao = useCallback(
        (item: CasoUso) => {
            router.push(projetosProjetoCanonical.planejamentoCasosDeUsoDetalhe(projetoId, item.id));
        },
        [router, projetoId],
    );

    const execBulk = useCallback(
        async (acao: 'obsoletar' | 'excluir') => {
            if (selectedIds.length === 0) {
                message.warning('Selecione pelo menos um caso de uso.');
                return;
            }
            setBulkBusy(true);
            try {
                const r = await bulk({ acao, ids: selectedIds });
                clearSelection();
                setOpcoesItem(null);
                const n = r?.data?.processados ?? 0;
                message.success(
                    acao === 'obsoletar'
                        ? `${n} registro(s) obsoletados.`
                        : `${n} registro(s) excluídos.`,
                );
                void refetch();
            } catch (e) {
                message.error(getLaravelApiErrorMessage(e));
            } finally {
                setBulkBusy(false);
            }
        },
        [selectedIds, bulk, clearSelection, refetch],
    );

    const promptBulkObsoletar = useCallback(() => {
        const n = selectedIds.length;
        void confirmDialog({
            title: 'Obsoletar selecionados?',
            content: `${n} caso(s) de uso serão marcados como obsoletos.`,
            okText: 'Obsoletar',
            cancelText: 'Cancelar',
            onOk: () => execBulk('obsoletar'),
        });
    }, [selectedIds.length, execBulk]);

    const promptBulkExcluir = useCallback(() => {
        const n = selectedIds.length;
        void confirmDialog({
            title: 'Excluir selecionados?',
            content: `${n} caso(s) de uso serão excluídos. Casos aprovados precisam ser obsoletados antes.`,
            okText: 'Excluir',
            cancelText: 'Cancelar',
            onOk: () => execBulk('excluir'),
        });
    }, [selectedIds.length, execBulk]);

    const acoesMassaModal = useMemo((): ModalOpcaoAction[] => {
        const n = selectedIds.length;
        return [
            {
                key: 'obsoletar',
                label: `Obsoletar selecionados${n > 0 ? ` (${n})` : ''}`,
                icon: <Ban size={ICON_SIZE_MD} aria-hidden />,
                disabled: bulkBusy || n === 0 || !canEditar,
                onClick: () => {
                    setModalAcoesMassaOpen(false);
                    window.setTimeout(() => promptBulkObsoletar(), 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 || !canEditar,
                onClick: () => {
                    setModalAcoesMassaOpen(false);
                    window.setTimeout(() => promptBulkExcluir(), BULK_CONFIRM_OPEN_DELAY_MS);
                },
            },
        ];
    }, [bulkBusy, selectedIds.length, canEditar, promptBulkObsoletar, promptBulkExcluir]);

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

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

    const resumoFiltrosAplicados = useMemo(() => {
        const partes: string[] = [];
        if (filtros.status) partes.push(`Status: ${labelCasoUsoStatus(filtros.status)}`);
        if (filtros.prioridade) partes.push(`Prioridade: ${labelCasoUsoPrioridade(filtros.prioridade)}`);
        if (filtros.nivel) partes.push(`Nível: ${labelCasoUsoNivel(filtros.nivel)}`);
        const q = filtros.search?.trim();
        if (q) partes.push(`Pesquisa: "${q}"`);
        return partes.length ? partes.join(' · ') : '';
    }, [filtros]);

    const abrirModalFiltros = useCallback(() => {
        setModalFiltrosDraft({ ...filtros });
        setDraftSortColumn(
            (tableSort?.columnKey as CasosUsoListaSortKey) ?? CASOS_USO_LISTA_URL_DEFAULTS.sortColumn,
        );
        setDraftSortDesc((tableSort?.order ?? CASOS_USO_LIST_DEFAULT_SORT.order) === 'descend');
        setFiltrosModalOpen(true);
    }, [filtros, tableSort]);

    const aplicarFiltrosModal = useCallback(() => {
        setFiltros({ ...modalFiltrosDraft });
        setTableSort({
            columnKey: draftSortColumn,
            order: draftSortDesc ? 'descend' : 'ascend',
        });
        setCurrentPage(1);
        setFiltrosModalOpen(false);
        clearSelection();
    }, [modalFiltrosDraft, draftSortColumn, draftSortDesc, clearSelection]);

    const handleApplySavedFilter = useCallback(
        (payload: unknown, meta: { nome: string }) => {
            const parsed = casosUsoApplySavedPayload(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 abrirOpcoes = useCallback((record: CasoUso) => {
        setOpcoesItem(record);
    }, []);

    const handleRowProps = useCallback(
        (record: CasoUso) =>
            buildListingRowInteractiveProps(record, {
                onAtivate: abrirOpcoes,
                getRowSummary: (row) =>
                    [row.codigo, row.titulo?.trim()].filter(Boolean).join(' — ') || `Caso de uso ${row.id}`,
                ariaLabelWithSummary: (summary) =>
                    `Caso de uso: ${summary}. Enter ou espaço abre o menu de opções.`,
                ariaLabelFallback: 'Caso de uso. Enter ou espaço abre o menu de opções.',
            }),
        [abrirOpcoes],
    );

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

    const columns: ColumnsType<CasoUso> = useMemo(() => {
        const allColumns: ColumnsType<CasoUso> = [
            {
                title: '',
                key: 'acoes',
                width: 52,
                align: 'center',
                fixed: 'left',
                onCell: () => ({ onClick: (e: React.MouseEvent) => e.stopPropagation() }),
                render: (_: unknown, record: CasoUso) => (
                    <ListingActionsColumnCell
                        ariaLabel={rotuloAriaOpcoes(record)}
                        onOpen={() => setOpcoesItem(record)}
                    />
                ),
            },
            {
                title: 'Código',
                dataIndex: 'codigo',
                key: 'codigo',
                width: 110,
                sorter: listingServerSortNoOp,
                sortOrder: sortColumnUi.columnKey === 'codigo' ? sortColumnUi.order : undefined,
            },
            {
                title: 'Título',
                dataIndex: 'titulo',
                key: 'titulo',
                ellipsis: true,
                sorter: listingServerSortNoOp,
                sortOrder: sortColumnUi.columnKey === 'titulo' ? sortColumnUi.order : undefined,
            },
            {
                title: 'Status',
                dataIndex: 'status',
                key: 'status',
                width: 140,
                sorter: listingServerSortNoOp,
                sortOrder: sortColumnUi.columnKey === 'status' ? sortColumnUi.order : undefined,
                render: (status: string) => (
                    <Tag color={CASO_USO_STATUS_COLOR[status] ?? 'default'}>{labelCasoUsoStatus(status)}</Tag>
                ),
            },
            {
                title: 'Prioridade',
                dataIndex: 'prioridade',
                key: 'prioridade',
                width: 120,
                sorter: listingServerSortNoOp,
                sortOrder: sortColumnUi.columnKey === 'prioridade' ? sortColumnUi.order : undefined,
                render: (v: string) => labelCasoUsoPrioridade(v),
            },
            {
                title: 'Nível',
                dataIndex: 'nivel',
                key: 'nivel',
                width: 120,
                sorter: listingServerSortNoOp,
                sortOrder: sortColumnUi.columnKey === 'nivel' ? sortColumnUi.order : undefined,
                render: (v: string) => labelCasoUsoNivel(v),
            },
            {
                title: 'Passos',
                dataIndex: 'passos_count',
                key: 'passos_count',
                width: 90,
                render: (n?: number) => n ?? 0,
            },
        ];
        return filterTableColumnsByVisibleKeys(allColumns, visibleColumnKeys, ['menu']);
    }, [sortColumnUi, visibleColumnKeys]);

    const exportRows = useMemo(
        () =>
            rows.map((r: any) => ({
                codigo: r.codigo,
                titulo: r.titulo,
                status: labelCasoUsoStatus(r.status),
                prioridade: labelCasoUsoPrioridade(r.prioridade),
                nivel: labelCasoUsoNivel(r.nivel),
                passos: r.passos_count ?? 0,
            })),
        [rows],
    );

    const postStatus = async (item: CasoUso, kind: 'aprovar' | 'reabrir' | 'obsoletar') => {
        const url =
            kind === 'aprovar'
                ? API_ENDPOINTS.projetos.casosUso.aprovar(projetoId, item.id)
                : kind === 'reabrir'
                  ? API_ENDPOINTS.projetos.casosUso.reabrir(projetoId, item.id)
                  : API_ENDPOINTS.projetos.casosUso.obsoletar(projetoId, item.id);
        try {
            await apiClient.post(url);
            message.success('Status atualizado.');
            void refetch();
        } catch (e) {
            message.error(getLaravelApiErrorMessage(e));
        }
    };

    const excluirUm = (item: CasoUso) => {
        void confirmDialog({
            title: 'Excluir caso de uso?',
            content: `${item.codigo} será excluído. Casos aprovados precisam ser obsoletados antes.`,
            okText: 'Excluir',
            cancelText: 'Cancelar',
            onOk: async () => {
                try {
                    await apiClient.delete(API_ENDPOINTS.projetos.casosUso.destroy(projetoId, item.id));
                    message.success('Caso de uso excluído.');
                    void refetch();
                } catch (e) {
                    message.error(getLaravelApiErrorMessage(e));
                }
            },
        });
    };

    const abrirNovo = () => setFormOpen(true);
    const fecharForm = () => {
        setFormOpen(false);
        const listPath = projetosProjetoCanonical.planejamentoCasosDeUso(projetoId);
        if (typeof window !== 'undefined' && window.location.pathname !== listPath) {
            router.replace(listPath);
        }
    };

    const showEmptyState = !isLoading && !isError && rows.length === 0;
    const showTableBlock = !isError && rows.length > 0;

    const headerActions = (
        <Space wrap size={8} align="center">
            {filtroSalvoAtivo ? (
                <SavedFilterActiveTag
                    nome={filtroSalvoAtivo.nome}
                    dataTestId="projeto-casos-uso-filtro-salvo-ativo"
                />
            ) : null}
            <ListingPageOptionsButton
                data-testid="projeto-casos-uso-lista-mais-opcoes"
                expanded={listaMaisOpcoesOpen}
                ariaLabel="Opções"
                tooltipTitle="Colunas visíveis da listagem"
                onClick={() => setListaMaisOpcoesOpen(true)}
            />
            <Tooltip
                title={
                    filtrosComAlgumAtivo
                        ? `Filtros ativos (${filtrosAtivosCount}) — sincronizam com a URL`
                        : 'Filtrar por status, prioridade, nível ou texto'
                }
            >
                <span style={{ display: 'inline-block' }}>
                    <Badge dot={filtrosComAlgumAtivo} color="geekblue">
                        <ButtonHeaderIcon
                            data-testid="projeto-casos-uso-abrir-filtros"
                            icon={<Filter size={ICON_SIZE_MD} aria-hidden />}
                            title={filtrosAtivosCount > 0 ? `Filtros (${filtrosAtivosCount})` : 'Filtros'}
                            aria-label="Abrir filtros de casos de uso"
                            aria-expanded={filtrosModalOpen}
                            aria-haspopup="dialog"
                            onClick={abrirModalFiltros}
                            className={btnHeaderStyles.btnHeaderIcon}
                        />
                    </Badge>
                </span>
            </Tooltip>
            <Tooltip title={EXPORT_HELP}>
                <span style={{ display: 'inline-block' }}>
                    <LazyExportButton
                        data={exportRows 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' },
                            { key: 'nivel', label: 'Nível' },
                            { key: 'passos', label: 'Passos' },
                        ]}
                        filename={`projeto-${projetoId}-casos-de-uso`}
                        title="Exportar casos de uso"
                        iconOnly
                        size="large"
                        exportMenuMode="modal"
                        exportHelpText={EXPORT_HELP}
                        className={btnHeaderStyles.btnHeaderIcon}
                    />
                </span>
            </Tooltip>
            {canEditar ? (
                <Tooltip title="Analisar o projeto e sugerir casos de uso com IA">
                    <span style={{ display: 'inline-block' }}>
                        <ButtonHeaderIcon
                            data-testid="planejamento-casos-uso-sugerir-ia"
                            icon={<Sparkles size={ICON_SIZE_MD} aria-hidden />}
                            title="Sugerir com IA"
                            aria-label="Sugerir casos de uso com IA"
                            onClick={abrirSugerirIa}
                            className={btnHeaderStyles.btnHeaderIcon}
                        />
                    </span>
                </Tooltip>
            ) : null}
        </Space>
    );

    return (
        <>
            <ProjetoLayout
                projetoId={projetoId}
                pageTitle="Casos de uso"
                showPageTitleIcon={false}
                titleSection="Casos de uso"
                headerAction={headerActions}
            >
                <MetricsGrid columns={4} style={{ marginBottom: 15, gap: 15 }}>
                    <MetricCard
                        icon={<BookOpen size={ICON_SIZE_MD} />}
                        label="Total"
                        value={resumo?.total ?? total}
                        variant="projetos"
                    />
                    <MetricCard
                        icon={<Pencil size={ICON_SIZE_MD} />}
                        label="Rascunho"
                        value={resumo?.rascunho ?? 0}
                        variant="planejamento"
                    />
                    <MetricCard
                        icon={<CheckCircle2 size={ICON_SIZE_MD} />}
                        label="Aprovados"
                        value={resumo?.aprovado ?? 0}
                        variant="concluidos"
                    />
                    <MetricCard
                        icon={<FileText size={ICON_SIZE_MD} />}
                        label="Sem passos"
                        value={resumo?.sem_passos ?? 0}
                        variant="pausados"
                    />
                </MetricsGrid>

                <ModalFiltrosCasosUso
                    open={filtrosModalOpen}
                    onClose={() => setFiltrosModalOpen(false)}
                    draft={modalFiltrosDraft}
                    onDraftChange={setModalFiltrosDraft}
                    draftSortColumn={draftSortColumn}
                    draftSortDesc={draftSortDesc}
                    onDraftSortChange={({ sortColumn, sortDesc }) => {
                        setDraftSortColumn(sortColumn);
                        setDraftSortDesc(sortDesc);
                    }}
                    onAplicar={aplicarFiltrosModal}
                    onLimparRascunho={() => {
                        setModalFiltrosDraft({});
                        setDraftSortColumn(CASOS_USO_LISTA_URL_DEFAULTS.sortColumn);
                        setDraftSortDesc(CASOS_USO_LISTA_URL_DEFAULTS.sortDesc);
                    }}
                    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 os casos de uso."
                        description="Verifique a conexão e tente novamente."
                        onRetry={() => void refetch()}
                    />
                ) : null}

                {showEmptyState ? (
                    <ListagemEmptyState
                        type={filtrosComAlgumAtivo ? 'warning' : 'info'}
                        compact={isMobile}
                        icon={<BookOpen size={iconTokenSize.xl} aria-hidden />}
                        message={
                            filtrosComAlgumAtivo ? 'Nenhum resultado para os filtros' : 'Nenhum caso de uso'
                        }
                        description={
                            filtrosComAlgumAtivo
                                ? 'Ajuste os critérios ou limpe os filtros para voltar a ver os casos de uso.'
                                : tipologicoEmptyDescription(TIPOLOGICO_EMPTY_DOMAIN.casosDeUso)
                        }
                        ctaLabel={
                            filtrosComAlgumAtivo ? 'Limpar filtros' : canCriar ? 'Novo caso de uso' : undefined
                        }
                        onCta={filtrosComAlgumAtivo ? limparTodosFiltros : canCriar ? abrirNovo : undefined}
                        secondaryCtaLabel={
                            !filtrosComAlgumAtivo && canEditar ? 'Sugerir com IA' : undefined
                        }
                        onSecondaryCta={
                            !filtrosComAlgumAtivo && canEditar ? abrirSugerirIa : undefined
                        }
                        extraActions={
                            !filtrosComAlgumAtivo ? (
                                <ProjetoTipologicoSyncCtas projetoId={projetoId} size="small" />
                            ) : undefined
                        }
                        data-testid="projeto-casos-uso-empty"
                    />
                ) : null}

                {showTableBlock ? (
                    <TableScrollWrapper hint={tabelaScrollHint}>
                        <LazyDataTable
                            rowKey="id"
                            columns={columns}
                            data={rows}
                            paginatedData={paginatedData}
                            loading={isLoading}
                            fetching={isFetching}
                            onRefresh={() => void refetch()}
                            rowSelection={canEditar ? rowSelection : undefined}
                            onChange={handleTableChange}
                            onRow={handleRowProps}
                            {...listingTableVirtualScrollProps(rows.length)}
                            autoMobileFromColumns={{
                                testIdPrefix: 'planejamento-casos-uso',
                                listHeading: 'Lista de casos de uso',
                                getFallbackTitle: (record: any) =>
                                    record.titulo?.trim() || `Caso de uso ${record.id}`,
                                getSubtitle: (record: any) =>
                                    [record.codigo, record.prioridade ? labelCasoUsoPrioridade(record.prioridade) : null]
                                        .filter(Boolean)
                                        .join(' · ') || undefined,
                                excludeFieldKeys: ['titulo', 'codigo'],
                                onOpenOptions: (item) => setOpcoesItem(item),
                            }}
                        />
                    </TableScrollWrapper>
                ) : null}

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

                {!isLoading ? (
                    <ModuleRelatedLinksPanel
                        surfaceKey={PLANEJAMENTO_CASOS_USO_RELATED_SURFACE}
                        variant="footer"
                        pagePrefix="projeto-planejamento-casos-uso"
                        projetoId={projetoId}
                    />
                ) : null}

                <ModalOpcoesCasoUso
                    open={opcoesItem !== null}
                    onClose={() => setOpcoesItem(null)}
                    item={opcoesItem}
                    onVer={irParaGestao}
                    onEditar={canEditar ? irParaGestao : undefined}
                    onAprovar={
                        canEditar
                            ? (item) =>
                                  void confirmDialog({
                                      title: 'Aprovar caso de uso?',
                                      content: 'É necessário ter pelo menos um passo principal.',
                                      okText: 'Aprovar',
                                      cancelText: 'Cancelar',
                                      onOk: () => postStatus(item, 'aprovar'),
                                  })
                            : undefined
                    }
                    onReabrir={
                        canEditar
                            ? (item) =>
                                  void confirmDialog({
                                      title: 'Reabrir para revisão?',
                                      content: 'O caso de uso voltará a ficar editável.',
                                      okText: 'Reabrir',
                                      cancelText: 'Cancelar',
                                      onOk: () => postStatus(item, 'reabrir'),
                                  })
                            : undefined
                    }
                    onObsoletar={
                        canEditar
                            ? (item) =>
                                  void confirmDialog({
                                      title: 'Obsoletar este caso de uso?',
                                      content: 'Ele deixará de fazer parte do conjunto ativo.',
                                      okText: 'Obsoletar',
                                      cancelText: 'Cancelar',
                                      onOk: () => postStatus(item, 'obsoletar'),
                                  })
                            : undefined
                    }
                    onExcluir={canEditar ? excluirUm : undefined}
                />

                <ModalCasoUsoForm
                    open={formOpen}
                    projetoId={projetoId}
                    onClose={fecharForm}
                    onSaved={(caso) => {
                        router.push(
                            projetosProjetoCanonical.planejamentoCasosDeUsoDetalhe(projetoId, caso.id),
                        );
                    }}
                />

                {!canEditar ? (
                    <Typography.Paragraph type="secondary" style={{ marginTop: 8 }}>
                        Você pode consultar os casos de uso. A edição exige permissão de projeto.
                    </Typography.Paragraph>
                ) : null}
            </ProjetoLayout>

            <ListingPageOptionsModal
                open={listaMaisOpcoesOpen}
                onClose={() => setListaMaisOpcoesOpen(false)}
                subtitle="Casos de uso"
                onColunasVisiveis={() => setColunasVisiveisModalOpen(true)}
                extraActions={[
                    {
                        key: 'diagrama-uml',
                        label: 'Diagrama UML',
                        icon: <GitBranch size={ICON_SIZE_MD} aria-hidden />,
                        onClick: () =>
                            router.push(projetosProjetoCanonical.planejamentoCasosDeUsoDiagrama(projetoId)),
                    },
                    ...(canEditar
                        ? [
                              {
                                  key: 'sugerir-ia',
                                  label: 'Sugerir com IA',
                                  icon: <Sparkles size={ICON_SIZE_MD} aria-hidden />,
                                  onClick: abrirSugerirIa,
                              },
                          ]
                        : []),
                ]}
                extraGroupTitle="Neste módulo"
                navigationActions={relatedNavActions}
                data-testid="projeto-casos-uso-opcoes-pagina-modal"
                aria-label="Opções da listagem de casos de uso"
            />

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

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

            {selectedRowKeys.length === 0 ? (
                <ListPageCreateFloatButton
                    data-testid="projeto-casos-uso-fab-novo"
                    disabled={!canCriar}
                    tooltip={!canCriar ? tooltipSemPermissao('criar') : 'Novo caso de uso'}
                    onClick={abrirNovo}
                />
            ) : null}

            <ModalSugerirCasosUsoIa
                open={iaModalOpen}
                loadingSugestoes={sugerirIaMutation.isPending}
                applying={aplicarSugestoesMutation.isPending}
                sugestoes={iaSugestoes}
                errorMessage={iaError}
                onClose={() => setIaModalOpen(false)}
                onRetry={abrirSugerirIa}
                onAplicar={(selecionados) => {
                    aplicarSugestoesMutation.mutate({ casos_uso: selecionados });
                }}
            />
        </>
    );
}
