'use client';

import { confirmDialog } from '@/lib/feedback/confirmDialog';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { Button, Checkbox, Divider, Dropdown, MenuProps, Modal, Space, Typography, Tooltip, Alert } from 'antd';
import { message } from '@/lib/feedback/message';
import type { ButtonProps } from 'antd';
import { Braces, Download, FileOutput, FileSpreadsheet, FileText, Save } from 'lucide-react';
import { ICON_SIZE_MD } from '@/components/icons';
import { usePathname } from 'next/navigation';
import {
    exportToCSV,
    exportToJSON,
    exportToJSONWithColumns,
    exportToExcel,
    exportToPDF,
    type ExportColumn,
} from '@/lib/utils/export';
import styles from './ExportButton.module.scss';

const EXPORT_COLUMNS_LS_PREFIX = 'waygest.export.columns.v1:';

function hashStorageFragment(input: string): string {
    let h = 0;
    for (let i = 0; i < input.length; i += 1) {
        h = (Math.imul(31, h) + input.charCodeAt(i)) | 0;
    }
    return `h${(h >>> 0).toString(36)}`;
}

function buildColumnPreferenceStorageKey(
    explicit: string | undefined,
    pathname: string,
    exportTitle: string,
    columnKeys: readonly string[],
): string {
    if (explicit?.trim()) {
        return explicit.trim();
    }
    const sorted = [...columnKeys].sort().join('\u001f');
    return `${pathname || '/'}#${exportTitle}#${hashStorageFragment(sorted)}`;
}

function readSavedColumnKeys(storageKey: string, validKeys: Set<string>): string[] | null {
    if (typeof window === 'undefined') {
        return null;
    }
    try {
        const raw = window.localStorage.getItem(EXPORT_COLUMNS_LS_PREFIX + storageKey);
        if (!raw) {
            return null;
        }
        const parsed = JSON.parse(raw) as unknown;
        if (!Array.isArray(parsed)) {
            return null;
        }
        const keys = parsed.filter((k): k is string => typeof k === 'string' && validKeys.has(k));
        return keys.length > 0 ? keys : null;
    } catch {
        return null;
    }
}

function writeSavedColumnKeys(storageKey: string, keys: string[]): void {
    if (typeof window === 'undefined' || keys.length === 0) {
        return;
    }
    window.localStorage.setItem(EXPORT_COLUMNS_LS_PREFIX + storageKey, JSON.stringify(keys));
}

function clearSavedColumnKeys(storageKey: string): void {
    if (typeof window === 'undefined') {
        return;
    }
    window.localStorage.removeItem(EXPORT_COLUMNS_LS_PREFIX + storageKey);
}

/** Exportação servidor (CSV / JSON completo filtrado na API). Só com `exportMenuMode="modal"`. */
export type ExportButtonServerCsvDownloadContext = {
    columnKeys: string[];
};

export type ExportButtonServerCsvProps = {
    label: string;
    description?: string;
    loading?: boolean;
    onDownload: (ctx?: ExportButtonServerCsvDownloadContext) => void | Promise<void>;
    /** Se true, envia as colunas seleccionadas no modal para o CSV da API (TASK-PSC-050). */
    applyColumnSelection?: boolean;
    /** Test id do botão CSV servidor (ex.: listagens com E2E de export filtrados). */
    'data-testid'?: string;
};

export type ExportButtonServerJsonProps = ExportButtonServerCsvProps;

export type ExportButtonClientFormat = 'csv' | 'json' | 'excel' | 'pdf';

interface ExportButtonProps {
    data?: Record<string, unknown>[] | unknown[];
    /** Alias legado de `data` (algumas telas passam `rows`). */
    rows?: Record<string, unknown>[] | unknown[];
    columns?: ExportColumn[];
    endpoint?: string;
    filename?: string;
    title?: string;
    disabled?: boolean;
    /** Quando true, exibe apenas o ícone (sem texto "Exportar"). Use title para acessibilidade. */
    iconOnly?: boolean;
    /** Tamanho do botão de disparo (ex.: alinhar a ícones 40px do header). */
    size?: ButtonProps['size'];
    /** Âmbito ou limites do export (ex.: "apenas esta página"). Mostrado em tooltip no botão e no modal. */
    helpTooltip?: string;
    /** Alias legado usado em listagens RH — equivalente a `helpTooltip`. */
    exportHelpText?: string;
    /** Classes no botão de disparo (ex.: alinhar visual ao `ButtonHeaderIcon` do header). */
    className?: string;
    /**
     * `dropdown` (default): menu compacto. `modal`: diálogo com opções (padrão listagens "tipo Movimentos", ver §1.5 do plano
     * `docs/frontend/listagens/plano-rollout-listagem-movimentos.md`).
     */
    exportMenuMode?: 'dropdown' | 'modal';
    /** CSV gerado pela API — mesmos filtros da listagem, até ao limite do servidor (só modal). */
    serverCsvExport?: ExportButtonServerCsvProps;
    /** JSON gerado pela API — mesmos filtros da listagem (só modal). */
    serverJsonExport?: ExportButtonServerJsonProps;
    /**
     * Chave opcional para memorizar colunas no `localStorage` (neste navegador).
     * Se omitida em `exportMenuMode="modal"`, a chave é deduzida da rota, do título e do conjunto de colunas.
     */
    columnsPreferenceStorageKey?: string;
    /** Título da seção de formatos client-side no modal (default: "Formato do arquivo"). */
    clientFormatsSectionTitle?: string;
    /** Chamado após exportação client-side bem-sucedida (página atual). */
    onClientExportComplete?: (
        formato: ExportButtonClientFormat,
        rowCount: number,
        meta?: { columnKeys: string[] },
    ) => void | Promise<void>;
    /** Exige confirmação antes de abrir o diálogo (exportação com dados pessoais / LGPD). */
    piiConfirmationMessage?: string;
    /**
     * Colunas pré-seleccionadas quando não há preferência guardada.
     * Default: todas. Use para omitir PII até opt-in (TASK-PSC-050).
     */
    defaultSelectedColumnKeys?: string[];
}

function wrapTrigger(node: React.ReactElement, helpTooltip: string | undefined) {
    if (!helpTooltip) {
        return node;
    }
    return (
        <Tooltip title={helpTooltip}>
            <span style={{ display: 'inline-block' }}>{node}</span>
        </Tooltip>
    );
}

export default function ExportButton({
    data,
    rows,
    columns,
    endpoint,
    filename = 'export',
    title,
    iconOnly = false,
    size,
    helpTooltip,
    exportHelpText,
    className,
    exportMenuMode = 'dropdown',
    serverCsvExport,
    serverJsonExport,
    columnsPreferenceStorageKey,
    onClientExportComplete,
    clientFormatsSectionTitle,
    piiConfirmationMessage,
    defaultSelectedColumnKeys,
    disabled = false,
}: ExportButtonProps) {
    const exportRows = data ?? rows;
    const pathname = usePathname() ?? '';
    const [loading, setLoading] = useState(false);
    const [exportModalOpen, setExportModalOpen] = useState(false);
    const [selectedColumnKeys, setSelectedColumnKeys] = useState<string[]>([]);

    const exportTitle = title ?? 'Exportar';
    const exportScopeHint = helpTooltip ?? exportHelpText;

    const triggerA11y = iconOnly ? { 'aria-label': exportTitle } : {};

    const allColumnKeys = useMemo(() => (columns ?? []).map((c) => c.key), [columns]);

    const columnPreferenceKey = useMemo(
        () => buildColumnPreferenceStorageKey(columnsPreferenceStorageKey, pathname, exportTitle, allColumnKeys),
        [columnsPreferenceStorageKey, pathname, exportTitle, allColumnKeys],
    );

    const validKeySet = useMemo(() => new Set(allColumnKeys), [allColumnKeys]);

    const resolveInitialColumnKeys = useCallback((): string[] => {
        const valid = allColumnKeys;
        if (valid.length === 0) {
            return [];
        }
        const saved = readSavedColumnKeys(columnPreferenceKey, validKeySet);
        if (!saved) {
            if (defaultSelectedColumnKeys?.length) {
                const preferred = defaultSelectedColumnKeys.filter((k) => validKeySet.has(k));
                if (preferred.length > 0) {
                    return preferred;
                }
            }
            return [...valid];
        }
        const savedSet = new Set(saved);
        const stillThere = valid.filter((k) => savedSet.has(k));
        if (stillThere.length === 0) {
            return [...valid];
        }
        const brandNew = valid.filter((k) => !savedSet.has(k));
        return [...stillThere, ...brandNew];
    }, [allColumnKeys, columnPreferenceKey, validKeySet, defaultSelectedColumnKeys]);

    useEffect(() => {
        if (!exportModalOpen || !columns?.length) {
            return;
        }
        setSelectedColumnKeys(resolveInitialColumnKeys());
    }, [exportModalOpen, columns, resolveInitialColumnKeys]);

    const activeColumns = useMemo(
        () => (columns ?? []).filter((c) => selectedColumnKeys.includes(c.key)),
        [columns, selectedColumnKeys],
    );

    const hasColumnSelection = activeColumns.length > 0;

    if (endpoint) {
        const btn = (
            <Button
                icon={<FileOutput size={ICON_SIZE_MD} aria-hidden />}
                onClick={() => window.open(endpoint, '_blank')}
                loading={loading}
                disabled={disabled}
                title={exportTitle}
                size={size}
                className={className}
                {...triggerA11y}
            >
                {!iconOnly && 'Exportar'}
            </Button>
        );
        return wrapTrigger(btn, exportScopeHint);
    }

    if (!exportRows || !columns || columns.length === 0) {
        const btn = (
            <Button
                icon={<FileOutput size={ICON_SIZE_MD} aria-hidden />}
                disabled={disabled}
                title={exportTitle}
                size={size}
                className={className}
                {...triggerA11y}
            >
                {!iconOnly && 'Exportar'}
            </Button>
        );
        return wrapTrigger(btn, exportScopeHint);
    }

    const notifyClientExportComplete = (formato: ExportButtonClientFormat) => {
        if (!onClientExportComplete || !exportRows) {
            return;
        }
        const count = Array.isArray(exportRows) ? exportRows.length : 0;
        const columnKeys =
            exportMenuMode === 'modal' && activeColumns.length > 0
                ? activeColumns.map((c) => c.key)
                : (columns ?? []).map((c) => c.key);
        void Promise.resolve(onClientExportComplete(formato, count, { columnKeys }));
    };

    const handleExportCSV = (cols: ExportColumn[] = columns) => {
        try {
            exportToCSV(exportRows as Record<string, unknown>[], cols, `${filename}.csv`);
            message.success('Arquivo CSV exportado com sucesso!');
            notifyClientExportComplete('csv');
        } catch {
            message.error('Erro ao exportar CSV');
        }
    };

    const handleExportJSON = (cols?: ExportColumn[]) => {
        try {
            if (cols && cols.length > 0) {
                exportToJSONWithColumns(exportRows as Record<string, unknown>[], cols, `${filename}.json`);
            } else {
                exportToJSON(exportRows, `${filename}.json`);
            }
            message.success('Arquivo JSON exportado com sucesso!');
            notifyClientExportComplete('json');
        } catch {
            message.error('Erro ao exportar JSON');
        }
    };

    const handleExportExcel = async (cols: ExportColumn[] = columns) => {
        try {
            setLoading(true);
            await exportToExcel(exportRows as Record<string, unknown>[], cols, `${filename}.xlsx`);
            message.success('Arquivo Excel exportado com sucesso!');
            notifyClientExportComplete('excel');
        } catch {
            message.error('Erro ao exportar Excel');
        } finally {
            setLoading(false);
        }
    };

    const handleExportPDF = async (cols: ExportColumn[] = columns) => {
        try {
            setLoading(true);
            await exportToPDF(
                exportRows as Record<string, unknown>[],
                cols,
                `${filename}.pdf`,
                title || 'Relatório',
            );
            message.success('Arquivo PDF exportado com sucesso!');
            notifyClientExportComplete('pdf');
        } catch {
            message.error('Erro ao exportar PDF');
        } finally {
            setLoading(false);
        }
    };

    const menuItems: MenuProps['items'] = [
        {
            key: 'excel',
            label: 'Exportar Excel',
            icon: <FileSpreadsheet size={ICON_SIZE_MD} aria-hidden />,
            onClick: () => void handleExportExcel(),
        },
        {
            key: 'pdf',
            label: 'Exportar PDF',
            icon: <FileText size={ICON_SIZE_MD} aria-hidden />,
            onClick: () => void handleExportPDF(),
        },
        {
            type: 'divider',
        },
        {
            key: 'csv',
            label: 'Exportar CSV',
            icon: <FileText size={ICON_SIZE_MD} aria-hidden />,
            onClick: () => handleExportCSV(),
        },
        {
            key: 'json',
            label: 'Exportar JSON',
            icon: <FileText size={ICON_SIZE_MD} aria-hidden />,
            onClick: () => handleExportJSON(),
        },
    ];

    const openExportModal = () => {
        if (piiConfirmationMessage) {
            confirmDialog({
                title: 'Confirmar exportação',
                content: piiConfirmationMessage,
                okText: 'Continuar',
                cancelText: 'Cancelar',
                onOk: () => setExportModalOpen(true),
            });
            return;
        }
        setExportModalOpen(true);
    };
    const closeExportModal = () => setExportModalOpen(false);

    const runInModal = (fn: () => void | Promise<void>) => {
        closeExportModal();
        void Promise.resolve(fn());
    };

    const handleSaveColumnPreference = () => {
        if (!hasColumnSelection) {
            message.warning('Selecione pelo menos uma coluna para salvar.');
            return;
        }
        writeSavedColumnKeys(columnPreferenceKey, selectedColumnKeys);
        message.success('Preferência de colunas guardada neste navegador.');
    };

    const handleClearColumnPreference = () => {
        clearSavedColumnKeys(columnPreferenceKey);
        setSelectedColumnKeys([...allColumnKeys]);
        message.info('Preferência de colunas reposta (todas as colunas).');
    };

    if (exportMenuMode === 'modal') {
        const triggerBtn = (
            <Button
                icon={<FileOutput size={ICON_SIZE_MD} aria-hidden />}
                loading={loading}
                disabled={disabled}
                title={exportTitle}
                size={size}
                className={className}
                onClick={openExportModal}
                {...triggerA11y}
            >
                {!iconOnly && 'Exportar'}
            </Button>
        );

        const checkboxOptions = columns.map((c) => ({ label: c.label, value: c.key }));

        const clientExportFormats: Array<{
            key: string;
            label: string;
            hint: string;
            icon: React.ReactNode;
            onClick: () => void;
        }> = [
            {
                key: 'excel',
                label: 'Excel',
                hint: 'Planilha .xlsx',
                icon: <FileSpreadsheet size={ICON_SIZE_MD} aria-hidden />,
                onClick: () => runInModal(() => void handleExportExcel(activeColumns)),
            },
            {
                key: 'pdf',
                label: 'PDF',
                hint: 'Relatório para impressão',
                icon: <FileText size={ICON_SIZE_MD} aria-hidden />,
                onClick: () => runInModal(() => void handleExportPDF(activeColumns)),
            },
            {
                key: 'csv',
                label: 'CSV',
                hint: 'Texto separado por vírgulas',
                icon: <FileText size={ICON_SIZE_MD} aria-hidden />,
                onClick: () => runInModal(() => handleExportCSV(activeColumns)),
            },
            {
                key: 'json',
                label: 'JSON',
                hint: 'Dados estruturados',
                icon: <Braces size={ICON_SIZE_MD} aria-hidden />,
                onClick: () => runInModal(() => handleExportJSON(activeColumns)),
            },
        ];

        return (
            <>
                {wrapTrigger(triggerBtn, exportScopeHint)}
                <Modal
                    title={exportTitle}
                    open={exportModalOpen}
                    onCancel={closeExportModal}
                    footer={null}
                    destroyOnHidden
                    centered
                    width={520}
                    className={styles.exportModal}
                >
                    <Space direction="vertical" size="middle" style={{ width: '100%' }}>
                        {exportScopeHint ? (
                            <Alert
                                type="info"
                                showIcon
                                message={exportScopeHint}
                                className={styles.scopeHint}
                            />
                        ) : null}

                        <div className={styles.section}>
                            <div className={styles.sectionHeader}>
                                <div>
                                    <Typography.Text strong className={styles.sectionTitle}>
                                        Colunas na exportação
                                    </Typography.Text>
                                    <Typography.Paragraph type="secondary" className={styles.sectionHint}>
                                        Escolha os campos e, se quiser, salve a seleção para exportações futuras neste
                                        navegador.
                                    </Typography.Paragraph>
                                </div>
                                <div className={styles.quickActions}>
                                    <Button
                                        type="link"
                                        size="small"
                                        onClick={() => setSelectedColumnKeys([...allColumnKeys])}
                                    >
                                        Marcar todas
                                    </Button>
                                    <Button
                                        type="link"
                                        size="small"
                                        onClick={() => {
                                            if (allColumnKeys.length > 0) {
                                                setSelectedColumnKeys([allColumnKeys[0]]);
                                            }
                                        }}
                                    >
                                        Só a primeira
                                    </Button>
                                </div>
                            </div>

                            <div className={styles.columnPanel}>
                                <div className={styles.columnGrid}>
                                    <Checkbox.Group
                                        options={checkboxOptions}
                                        value={selectedColumnKeys}
                                        onChange={(vals) => setSelectedColumnKeys(vals as string[])}
                                    />
                                </div>
                            </div>

                            <div className={styles.preferenceRow}>
                                <Button
                                    type="default"
                                    size="small"
                                    icon={<Save size={ICON_SIZE_MD} aria-hidden />}
                                    onClick={handleSaveColumnPreference}
                                >
                                    Salvar preferência
                                </Button>
                                <Button type="link" size="small" onClick={handleClearColumnPreference}>
                                    Restaurar padrão
                                </Button>
                            </div>

                            {!hasColumnSelection ? (
                                <Typography.Text type="danger" className={styles.validationError}>
                                    Selecione pelo menos uma coluna para exportar.
                                </Typography.Text>
                            ) : null}
                        </div>

                        <Divider style={{ margin: '4px 0' }} />

                        <div className={styles.section}>
                            <Typography.Text strong className={styles.sectionTitle}>
                                {clientFormatsSectionTitle ?? 'Formato do arquivo'}
                            </Typography.Text>
                            <div className={styles.formatGrid}>
                                {clientExportFormats.map((format) => (
                                    <button
                                        key={format.key}
                                        type="button"
                                        className={styles.formatCard}
                                        disabled={loading || !hasColumnSelection}
                                        onClick={format.onClick}
                                    >
                                        <span className={styles.formatCardIcon}>{format.icon}</span>
                                        <span className={styles.formatCardLabel}>{format.label}</span>
                                        <span className={styles.formatCardHint}>{format.hint}</span>
                                    </button>
                                ))}
                            </div>
                        </div>

                        {serverCsvExport || serverJsonExport ? (
                            <div className={styles.serverSection}>
                                <Typography.Paragraph type="secondary" className={styles.serverHint}>
                                    {serverCsvExport?.applyColumnSelection
                                        ? 'Listagem completa com os filtros ativos (limite na API). A seleção de colunas acima aplica-se ao CSV filtrado.'
                                        : 'Listagem completa com os filtros ativos (limite definido na API). A seleção de colunas acima não se aplica a estas exportações.'}
                                </Typography.Paragraph>
                                <div className={styles.formatGrid}>
                                    {serverCsvExport ? (
                                        <button
                                            type="button"
                                            className={styles.formatCard}
                                            disabled={
                                                loading ||
                                                Boolean(serverCsvExport.loading) ||
                                                (Boolean(serverCsvExport.applyColumnSelection) &&
                                                    !hasColumnSelection)
                                            }
                                            data-testid={
                                                serverCsvExport['data-testid'] ?? 'export-button-server-csv'
                                            }
                                            onClick={() =>
                                                runInModal(() =>
                                                    void serverCsvExport.onDownload(
                                                        serverCsvExport.applyColumnSelection
                                                            ? { columnKeys: [...selectedColumnKeys] }
                                                            : undefined,
                                                    ),
                                                )
                                            }
                                        >
                                            <span className={styles.formatCardIcon}>
                                                <Download size={ICON_SIZE_MD} aria-hidden />
                                            </span>
                                            <span className={styles.formatCardLabel}>{serverCsvExport.label}</span>
                                            {serverCsvExport.description ? (
                                                <span className={styles.formatCardHint}>
                                                    {serverCsvExport.description}
                                                </span>
                                            ) : null}
                                        </button>
                                    ) : null}
                                    {serverJsonExport ? (
                                        <button
                                            type="button"
                                            className={styles.formatCard}
                                            disabled={loading || Boolean(serverJsonExport.loading)}
                                            data-testid="export-button-server-json"
                                            onClick={() => runInModal(() => void serverJsonExport.onDownload())}
                                        >
                                            <span className={styles.formatCardIcon}>
                                                <Download size={ICON_SIZE_MD} aria-hidden />
                                            </span>
                                            <span className={styles.formatCardLabel}>{serverJsonExport.label}</span>
                                            {serverJsonExport.description ? (
                                                <span className={styles.formatCardHint}>
                                                    {serverJsonExport.description}
                                                </span>
                                            ) : null}
                                        </button>
                                    ) : null}
                                </div>
                            </div>
                        ) : null}
                    </Space>
                </Modal>
            </>
        );
    }

    const trigger = (
        <Dropdown menu={{ items: menuItems }} trigger={['click']}>
            <Button
                icon={<FileOutput size={ICON_SIZE_MD} aria-hidden />}
                loading={loading}
                disabled={disabled}
                title={exportTitle}
                size={size}
                className={className}
                {...triggerA11y}
            >
                {!iconOnly && 'Exportar'}
            </Button>
        </Dropdown>
    );

    return wrapTrigger(trigger, exportScopeHint);
}
