'use client';

import React, { useEffect, useMemo, useRef, useState } from 'react';
import { Alert, Button, Modal, Progress, Space, Table, Tag, Typography, Upload } from 'antd';
import type { UploadFile } from 'antd/es/upload';
import { Download, Upload as UploadIcon } from 'lucide-react';

import { ICON_SIZE_MD } from '@/components/icons';
import {
    mergeWaygestFormModalBodyStyles,
    useWaygestFormModalProps,
    waygestFormModalFooterClassName,
} from '@/hooks/useWaygestFormModalProps';
import { message } from '@/lib/feedback/message';
import { getLaravelApiErrorMessage } from '@/lib/api/laravelApiErrorMessage';
import {
    importarProjetoEntidadeCsvCommit,
    importarProjetoEntidadeCsvDryRun,
} from './projetoEntidadeImportCsvService';
import {
    downloadProjetoImportCsvErros,
    downloadProjetoImportCsvFalhasCommit,
} from './projetoImportCsvErrosDownload';
import { downloadModulosImportCsvTemplate } from './projetoModulosImportCsvTemplate';
import { downloadRequisitosImportCsvTemplate } from './projetoRequisitosImportCsvTemplate';
import {
    PROJETO_IMPORT_CSV_MAX_LINHAS_DRY_RUN,
    type ProjetoImportCsvBatch,
    type ProjetoImportCsvKind,
    type ProjetoImportCsvLinhaDetalhe,
    type ProjetoImportCsvLinhaStatus,
} from './types';
import { useProjetoEntidadeImportCsvPolling } from './useProjetoEntidadeImportCsvPolling';

const { Paragraph, Text } = Typography;

export type ProjetoEntidadeImportCsvModalProps = {
    open: boolean;
    onClose: () => void;
    /** Refetch da listagem após commit concluído com importações. */
    onSuccess?: () => void | Promise<void>;
    projetoId: string;
    kind: ProjetoImportCsvKind;
};

type Step = 'upload' | 'preview' | 'progress' | 'done';

const STATUS_TAG_COLOR: Record<ProjetoImportCsvLinhaStatus, string> = {
    ok: 'success',
    aviso: 'warning',
    erro: 'error',
};

const STATUS_LABEL: Record<ProjetoImportCsvLinhaStatus, string> = {
    ok: 'OK',
    aviso: 'Aviso',
    erro: 'Erro',
};

const COPY: Record<
    ProjetoImportCsvKind,
    {
        title: string;
        entitySingular: string;
        entityPlural: string;
        columnsHint: React.ReactNode;
        templateDownload: () => void;
        testId: string;
    }
> = {
    requisitos: {
        title: 'Importar requisitos (CSV)',
        entitySingular: 'requisito',
        entityPlural: 'requisitos',
        columnsHint: (
            <>
                Obrigatório: <Text code>titulo</Text>. Opcionais: <Text code>prioridade</Text>,{' '}
                <Text code>tipo</Text>, <Text code>status</Text>, <Text code>modulo_codigo</Text>,{' '}
                <Text code>external_id</Text>, <Text code>descricao</Text>, <Text code>codigo</Text>.
            </>
        ),
        templateDownload: () => downloadRequisitosImportCsvTemplate(),
        testId: 'projeto-requisitos-import-csv-modal',
    },
    modulos: {
        title: 'Importar módulos (CSV)',
        entitySingular: 'módulo',
        entityPlural: 'módulos',
        columnsHint: (
            <>
                Informe <Text code>nome</Text> e/ou <Text code>codigo</Text>. Opcionais:{' '}
                <Text code>status_modulo</Text> (alias <Text code>status</Text>), <Text code>ordem</Text>,{' '}
                <Text code>external_id</Text>, <Text code>descricao</Text>.
            </>
        ),
        templateDownload: () => downloadModulosImportCsvTemplate(),
        testId: 'projeto-modulos-import-csv-modal',
    },
};

function importProgressPercent(batch: ProjetoImportCsvBatch | null): number {
    if (!batch) return 0;
    if (batch.status === 'done' || batch.status === 'failed' || batch.status === 'cancelled') {
        return 100;
    }
    if (batch.status === 'processing') return 55;
    if (batch.status === 'queued') return 15;
    return 0;
}

function isCsvFile(file: File): boolean {
    return /\.csv$/i.test(file.name) || file.type === 'text/csv';
}

/**
 * Modal de importação CSV requisitos/módulos: upload → dry-run → relatório → commit + poll.
 *
 * Espelha `MovimentosImportCsvModal`. AuthZ: update no projecto (CTA na tela via write gates).
 */
export function ProjetoEntidadeImportCsvModal({
    open,
    onClose,
    onSuccess,
    projetoId,
    kind,
}: ProjetoEntidadeImportCsvModalProps) {
    const modalLayout = useWaygestFormModalProps();
    const copy = COPY[kind];
    const importPoll = useProjetoEntidadeImportCsvPolling({ kind, projetoId });

    const [fileList, setFileList] = useState<UploadFile[]>([]);
    const [busy, setBusy] = useState(false);
    const [step, setStep] = useState<Step>('upload');
    const [preview, setPreview] = useState<ProjetoImportCsvBatch | null>(null);
    const processedTerminalRef = useRef<string | null>(null);

    const resetState = () => {
        setFileList([]);
        setStep('upload');
        setPreview(null);
        setBusy(false);
        processedTerminalRef.current = null;
        importPoll.reset();
    };

    useEffect(() => {
        if (!importPoll.isTerminal || !importPoll.batch) {
            return;
        }

        const terminalKey = `${importPoll.batch.batch_id}:${importPoll.batch.status}`;
        if (processedTerminalRef.current === terminalKey) {
            return;
        }
        processedTerminalRef.current = terminalKey;

        const batch = importPoll.batch;
        setStep('done');

        if (batch.status === 'cancelled') {
            message.info('Importação cancelada.');
            return;
        }

        if (batch.status === 'failed') {
            message.error(
                batch.error_message ||
                    'A importação falhou. Verifique o arquivo e tente novamente.',
            );
            return;
        }

        const importadas = batch.linhas_importadas ?? 0;
        const falhasCommit = batch.relatorio?.falhas_commit?.length ?? 0;

        if (importadas > 0 && falhasCommit === 0) {
            message.success(
                importadas === 1
                    ? `1 ${copy.entitySingular} importado com sucesso.`
                    : `${importadas} ${copy.entityPlural} importados com sucesso.`,
            );
            void onSuccess?.();
            return;
        }

        if (importadas > 0 && falhasCommit > 0) {
            message.warning(
                `Importação parcial: ${importadas} importado(s), ${falhasCommit} falha(s) no commit.`,
            );
            void onSuccess?.();
            return;
        }

        message.error(
            'Nenhum registro foi importado. Corrija o arquivo ou tente novamente.',
        );
    }, [copy.entityPlural, copy.entitySingular, importPoll.batch, importPoll.isTerminal, onSuccess]);

    const handleClose = () => {
        if (busy || importPoll.polling) return;
        resetState();
        onClose();
    };

    const handlePreview = async () => {
        const file = fileList[0]?.originFileObj;
        if (!file) {
            message.warning('Selecione um arquivo CSV.');
            return;
        }

        setBusy(true);
        try {
            const data = await importarProjetoEntidadeCsvDryRun(kind, projetoId, file);
            setPreview(data);
            setStep('preview');
        } catch (error: unknown) {
            message.error(
                getLaravelApiErrorMessage(
                    error,
                    'Não foi possível pré-visualizar o CSV. Verifique o arquivo e tente novamente.',
                ),
            );
        } finally {
            setBusy(false);
        }
    };

    const handleCommit = async () => {
        const batchId = preview?.batch_id || preview?.id;
        if (!batchId) {
            message.warning('Selecione um arquivo CSV.');
            return;
        }

        const importaveis = (preview?.linhas_ok ?? 0) + (preview?.linhas_aviso ?? 0);
        if (importaveis === 0) {
            message.warning('Não há linhas válidas para importar. Corrija o CSV.');
            return;
        }

        setBusy(true);
        try {
            const data = await importarProjetoEntidadeCsvCommit(kind, projetoId, batchId);
            setStep('progress');
            importPoll.start(data.batch_id || batchId, data);
        } catch (error: unknown) {
            message.error(
                getLaravelApiErrorMessage(
                    error,
                    'Não foi possível confirmar a importação. Tente novamente.',
                ),
            );
        } finally {
            setBusy(false);
        }
    };

    const previewLinhas = useMemo((): ProjetoImportCsvLinhaDetalhe[] => {
        return preview?.relatorio?.linhas ?? [];
    }, [preview]);

    const errosDryRun = useMemo(
        () => previewLinhas.filter((l) => l.status === 'erro' || l.status === 'aviso'),
        [previewLinhas],
    );
    const falhasCommit = importPoll.batch?.relatorio?.falhas_commit ?? [];
    const canCommit =
        ((preview?.linhas_ok ?? 0) + (preview?.linhas_aviso ?? 0)) > 0 &&
        preview?.status === 'dry_run';

    const progressBatch = importPoll.batch ?? preview;
    const progressPercent = importProgressPercent(progressBatch);
    const progressException =
        progressBatch?.status === 'failed' || importPoll.pollError === 'timeout';

    const footer = (
        <div className={waygestFormModalFooterClassName}>
            {step === 'progress' ? (
                <Button onClick={handleClose} disabled={importPoll.polling}>
                    {importPoll.polling ? 'A processar…' : 'Fechar'}
                </Button>
            ) : step === 'done' ? (
                <>
                    {falhasCommit.length > 0 ? (
                        <Button
                            onClick={() => downloadProjetoImportCsvFalhasCommit(falhasCommit)}
                            data-testid={`${copy.testId}-falhas-commit-download`}
                        >
                            Baixar falhas do commit
                        </Button>
                    ) : null}
                    <Button
                        type="primary"
                        onClick={() => {
                            resetState();
                            onClose();
                        }}
                        data-testid={`${copy.testId}-fechar-done`}
                    >
                        Fechar
                    </Button>
                </>
            ) : step === 'upload' ? (
                <>
                    <Button
                        icon={<Download size={ICON_SIZE_MD} aria-hidden />}
                        onClick={() => copy.templateDownload()}
                        disabled={busy}
                        data-testid={`${copy.testId}-download-template`}
                    >
                        Baixar template
                    </Button>
                    <Button onClick={handleClose} disabled={busy}>
                        Cancelar
                    </Button>
                    <Button
                        type="primary"
                        loading={busy}
                        disabled={fileList.length === 0}
                        onClick={() => void handlePreview()}
                        data-testid={`${copy.testId}-preview`}
                    >
                        Pré-visualizar
                    </Button>
                </>
            ) : (
                <>
                    <Button onClick={() => setStep('upload')} disabled={busy}>
                        Voltar
                    </Button>
                    <Button
                        onClick={() => downloadProjetoImportCsvErros(errosDryRun)}
                        disabled={errosDryRun.length === 0}
                        data-testid={`${copy.testId}-erros-download`}
                    >
                        Baixar erros
                    </Button>
                    <Button
                        type="primary"
                        loading={busy}
                        disabled={!canCommit}
                        onClick={() => void handleCommit()}
                        data-testid={`${copy.testId}-commit`}
                    >
                        Confirmar importação
                    </Button>
                </>
            )}
        </div>
    );

    const modalWidth =
        step === 'preview' || step === 'done'
            ? Math.max(Number(modalLayout.width ?? 720), 920)
            : step === 'progress'
              ? 560
              : (modalLayout.width ?? 720);

    return (
        <Modal
            title={copy.title}
            open={open}
            onCancel={handleClose}
            destroyOnHidden
            width={modalWidth}
            centered={modalLayout.centered ?? true}
            className={modalLayout.className}
            styles={mergeWaygestFormModalBodyStyles(modalLayout, {
                body: { maxHeight: 'min(75vh, calc(100vh - 180px))', overflowY: 'auto' },
            })}
            zIndex={modalLayout.zIndex}
            footer={footer}
            data-testid={copy.testId}
        >
            {step === 'progress' || (step === 'done' && importPoll.batch) ? (
                <Space direction="vertical" size={12} style={{ width: '100%' }}>
                    <Paragraph style={{ marginBottom: 0 }}>
                        {step === 'progress'
                            ? 'A importação está em fila. Não feche esta janela até concluir.'
                            : 'Processamento concluído.'}
                    </Paragraph>
                    <Progress
                        percent={progressPercent}
                        status={
                            progressException
                                ? 'exception'
                                : step === 'done' && progressBatch?.status === 'done'
                                  ? 'success'
                                  : 'active'
                        }
                        aria-label="Progresso da importação CSV"
                    />
                    <Text type="secondary" style={{ fontSize: 12 }}>
                        {progressBatch?.status === 'queued'
                            ? 'Na fila…'
                            : progressBatch?.status === 'processing'
                              ? 'A processar linhas…'
                              : progressBatch?.status === 'done'
                                ? `Importados: ${progressBatch.linhas_importadas ?? 0}. Falhas no commit: ${falhasCommit.length}.`
                                : progressBatch?.status === 'failed'
                                  ? progressBatch.error_message ||
                                    'A importação falhou.'
                                  : importPoll.pollError === 'timeout'
                                    ? 'Tempo esgotado ao asalvar o processamento. Atualize a listagem ou tente novamente.'
                                    : null}
                    </Text>
                    {step === 'done' && falhasCommit.length > 0 ? (
                        <Alert
                            type="warning"
                            showIcon
                            message={`${falhasCommit.length} linha(s) falharam no commit. Baixe o relatório para corrigir.`}
                        />
                    ) : null}
                </Space>
            ) : step === 'upload' ? (
                <>
                    <Paragraph type="secondary" style={{ marginBottom: 8 }}>
                        Ficheiro CSV em <Text strong>UTF-8</Text> (máx.{' '}
                        {PROJETO_IMPORT_CSV_MAX_LINHAS_DRY_RUN} linhas no dry-run). A pré-visualização{' '}
                        <Text strong>não grava</Text> registos — só após confirmar a importação.
                    </Paragraph>
                    <Paragraph style={{ marginBottom: 16, fontSize: 13 }}>{copy.columnsHint}</Paragraph>

                    <Upload.Dragger
                        accept=".csv,text/csv"
                        maxCount={1}
                        fileList={fileList}
                        disabled={busy}
                        beforeUpload={(file) => {
                            if (!isCsvFile(file)) {
                                message.error('Use um arquivo .csv');
                                return Upload.LIST_IGNORE;
                            }
                            setPreview(null);
                            setStep('upload');
                            setFileList([
                                {
                                    uid: file.uid,
                                    name: file.name,
                                    status: 'done',
                                    originFileObj: file,
                                },
                            ]);
                            return false;
                        }}
                        onRemove={() => {
                            if (busy) return false;
                            setFileList([]);
                            setPreview(null);
                        }}
                        data-testid={`${copy.testId}-upload`}
                    >
                        <p className="ant-upload-drag-icon">
                            <UploadIcon size={ICON_SIZE_MD} aria-hidden />
                        </p>
                        <p className="ant-upload-text">Arraste o CSV ou clique para selecionar</p>
                    </Upload.Dragger>
                </>
            ) : (
                <>
                    {preview ? (
                        <Paragraph style={{ marginBottom: 12 }}>
                            Pré-visualização: {preview.linhas_ok} OK, {preview.linhas_aviso} aviso(s),{' '}
                            {preview.linhas_erro} erro(s) — total {preview.total_linhas} linha(s).
                        </Paragraph>
                    ) : null}
                    {!canCommit ? (
                        <Alert
                            type="error"
                            showIcon
                            style={{ marginBottom: 12 }}
                            message="Não há linhas válidas para importar. Corrija o CSV e volte a pré-visualizar."
                        />
                    ) : null}
                    <Table
                        size="small"
                        rowKey={(row: any) => `${row.linha}-${row.status}`}
                        pagination={{ pageSize: 8, hideOnSinglePage: true }}
                        scroll={{ x: 640 }}
                        dataSource={previewLinhas}
                        locale={{ emptyText: 'Sem linhas no relatório.' }}
                        data-testid={`${copy.testId}-preview-table`}
                        columns={[
                            {
                                title: 'Linha',
                                dataIndex: 'linha',
                                width: 72,
                            },
                            {
                                title: 'Estado',
                                dataIndex: 'status',
                                width: 100,
                                render: (status: ProjetoImportCsvLinhaStatus) => (
                                    <Tag color={STATUS_TAG_COLOR[status]}>
                                        {STATUS_LABEL[status] ?? status}
                                    </Tag>
                                ),
                            },
                            {
                                title: 'Detalhe',
                                key: 'motivo',
                                render: (_: unknown, row: ProjetoImportCsvLinhaDetalhe) =>
                                    row.motivo || '—',
                            },
                        ]}
                    />
                    {errosDryRun.length > 0 ? (
                        <Paragraph type="danger" style={{ marginTop: 12, marginBottom: 0 }}>
                            {errosDryRun.length} linha(s) com erro ou aviso — corrija antes de confirmar
                            ou importe só as válidas.
                        </Paragraph>
                    ) : null}
                </>
            )}
        </Modal>
    );
}
