'use client';

import { confirmDialog } from '@/lib/feedback/confirmDialog';
import React, { useCallback, useEffect, useLayoutEffect, useMemo, useState, type ReactNode } from 'react';
import dynamic from 'next/dynamic';
import { usePathname, useSearchParams, useRouter } from 'next/navigation';
import Link from 'next/link';
import { Badge, Modal, Space, Spin, Tag, Tooltip, Typography, Alert, Button, Pagination } from 'antd';
import { message } from '@/lib/feedback/message';
import type { ColumnsType } from 'antd/es/table';
import { CheckCircle2, Filter, ScrollText, Trash2, Bot } from 'lucide-react';
import { ICON_SIZE_MD, iconTokenSize } from '@/components/icons';
import dayjs from 'dayjs';
import type { Dayjs } from 'dayjs';
import { keepPreviousData } from '@tanstack/react-query';
import { useQueryCache } from '@/hooks/useQueryCache';
import { useQueryClient } from '@tanstack/react-query';
import { queryKeys } from '@/lib/cache/queryKeys';
import { useListingFilteredRowSelection } from '@/hooks/useListingFilteredRowSelection';
import { useServerSideListingTableChange, listingSortColumnUi, type ServerSideSortState } from '@/hooks/useServerSideListingTableChange';
import { API_ENDPOINTS } from '@/lib/api/endpoints';
import { LazyDataTable, LazyExportButton } from '@/components/lazy';
import btnHeaderStyles from '@/components/ui/buttons/ButtonHeaderIcon/ButtonHeaderIcon.module.scss';
import { TableScrollWrapper } from '@/components/tables/TableScrollWrapper';
import PageWrapper from '@/components/layouts/PageWrapper';
import { ListPageLayout } from '@/components/layouts/ListPageLayout';
import { ButtonHeaderIcon } from '@/components/ui';
import {
    ListingBulkFabModal,
    ListingActionsColumnCell,
    ListingColumnCustomizeModal,
    ListingPageOptionsButton,
    ListingPageOptionsModal,
    listingServerSortNoOp,
    buildListingRowInteractiveProps,
    SavedFilterActiveTag,
    ListagemListaError,
    ListagemEmptyState,
    filterTableColumnsByVisibleKeys,
    useListingMobileInteractionHint,
    useListingVisibleColumns,
} from '@/components/listings';
import { ModuleRelatedLinksPanel } from '@/components/navigation/ModuleRelatedLinksPanel';
import { useModuleRelatedLinks } from '@/hooks/useModuleRelatedLinks';
import {
    SUPORTE_LOGS_LIST_COLUMN_CATALOG,
    SUPORTE_LOGS_LIST_MODULE_KEY,
} from './utils/suporteLogsListColumnCatalog';
import {
    mergeWaygestFormModalBodyStyles,
    useWaygestFormModalProps,
} from '@/hooks/useWaygestFormModalProps';
import { useSetPageDocumentTitle } from '@/contexts/PageDocumentTitleContext';
import { usePermissions } from '@/contexts/PermissionsContext';
import { useIsMobile } from '@/hooks/useIsMobile';
import type { PaginatedResponse } from '@/types';
import apiClient from '@/lib/api/client';
import { getLaravelApiErrorMessage } from '@/lib/api/laravelApiErrorMessage';
import { getLogLevelColor } from './logsLevelUtils';
import type { ConfigGeralSuporte, LogEntry, LogsSummary, PaginatedLogs } from './types';
import { SuporteLogsMetrics } from './components/SuporteLogsMetrics';
import { ModalFiltrosSuporteLogs } from './components/ModalFiltrosSuporteLogs';
import { CardLog } from './components/CardLog';
import { SuporteLogsResolvedNav } from './components/SuporteLogsResolvedNav';
import { SuporteLogsOcorrenciasChart } from './components/SuporteLogsOcorrenciasChart';
import {
    downloadSuporteLogsFilteredCsv,
    SUPORTE_LOGS_EXPORT_ALL_CSV_LABEL,
    SUPORTE_LOGS_EXPORT_PAGE_HELP,
} from './utils/suporteLogsExport';
import screenStyles from './suporteLogsScreen.module.scss';
import { parseSuporteLogsFiltrosFromPayload } from './utils/suporteLogsFiltrosPayload';
import type { SuporteLogsResolvedFilter } from './utils/suporteLogsListaFiltersUrl';
import {
    SUPORTE_LOGS_LISTA_DEFAULT_SORT_BY,
    SUPORTE_LOGS_LISTA_DEFAULT_SORT_DIR,
    SUPORTE_LOGS_LISTA_URL_DEFAULTS,
    type SuporteLogsListaUrlState} from './utils/suporteLogsListaFiltersUrl';
import { useSuporteLogsListaUrlSync } from './hooks/useSuporteLogsListaUrlSync';
import type { ModalOpcaoAction } from '@/components/ModalOpcoesBase';
import { ModalRelatorioBugsProjeto } from './components/ModalRelatorioBugsProjeto';

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

const BULK_CONFIRM_OPEN_DELAY_MS = 120;

const SUPORTE_LOGS_LIST_DEFAULT_SORT: Exclude<ServerSideSortState, null> = {
    columnKey: 'logged_at',
    order: 'descend'};

const EMPTY_LOGS: LogEntry[] = [];

const EXPORT_HELP = SUPORTE_LOGS_EXPORT_PAGE_HELP;

function sortColumnKeyToApi(columnKey: string): string {
    if (columnKey === 'message') return 'mensagem';
    return columnKey;
}

function apiSortToTableSort(sortBy: string, sortDir: 'asc' | 'desc'): ServerSideSortState {
    if (sortBy === SUPORTE_LOGS_LISTA_DEFAULT_SORT_BY && sortDir === SUPORTE_LOGS_LISTA_DEFAULT_SORT_DIR) {
        return null;
    }
    const columnKey = sortBy === 'mensagem' ? 'message' : sortBy;
    return {
        columnKey,
        order: sortDir === 'asc' ? 'ascend' : 'descend'};
}

export interface SuporteLogsScreenProps {
    /** Fixa filtro projeto_id (vista observabilidade por projeto) */
    projetoIdFixo?: string;
    /** Oculta breadcrumb Suporte e sincronização URL da listagem global */
    embeddedInProjeto?: boolean;
    /**
     * Quando `embeddedInProjeto`, envia a toolbar (prompt/export/filtros) para o
     * `headerAction` do `ProjetoLayout` (desktop). Em mobile fica na barra inferior.
     */
    onHeaderActionsChange?: (actions: ReactNode | null) => void;
}

export function SuporteLogsScreen({
    projetoIdFixo,
    embeddedInProjeto = false,
    onHeaderActionsChange,
}: SuporteLogsScreenProps = {}) {
    const router = useRouter();
    const pathname = usePathname();
    const searchParams = useSearchParams();
    const queryClient = useQueryClient();
    const isMobile = useIsMobile();
    const filtrosModalLayout = useWaygestFormModalProps();
    const filtrosModalStyles = mergeWaygestFormModalBodyStyles(filtrosModalLayout);
    const { hasPermission } = usePermissions();
    const podeGerenciarLogs = hasPermission('projetos.logs.gerenciar');

    useSetPageDocumentTitle(embeddedInProjeto ? ['Logs do projeto'] : ['Logs']);

    const endpointGerais = API_ENDPOINTS.customerSuccess?.configuracoesGeraisSuporte?.show;
    const { data: configGerais, isLoading: isLoadingConfig } = useQueryCache<ConfigGeralSuporte>({
        queryKey: queryKeys.suporte.configuracoesGerais(),
        endpoint: endpointGerais ?? '',
        staleTime: 5 * 60 * 1000,
        enabled: !!endpointGerais && !embeddedInProjeto});

    const [exportingFiltered, setExportingFiltered] = useState(false);

    const [page, setPage] = useState(1);
    const [perPage, setPerPage] = useState(SUPORTE_LOGS_LISTA_URL_DEFAULTS.perPage);
    const [tableSort, setTableSort] = useState<ServerSideSortState>(null);

    const [level, setLevel] = useState('');
    const [periodo, setPeriodo] = useState<[Dayjs | null, Dayjs | null] | null>(null);
    const [projetoId, setProjetoId] = useState(projetoIdFixo ?? '');
    const [resolved, setResolved] = useState<SuporteLogsResolvedFilter>('no');
    const [searchApplied, setSearchApplied] = useState('');

    const [filtrosModalOpen, setFiltrosModalOpen] = useState(false);
    const [filtroSalvoAtivo, setFiltroSalvoAtivo] = useState<{ nome: string } | null>(null);

    const [draftLevel, setDraftLevel] = useState('');
    const [draftPeriodo, setDraftPeriodo] = useState<[Dayjs | null, Dayjs | null] | null>(null);
    const [draftProjetoId, setDraftProjetoId] = useState('');
    const [draftResolved, setDraftResolved] = useState<SuporteLogsResolvedFilter>('no');
    const [draftSearch, setDraftSearch] = useState('');

    const [modalOpcoesOpen, setModalOpcoesOpen] = useState(false);
    const [logSelecionado, setLogSelecionado] = useState<LogEntry | null>(null);
    const [modalAcoesMassaOpen, setModalAcoesMassaOpen] = useState(false);
    const [bulkBusy, setBulkBusy] = useState(false);
    const [modalRelatorioBugsOpen, setModalRelatorioBugsOpen] = useState(false);
    const [listaMaisOpcoesOpen, setListaMaisOpcoesOpen] = useState(false);
    const [colunasVisiveisModalOpen, setColunasVisiveisModalOpen] = useState(false);
    const { visibleKeys: logsVisibleColumnKeys, columnOrder, setVisibleKeys: setLogsVisibleColumnKeys } =
        useListingVisibleColumns(SUPORTE_LOGS_LIST_MODULE_KEY, SUPORTE_LOGS_LIST_COLUMN_CATALOG);
    const closeListaMaisOpcoes = useCallback(() => setListaMaisOpcoesOpen(false), []);
    const openColunasVisiveis = useCallback(() => {
        setListaMaisOpcoesOpen(false);
        setColunasVisiveisModalOpen(true);
    }, []);
    const { modalActions: logsRelatedNavActions } = useModuleRelatedLinks({
        surfaceKey: 'suporte.logs.list',
        pagePrefix: 'suporte-logs',
        modalOnClose: closeListaMaisOpcoes,
    });

    const projetoIdParaPrompt = projetoIdFixo || projetoId;

    const dateFromStr = periodo?.[0]?.format('YYYY-MM-DD') ?? '';
    const dateToStr = periodo?.[1]?.format('YYYY-MM-DD') ?? '';

    const listaUrlSnapshot = useMemo((): SuporteLogsListaUrlState => {
        const sortBy = tableSort ? sortColumnKeyToApi(tableSort.columnKey) : SUPORTE_LOGS_LISTA_DEFAULT_SORT_BY;
        const sortDir = tableSort ? (tableSort.order === 'ascend' ? 'asc' : 'desc') : SUPORTE_LOGS_LISTA_DEFAULT_SORT_DIR;
        return {
            page,
            perPage,
            level,
            dateFrom: dateFromStr,
            dateTo: dateToStr,
            projetoId,
            resolved,
            search: searchApplied.trim(),
            sortBy,
            sortDir};
    }, [
        page,
        perPage,
        level,
        dateFromStr,
        dateToStr,
        projetoId,
        resolved,
        searchApplied,
        tableSort,
    ]);

    const onHydrateSuporteLogsFromUrl = useCallback((v: SuporteLogsListaUrlState) => {
        setPage(v.page);
        setPerPage(v.perPage);
        setLevel(v.level);
        setProjetoId(v.projetoId);
        setResolved(v.resolved);
        setSearchApplied(v.search);
        setTableSort(apiSortToTableSort(v.sortBy, v.sortDir));
        setFiltroSalvoAtivo(null);
        if (v.dateFrom && v.dateTo) {
            setPeriodo([dayjs(v.dateFrom), dayjs(v.dateTo)]);
        } else if (v.dateFrom) {
            setPeriodo([dayjs(v.dateFrom), null]);
        } else if (v.dateTo) {
            setPeriodo([null, dayjs(v.dateTo)]);
        } else {
            setPeriodo(null);
        }
    }, []);

    useSuporteLogsListaUrlSync({
        pathname: pathname || '/suporte/logs',
        searchParams,
        snapshot: listaUrlSnapshot,
        onHydrateFromUrl: onHydrateSuporteLogsFromUrl,
        enabled: !embeddedInProjeto && !projetoIdFixo,
    });

    useEffect(() => {
        if (!filtrosModalOpen) return;
        setDraftLevel(level);
        setDraftPeriodo(periodo);
        setDraftProjetoId(projetoId);
        setDraftResolved(resolved);
        setDraftSearch(searchApplied);
    }, [filtrosModalOpen, level, periodo, projetoId, resolved, searchApplied]);

    const listParams = useMemo(() => {
        const sortBy = tableSort ? sortColumnKeyToApi(tableSort.columnKey) : SUPORTE_LOGS_LISTA_DEFAULT_SORT_BY;
        const sortDirection = tableSort ? (tableSort.order === 'ascend' ? 'asc' : 'desc') : SUPORTE_LOGS_LISTA_DEFAULT_SORT_DIR;
        const p: Record<string, string | number | undefined> = {
            page,
            per_page: perPage,
            sort_by: sortBy,
            sort_direction: sortDirection};
        if (level && level !== 'all') p.level = level;
        if (dateFromStr) p.date_from = dateFromStr;
        if (dateToStr) p.date_to = dateToStr;
        const pid = projetoIdFixo || projetoId;
        if (pid) p.projeto_id = pid;
        if (resolved === 'yes') p.resolved = 1;
        if (resolved === 'no') p.resolved = 0;
        if (resolved === 'all') {
            /* omit resolved — API shows all */
        }
        if (searchApplied.trim()) p.search = searchApplied.trim();
        return p;
    }, [page, perPage, tableSort, level, dateFromStr, dateToStr, projetoId, projetoIdFixo, resolved, searchApplied]);

    const paramsSummary = useMemo(() => {
        const p: Record<string, string | number | undefined> = {};
        if (level && level !== 'all') p.level = level;
        if (dateFromStr) p.date_from = dateFromStr;
        if (dateToStr) p.date_to = dateToStr;
        const pid = projetoIdFixo || projetoId;
        if (pid) p.projeto_id = pid;
        if (resolved === 'yes') p.resolved = 1;
        if (resolved === 'no') p.resolved = 0;
        return p;
    }, [level, dateFromStr, dateToStr, projetoId, projetoIdFixo, resolved]);

    const exportFilterParams = useMemo(() => {
        const { page: _p, per_page: _pp, ...rest } = listParams;
        return rest;
    }, [listParams]);

    const { data: logsResponse, isLoading, isFetching, isError, error, refetch } = useQueryCache<PaginatedLogs>({
        queryKey: queryKeys.projetos.logs.list(listParams),
        endpoint: API_ENDPOINTS.projetos.logs.index,
        params: listParams,
        staleTime: 1 * 60 * 1000,
        gcTime: 5 * 60 * 1000,
        placeholderData: keepPreviousData});

    const { data: summaryData } = useQueryCache<LogsSummary>({
        queryKey: queryKeys.projetos.logs.summary(paramsSummary),
        endpoint: API_ENDPOINTS.projetos.logs.summary,
        params: paramsSummary,
        staleTime: 1 * 60 * 1000,
        gcTime: 5 * 60 * 1000});

    const { data: projetosData } = useQueryCache<{ data?: { id: number; nome?: string }[] }>({
        queryKey: queryKeys.projetos.lists(),
        endpoint: API_ENDPOINTS.projetos.index,
        params: { per_page: 500 },
        staleTime: 5 * 60 * 1000});

    const projetos = useMemo(() => projetosData?.data ?? [], [projetosData]);
    const summary = summaryData ?? { total: 0, counts_by_level: {} };
    const pendingTotal = summary.pending_total ?? 0;
    const resolvedTotal = summary.resolved_total ?? 0;
    const seriesByDay = summary.series_by_day ?? [];

    const handleResolvedNavChange = useCallback((next: SuporteLogsResolvedFilter) => {
        setResolved(next);
        setPage(1);
        setFiltroSalvoAtivo(null);
    }, []);

    const paginatedData: PaginatedResponse<LogEntry> = useMemo(() => {
        if (!logsResponse) {
            return {
                data: EMPTY_LOGS,
                meta: {
                    current_page: 1,
                    per_page: perPage,
                    total: 0,
                    last_page: 1,
                    from: 0,
                    to: 0},
                links: { first: '', last: '', prev: null, next: null }};
        }
        const rows = logsResponse.data ?? [];
        const meta = logsResponse.meta;
        const cur = logsResponse.current_page ?? meta?.current_page ?? 1;
        const pp = logsResponse.per_page ?? meta?.per_page ?? perPage;
        const total = logsResponse.total ?? meta?.total ?? 0;
        const last = logsResponse.last_page ?? meta?.last_page ?? 1;
        return {
            data: rows,
            meta: {
                current_page: cur,
                per_page: pp,
                total,
                last_page: last,
                from: total === 0 ? 0 : (cur - 1) * pp + 1,
                to: Math.min(cur * pp, total)},
            links: { first: '', last: '', prev: null, next: null }};
    }, [logsResponse, perPage]);

    const erroListaMsg = useMemo(
        () =>
            getLaravelApiErrorMessage(
                error,
                'Verifique a conexão e tente novamente. Se o problema persistir, contate o suporte.',
            ),
        [error],
    );

    const logsExportRows = useMemo(
        () =>
            paginatedData.data.map((l) => ({
                id: l.id,
                level: l.level,
                mensagem: l.header || l.message || '',
                environment: l.environment,
                projeto: l.projeto?.nome ?? '',
                logged_at: l.logged_at,
                resolvido_em: l.resolved_at ?? ''})),
        [paginatedData.data],
    );

    const filtrosAtivosCount = useMemo(() => {
        let n = 0;
        if (dateFromStr && dateToStr) n += 1;
        // Com projeto fixo (observabilidade no projeto), o filtro de projeto é implícito — não conta.
        if (projetoId && !projetoIdFixo) n += 1;
        if (resolved !== 'no') n += 1;
        if (level && level !== 'all' && level !== '') n += 1;
        if (searchApplied.trim()) n += 1;
        return n;
    }, [dateFromStr, dateToStr, projetoId, projetoIdFixo, resolved, level, searchApplied]);

    const filtrosComAlgumAtivo = filtrosAtivosCount > 0;

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

    const limparTodosFiltros = useCallback(() => {
        setLevel('');
        setPeriodo(null);
        setProjetoId(projetoIdFixo ?? '');
        setResolved('no');
        setSearchApplied('');
        setFiltroSalvoAtivo(null);
        setDraftLevel('');
        setDraftPeriodo(null);
        setDraftProjetoId(projetoIdFixo ?? '');
        setDraftResolved('no');
        setDraftSearch('');
        setPage(1);
        setFiltrosModalOpen(false);
    }, [projetoIdFixo]);

    const aplicarFiltrosModal = useCallback(() => {
        setLevel(draftLevel);
        setPeriodo(draftPeriodo);
        setProjetoId(projetoIdFixo || draftProjetoId);
        setResolved(draftResolved);
        setSearchApplied(draftSearch.trim());
        setFiltroSalvoAtivo(null);
        setPage(1);
        setFiltrosModalOpen(false);
    }, [draftLevel, draftPeriodo, draftProjetoId, draftResolved, draftSearch, projetoIdFixo]);

    const handleApplySaved = useCallback((payload: unknown, meta: { nome: string }) => {
        const parsed = parseSuporteLogsFiltrosFromPayload(payload);
        if (parsed.level !== undefined) setLevel(parsed.level ?? '');
        if (parsed.dateFrom !== undefined || parsed.dateTo !== undefined) {
            const df = parsed.dateFrom?.trim() ?? '';
            const dt = parsed.dateTo?.trim() ?? '';
            if (df && dt) {
                setPeriodo([dayjs(df), dayjs(dt)]);
            } else if (df) {
                setPeriodo([dayjs(df), null]);
            } else if (dt) {
                setPeriodo([null, dayjs(dt)]);
            } else {
                setPeriodo(null);
            }
        }
        if (!projetoIdFixo && parsed.projetoId !== undefined) {
            setProjetoId(parsed.projetoId ?? '');
        }
        if (parsed.resolved !== undefined) setResolved(parsed.resolved);
        if (parsed.search !== undefined) setSearchApplied((parsed.search ?? '').trim());
        setFiltroSalvoAtivo({ nome: meta.nome });
        setPage(1);
        setFiltrosModalOpen(false);
    }, [projetoIdFixo]);

    const resumoFiltrosAplicados = useMemo(() => {
        const partes: string[] = [];
        if (level && level !== 'all') partes.push(`Nível: ${level}`);
        if (dateFromStr && dateToStr) partes.push(`Período: ${dateFromStr} — ${dateToStr}`);
        if (projetoId && !projetoIdFixo) {
            const nome = projetos.find((p) => String(p.id) === projetoId)?.nome;
            partes.push(`Projeto: ${nome ?? `#${projetoId}`}`);
        }
        if (resolved === 'yes') partes.push('Situação: resolvidos');
        if (resolved === 'all') partes.push('Situação: todos');
        if (searchApplied.trim()) partes.push(`Pesquisa: "${searchApplied.trim()}"`);
        return partes.join(' · ') || 'Nenhum filtro além do padrão (só pendentes).';
    }, [level, dateFromStr, dateToStr, projetoId, projetoIdFixo, resolved, searchApplied, projetos]);

    const handleOpenOpcoes = useCallback((item: LogEntry) => {
        setLogSelecionado(item);
        setModalOpcoesOpen(true);
    }, []);

    const handleFecharModalOpcoes = useCallback(() => {
        setModalOpcoesOpen(false);
        setLogSelecionado(null);
    }, []);

    const handleVerDetalhes = useCallback(
        (record: LogEntry) => {
            handleFecharModalOpcoes();
            router.push(`/suporte/logs/${record.id}`);
        },
        [handleFecharModalOpcoes, router],
    );

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

    const sortColumnUi = listingSortColumnUi(tableSort, SUPORTE_LOGS_LIST_DEFAULT_SORT);

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

    useEffect(() => {
        clearSelection();
    }, [level, periodo, projetoId, resolved, searchApplied, page, perPage, tableSort, clearSelection]);

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

    const handleBulkMarcarRealizado = useCallback(() => {
        const ids = selectedIdsBulk;
        const alvo = paginatedData.data.filter((r: any) => ids.includes(r.id) && !r.resolved_at);
        if (alvo.length === 0) {
            Modal.warning({
                title: 'Nada a marcar',
                content: 'Não há logs não realizados na selecção.',
                okText: 'Fechar'});
            return;
        }
        setModalAcoesMassaOpen(false);
        window.setTimeout(() => {
            confirmDialog({
                title: 'Marcar como realizado',
                content: `Marcar ${alvo.length} log(s) como realizado(s)?`,
                okText: 'Marcar',
                cancelText: 'Cancelar',
                onOk: async () => {
                    setBulkBusy(true);
                    try {
                        const res = await apiClient.post(API_ENDPOINTS.projetos.logs.bulk, {
                            acao: 'marcar_realizado',
                            ids: alvo.map((l) => l.id),
                        });
                        const data = res.data as { sucesso?: number; falha?: number };
                        clearSelection();
                        await queryClient.invalidateQueries({ queryKey: queryKeys.projetos.logs.all });
                        if ((data.falha ?? 0) === 0) {
                            Modal.success({
                                title: `${data.sucesso ?? alvo.length} log(s) atualizado(s).`,
                                okText: 'Fechar',
                            });
                            return;
                        }
                        Modal.warning({
                            title: 'Concluído com avisos',
                            content: `${data.sucesso ?? 0} atualizado(s), ${data.falha ?? 0} falharam.`,
                            okText: 'Fechar',
                        });
                    } catch {
                        Modal.error({ title: 'Não foi possível atualizar os logs.', okText: 'Fechar' });
                    } finally {
                        setBulkBusy(false);
                    }
                }});
        }, BULK_CONFIRM_OPEN_DELAY_MS);
    }, [selectedIdsBulk, paginatedData.data, clearSelection, queryClient]);

    const handleBulkExcluir = useCallback(() => {
        const ids = selectedIdsBulk;
        if (ids.length === 0) {
            Modal.warning({
                title: 'Selecção vazia',
                content: 'Selecione pelo menos um log.',
                okText: 'Fechar'});
            return;
        }
        setModalAcoesMassaOpen(false);
        window.setTimeout(() => {
            confirmDialog({
                title: 'Excluir logs selecionados',
                content: `Excluir permanentemente ${ids.length} log(s)? Esta ação não pode ser desfeita.`,
                okText: 'Excluir',
                cancelText: 'Cancelar',
                okButtonProps: { danger: true },
                onOk: async () => {
                    setBulkBusy(true);
                    try {
                        const res = await apiClient.post(API_ENDPOINTS.projetos.logs.bulk, {
                            acao: 'excluir',
                            ids,
                        });
                        const data = res.data as { sucesso?: number; falha?: number };
                        clearSelection();
                        handleFecharModalOpcoes();
                        await queryClient.invalidateQueries({ queryKey: queryKeys.projetos.logs.all });
                        const ok = data.sucesso ?? 0;
                        const fail = data.falha ?? 0;
                        if (ok > 0 && fail === 0) {
                            Modal.success({ title: `${ok === 1 ? 'Log excluído' : `${ok} logs excluídos`}.`, okText: 'Fechar' });
                            return;
                        }
                        if (ok > 0 && fail > 0) {
                            Modal.warning({
                                title: 'Concluído com avisos',
                                content: `${ok} excluído(s), ${fail} falharam (permissão ou estado).`,
                                okText: 'Fechar'});
                            return;
                        }
                        Modal.error({ title: 'Não foi possível excluir os logs selecionados.', okText: 'Fechar' });
                    } finally {
                        setBulkBusy(false);
                    }
                }});
        }, BULK_CONFIRM_OPEN_DELAY_MS);
    }, [selectedIdsBulk, clearSelection, queryClient, handleFecharModalOpcoes]);

    const acoesMassaModal = useMemo((): ModalOpcaoAction[] => {
        if (!podeGerenciarLogs) {
            return [];
        }
        const n = selectedIdsBulk.length;
        return [
            {
                key: 'realizado',
                label: `Marcar como realizado${n > 0 ? ` (${n})` : ''}`,
                icon: <CheckCircle2 size={ICON_SIZE_MD} aria-hidden />,
                onClick: handleBulkMarcarRealizado,
                disabled: bulkBusy || n === 0},
            {
                key: 'excluir',
                label: `Excluir selecionados${n > 0 ? ` (${n})` : ''}`,
                icon: <Trash2 size={ICON_SIZE_MD} aria-hidden />,
                danger: true,
                onClick: handleBulkExcluir,
                disabled: bulkBusy || n === 0},
        ];
    }, [bulkBusy, handleBulkMarcarRealizado, handleBulkExcluir, selectedIdsBulk.length, podeGerenciarLogs]);

    const handleLogRowProps = useCallback(
        (record: LogEntry) =>
            buildListingRowInteractiveProps(record, {
                onAtivate: handleOpenOpcoes,
                getRowSummary: (row) => [row.header || row.message, row.level?.toUpperCase()].filter(Boolean).join(' · '),
                ariaLabelWithSummary: (summary) => `Log: ${summary}. Enter ou espaço abre o menu de opções.`,
                ariaLabelFallback: 'Log. Enter ou espaço abre o menu de opções.'}),
        [handleOpenOpcoes],
    );

    const logsTabelaScrollHint = useListingMobileInteractionHint(
        'Toque num card para abrir opções do log.',
    );

    const handleExportFilteredCsv = useCallback(async () => {
        setExportingFiltered(true);
        try {
            await downloadSuporteLogsFilteredCsv(exportFilterParams);
            message.success('Export CSV iniciado.');
        } catch (e) {
            message.error(e instanceof Error ? e.message : 'Não foi possível exportar.');
        } finally {
            setExportingFiltered(false);
        }
    }, [exportFilterParams]);

    const headerToolbar = useMemo(
        () => (
            <Space wrap size={8} align="center">
                {!embeddedInProjeto ? (
                    <ListingPageOptionsButton
                        data-testid="suporte-logs-lista-mais-opcoes"
                        expanded={listaMaisOpcoesOpen}
                        ariaLabel="Opções da listagem de logs"
                        onClick={() => setListaMaisOpcoesOpen(true)}
                    />
                ) : null}
                {projetoIdParaPrompt ? (
                    <Tooltip title="Inclui só critical, error e warning não resolvidos (notice/info ficam só na listagem)">
                        <Button
                            type="primary"
                            icon={<Bot size={ICON_SIZE_MD} aria-hidden />}
                            onClick={() => setModalRelatorioBugsOpen(true)}
                            data-testid="suporte-logs-gerar-prompt"
                        >
                            Gerar prompt de correção
                        </Button>
                    </Tooltip>
                ) : null}
                <Tooltip
                    title={
                        filtrosComAlgumAtivo
                            ? `Filtros ativos (${filtrosAtivosCount}) — abrir para alterar critérios`
                            : 'Abrir filtros (nível, período, projeto, situação, pesquisa)'
                    }
                >
                    <span style={{ display: 'inline-block' }}>
                        <Badge dot={filtrosComAlgumAtivo} color="geekblue">
                            <ButtonHeaderIcon
                                data-testid="suporte-logs-abrir-filtros"
                                icon={<Filter size={ICON_SIZE_MD} aria-hidden />}
                                title={filtrosAtivosCount > 0 ? `Filtros (${filtrosAtivosCount})` : 'Filtros'}
                                aria-label="Abrir filtros dos logs"
                                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={logsExportRows as unknown as Record<string, unknown>[]}
                            columns={[
                                { key: 'id', label: 'ID' },
                                { key: 'level', label: 'Nível' },
                                { key: 'mensagem', label: 'Mensagem' },
                                { key: 'environment', label: 'Ambiente' },
                                { key: 'projeto', label: 'Projeto' },
                                { key: 'logged_at', label: 'Data' },
                                { key: 'resolvido_em', label: 'Resolvido em' },
                            ]}
                            filename={`suporte-logs-p${paginatedData.meta.current_page}`}
                            title="Exportar logs"
                            iconOnly
                            size="large"
                            exportMenuMode="modal"
                            helpTooltip={EXPORT_HELP}
                            className={btnHeaderStyles.btnHeaderIcon}
                        />
                    </span>
                </Tooltip>
                <Tooltip title="CSV com todos os registros que correspondem aos filtros atuais (até 5000)">
                    <Button
                        loading={exportingFiltered}
                        onClick={() => void handleExportFilteredCsv()}
                        aria-label={SUPORTE_LOGS_EXPORT_ALL_CSV_LABEL}
                    >
                        {SUPORTE_LOGS_EXPORT_ALL_CSV_LABEL}
                    </Button>
                </Tooltip>
            </Space>
        ),
        [
            embeddedInProjeto,
            listaMaisOpcoesOpen,
            projetoIdParaPrompt,
            filtrosComAlgumAtivo,
            filtrosAtivosCount,
            filtrosModalOpen,
            abrirModalFiltros,
            logsExportRows,
            paginatedData.meta.current_page,
            exportingFiltered,
            handleExportFilteredCsv,
        ],
    );

    useLayoutEffect(() => {
        if (!embeddedInProjeto || !onHeaderActionsChange) return;
        onHeaderActionsChange(isMobile ? null : headerToolbar);
        return () => onHeaderActionsChange(null);
    }, [embeddedInProjeto, onHeaderActionsChange, headerToolbar, isMobile]);

    const allColumns: ColumnsType<LogEntry> = useMemo(
        () => [
            {
                title: '',
                key: 'menu',
                width: 56,
                align: 'center' as const,
                fixed: 'left' as const,
                onCell: () => ({ onClick: (e: React.MouseEvent) => e.stopPropagation() }),
                render: (_: unknown, record: LogEntry) => (
                    <ListingActionsColumnCell
                        tooltipTitle="Opções"
                        ariaLabel={`Opções do log ${record.id}`}
                        onOpen={() => handleOpenOpcoes(record)}
                        data-testid={`suporte-logs-opcoes-${record.id}`}
                    />
                )},
            {
                title: 'ID',
                dataIndex: 'id',
                key: 'id',
                width: 72,
                sorter: listingServerSortNoOp,
                sortOrder: sortColumnUi.columnKey === 'id' ? sortColumnUi.order : undefined},
            {
                title: 'Nível',
                dataIndex: 'level',
                key: 'level',
                width: 110,
                sorter: listingServerSortNoOp,
                sortOrder: sortColumnUi.columnKey === 'level' ? sortColumnUi.order : undefined,
                render: (lvl: string) => <Tag color={getLogLevelColor(lvl)}>{String(lvl).toUpperCase()}</Tag>},
            {
                title: 'Mensagem',
                key: 'message',
                ellipsis: true,
                sorter: listingServerSortNoOp,
                sortOrder: sortColumnUi.columnKey === 'message' ? sortColumnUi.order : undefined,
                render: (_: unknown, record: LogEntry) => (
                    <span style={{ fontWeight: 500, color: '#2c3e50' }}>{record.header || record.message || '-'}</span>
                )},
            {
                title: 'Ambiente',
                dataIndex: 'environment',
                key: 'environment',
                width: 100,
                sorter: listingServerSortNoOp,
                sortOrder: sortColumnUi.columnKey === 'environment' ? sortColumnUi.order : undefined},
            {
                title: 'Projeto',
                key: 'projeto',
                width: 140,
                sorter: listingServerSortNoOp,
                sortOrder: sortColumnUi.columnKey === 'projeto' ? sortColumnUi.order : undefined,
                render: (_: unknown, record: LogEntry) => record.projeto?.nome ?? '-'},
            {
                title: 'Data',
                dataIndex: 'logged_at',
                key: 'logged_at',
                width: 160,
                sorter: listingServerSortNoOp,
                sortOrder: sortColumnUi.columnKey === 'logged_at' ? sortColumnUi.order : undefined,
                render: (val: string) => (val ? dayjs(val).format('DD/MM/YYYY HH:mm') : '-')},
            ...(resolved === 'yes' || resolved === 'all'
                ? [
                      {
                          title: 'Resolvido em',
                          dataIndex: 'resolved_at',
                          key: 'resolved_at',
                          width: 160,
                          render: (val: string | null | undefined) =>
                              val ? dayjs(val).format('DD/MM/YYYY HH:mm') : (
                                  <Tag>Pendente</Tag>
                              ),
                      } as ColumnsType<LogEntry>[number],
                  ]
                : []),
        ],
        [sortColumnUi, handleOpenOpcoes, resolved],
    );

    const isCompactTable = useIsMobile();
    const columns = useMemo(() => {
        let cols = allColumns;
        if (projetoIdFixo) {
            cols = cols.filter((c) => c.key !== 'projeto');
        }
        return filterTableColumnsByVisibleKeys(cols, logsVisibleColumnKeys, ['menu']);
    }, [allColumns, logsVisibleColumnKeys, projetoIdFixo]);

    const totalLista = paginatedData.meta.total;
    const showEmptyState = !isError && totalLista === 0 && !isLoading;
    const showLogsTable = !isError && !showEmptyState;

    if (!embeddedInProjeto && endpointGerais && (isLoadingConfig || configGerais?.habilitar_pagina_logs === false)) {
        if (isLoadingConfig) {
            return (
                <PageWrapper breadcrumbItems={[{ title: 'Suporte', path: '/suporte' }, { title: 'Logs' }]}>
                    <div style={{ textAlign: 'center', padding: 48 }}>
                        <Spin size="large" />
                    </div>
                </PageWrapper>
            );
        }

        return (
            <PageWrapper breadcrumbItems={[{ title: 'Suporte', path: '/suporte' }, { title: 'Logs' }]}>
                <Alert
                    type="warning"
                    showIcon
                    message="Logs desativados pelo administrador"
                    description={
                        <>
                            A página de logs está desativada nas configurações gerais do suporte.{' '}
                            <Link href="/suporte/configuracoes/configuracoes-gerais">
                                Ativar em Configurações gerais
                            </Link>
                            .
                        </>
                    }
                    action={
                        <Button type="primary" size="small" onClick={() => router.push('/suporte')}>
                            Voltar ao Suporte
                        </Button>
                    }
                />
            </PageWrapper>
        );
    }

    return (
        <>
            <ListPageLayout
                suppressPageHeader={embeddedInProjeto}
                breadcrumbItems={
                    embeddedInProjeto
                        ? []
                        : [{ title: 'Suporte', path: '/suporte' }, { title: 'Logs' }]
                }
                header={{
                    title: embeddedInProjeto ? 'Logs deste projeto' : 'Logs',
                    icon: <ScrollText size={ICON_SIZE_MD} aria-hidden />,
                    description:
                        !embeddedInProjeto && filtroSalvoAtivo ? (
                            <SavedFilterActiveTag nome={filtroSalvoAtivo.nome} dataTestId="suporte-logs-filtro-salvo-ativo" />
                        ) : undefined,
                    actions: embeddedInProjeto ? undefined : headerToolbar,
                }}
                mobileInlineActions={embeddedInProjeto && isMobile ? headerToolbar : undefined}
                mobileHideOpcoesButton={embeddedInProjeto && isMobile}
                metricsWrapperStyle={{ marginBottom: 15 }}
                metrics={
                    <SuporteLogsMetrics summary={summary} isLoading={isLoading} isError={isError} />
                }
                mobileFiltersDrawerDataTestId="suporte-logs-filtros-drawer-mobile"
                mobileOnOpenFilters={abrirModalFiltros}
                loading={isLoading && !logsResponse}
                loadingTip="Carregando logs…"
                onResetFilters={limparTodosFiltros}

                activeFiltersCount={filtrosAtivosCount}
                onRefresh={() => void refetch()}
                refreshLoading={isFetching}
                opcoesModalTitle="Mais"
                belowContent={
                    !embeddedInProjeto ? (
                        <ModuleRelatedLinksPanel
                            surfaceKey="suporte.logs.list"
                            variant="inline"
                            listPlacement="after"
                            pagePrefix="suporte-logs"
                        />
                    ) : undefined
                }
                content={
                    <>
                        <SuporteLogsResolvedNav
                            value={resolved}
                            onChange={handleResolvedNavChange}
                            pendingTotal={pendingTotal}
                            resolvedTotal={resolvedTotal}
                            disabled={isLoading && !logsResponse}
                        />

                        {filtrosComAlgumAtivo ? (
                            <div className={screenStyles.filtrosAtivosBanner} data-testid="suporte-logs-filtros-ativos">
                                <div className={screenStyles.filtrosAtivosMeta}>
                                    <p className={screenStyles.filtrosAtivosTitulo}>
                                        Filtros ativos ({filtrosAtivosCount})
                                    </p>
                                    <p className={screenStyles.filtrosAtivosDescricao}>{resumoFiltrosAplicados}</p>
                                </div>
                            </div>
                        ) : null}

                        {isError ? (
                            <ListagemListaError
                                message="Não foi possível carregar os logs"
                                description={erroListaMsg}
                                onRetry={() => void refetch()}
                                data-testid="suporte-logs-lista-retry"
                            />
                        ) : null}

                        {showEmptyState ? (
                            <ListagemEmptyState
                                type={filtrosComAlgumAtivo || resolved !== 'no' ? 'warning' : 'info'}
                                icon={<ScrollText size={iconTokenSize.xl} aria-hidden />}
                                message={
                                    filtrosComAlgumAtivo
                                        ? 'Nenhum resultado para os filtros'
                                        : resolved === 'yes'
                                          ? 'Nenhum log resolvido'
                                          : resolved === 'all'
                                            ? 'Nenhum log neste projeto'
                                            : 'Nenhum log pendente'
                                }
                                description={
                                    filtrosComAlgumAtivo
                                        ? 'Ajuste os critérios ou limpe os filtros para voltar a ver ocorrências.'
                                        : resolved === 'yes'
                                          ? 'Quando marcar ocorrências como resolvidas, elas aparecerão aqui.'
                                          : 'Quando a aplicação registrar eventos, eles aparecerão aqui para triagem e acompanhamento.'
                                }
                                ctaLabel={
                                    filtrosComAlgumAtivo
                                        ? 'Limpar filtros'
                                        : resolved === 'yes'
                                          ? 'Ver pendentes'
                                          : undefined
                                }
                                onCta={
                                    filtrosComAlgumAtivo
                                        ? limparTodosFiltros
                                        : resolved === 'yes'
                                          ? () => handleResolvedNavChange('no')
                                          : undefined
                                }
                                secondaryCtaLabel={filtrosComAlgumAtivo ? 'Ajustar filtros' : undefined}
                                onSecondaryCta={filtrosComAlgumAtivo ? abrirModalFiltros : undefined}
                                data-testid="suporte-logs-empty"
                            />
                        ) : null}

                        {showLogsTable ? (
                            <section
                                className={screenStyles.tableSection}
                                aria-labelledby="suporte-logs-lista-heading"
                            >
                                <Typography.Title level={5} id="suporte-logs-lista-heading" className="sr-only">
                                    Lista de logs
                                </Typography.Title>
                                <Typography.Paragraph id="suporte-logs-ajuda-teclado" className="sr-only">
                                    Use as caixas de seleção para escolher linhas; com seleção ativa, o botão flutuante abre
                                    ações em massa. Clique na linha ou use Enter ou espaço para abrir opções do registro.
                                </Typography.Paragraph>
                                <div
                                    data-testid="suporte-logs-tabela"
                                    aria-labelledby="suporte-logs-lista-heading"
                                    aria-describedby="suporte-logs-ajuda-teclado"
                                    aria-busy={isFetching}
                                    aria-live="polite"
                                >
                                    <TableScrollWrapper hint={logsTabelaScrollHint}>
                                        {isCompactTable ? (
                                            <div>
                                                {paginatedData.data.map((log) => (
                                                    <CardLog
                                                        key={log.id}
                                                        item={log}
                                                        onOpenOpcoes={handleOpenOpcoes}
                                                    />
                                                ))}
                                                <Pagination
                                                    style={{ marginTop: 16, textAlign: 'right' }}
                                                    current={paginatedData.meta.current_page}
                                                    pageSize={paginatedData.meta.per_page}
                                                    total={paginatedData.meta.total}
                                                    showSizeChanger
                                                    onChange={(p, ps) => {
                                                        setPage(p);
                                                        if (ps) setPerPage(ps);
                                                    }}
                                                    disabled={isLoading || bulkBusy}
                                                />
                                            </div>
                                        ) : (
                                            <LazyDataTable<LogEntry>
                                                rowKey="id"
                                                columns={columns}
                                                paginatedData={paginatedData}
                                                loading={isLoading}
                                                fetching={isFetching}
                                                showRefresh={false}
                                                scroll={{ x: 'max-content' }}
                                                rowSelection={podeGerenciarLogs ? logsRowSelection : undefined}
                                                onChange={handleTableChange}
                                                onPageChange={(p: number, ps?: number) => {
                                                    setPage(p);
                                                    if (ps) setPerPage(ps);
                                                }}
                                                onRow={handleLogRowProps}
                                            />
                                        )}
                                    </TableScrollWrapper>
                                </div>
                            </section>
                        ) : null}

                        {!isError ? (
                            <SuporteLogsOcorrenciasChart series={seriesByDay} isLoading={!summaryData && isLoading} />
                        ) : null}
                    </>
                }
            />

            <ListingPageOptionsModal
                open={listaMaisOpcoesOpen}
                onClose={closeListaMaisOpcoes}
                subtitle="Logs de suporte"
                onColunasVisiveis={openColunasVisiveis}
                navigationActions={logsRelatedNavActions}
                data-testid="suporte-logs-opcoes-pagina-modal"
            />
            <ListingColumnCustomizeModal
                open={colunasVisiveisModalOpen}
                onClose={() => setColunasVisiveisModalOpen(false)}
                catalog={
                    projetoIdFixo
                        ? SUPORTE_LOGS_LIST_COLUMN_CATALOG.filter((c) => c.key !== 'projeto')
                        : SUPORTE_LOGS_LIST_COLUMN_CATALOG
                }
                value={logsVisibleColumnKeys}
                order={columnOrder}
                onApply={setLogsVisibleColumnKeys}
                data-testid="suporte-logs-customizar-colunas-modal"
            />

            <ModalFiltrosSuporteLogs
                open={filtrosModalOpen}
                onClose={() => setFiltrosModalOpen(false)}
                draftLevel={draftLevel}
                draftPeriodo={draftPeriodo}
                draftProjetoId={draftProjetoId}
                draftResolved={draftResolved}
                draftSearch={draftSearch}
                onDraftLevelChange={setDraftLevel}
                onDraftPeriodoChange={setDraftPeriodo}
                onDraftProjetoIdChange={setDraftProjetoId}
                onDraftResolvedChange={setDraftResolved}
                onDraftSearchChange={setDraftSearch}
                projetos={projetos}
                onAplicar={aplicarFiltrosModal}
                onLimparTodos={limparTodosFiltros}
                onApplySaved={handleApplySaved}
                ocultarFiltroProjeto={Boolean(projetoIdFixo)}
                modalWidth={filtrosModalLayout.width}
                modalCentered={filtrosModalLayout.centered}
                modalClassName={filtrosModalLayout.className}
                modalZIndex={filtrosModalLayout.zIndex}
                modalStyles={filtrosModalStyles}
            />

            <ListingBulkFabModal
                showFab={podeGerenciarLogs && selectedRowKeys.length > 0}
                modalOpen={modalAcoesMassaOpen}
                onOpenModal={() => setModalAcoesMassaOpen(true)}
                onCloseModal={() => setModalAcoesMassaOpen(false)}
                busy={bulkBusy}
                modalTitle="Ações em massa"
                modalSubtitle={`${selectedRowKeys.length} log(s) selecionado(s)`}
                actions={acoesMassaModal}
                fabAriaLabel={`Ações em massa — ${selectedRowKeys.length} log(s) selecionado(s)`}
                data-testid-fab="suporte-logs-fab-acoes-massa"
                data-testid-modal="suporte-logs-acoes-massa-modal"
                modalWidth={400}
            />

            <ModalOpcoesLog
                open={modalOpcoesOpen}
                onClose={handleFecharModalOpcoes}
                log={logSelecionado}
                onVerDetalhes={handleVerDetalhes}
                podeGerenciar={podeGerenciarLogs}
                onExcluido={() => {
                    queryClient.invalidateQueries({ queryKey: queryKeys.projetos.logs.all });
                    handleFecharModalOpcoes();
                    setPage(1);
                }}
            />

            {projetoIdParaPrompt ? (
                <ModalRelatorioBugsProjeto
                    open={modalRelatorioBugsOpen}
                    onClose={() => setModalRelatorioBugsOpen(false)}
                    projetoId={String(projetoIdParaPrompt)}
                    onResolvidos={() => {
                        void queryClient.invalidateQueries({ queryKey: queryKeys.projetos.logs.all });
                    }}
                />
            ) : null}
        </>
    );
}
