'use client';

/**
 * Detalhe da release com checklist por superfície e transição de status
 * (gate `publicada` + override auditado — TASK-PPS-004 UX).
 *
 * Checklist: alterações locais acumuladas + um PATCH batch (`updateSuperficies`)
 * via "Salvar checklist" (TASK-PPS-025 / PPS-TEC-023).
 *
 * @route /projetos/[id]/produto/releases/[releaseId]
 */

import { ArrowLeft, CheckCircle2, Copy, ListChecks, Save } from 'lucide-react';
import Link from 'next/link';
import React, { useEffect, useMemo, useState } from 'react';
import { useParams, useRouter } from 'next/navigation';
import {
    Alert,
    Button,
    Descriptions,
    Select,
    Space,
    Table,
    Tag,
    Tooltip,
    Typography,
} from 'antd';
import { message } from '@/lib/feedback/message';
import { confirmDialog } from '@/lib/feedback/confirmDialog';
import ProjetoLayout from '@/components/layouts/ProjetoLayout';
import ContentCard from '@/components/layouts/ContentCard';
import { useQueryCache } from '@/hooks/useQueryCache';
import { useMutationCache } from '@/hooks/useMutationCache';
import { API_ENDPOINTS } from '@/lib/api/endpoints';
import { extractProjetoApiErrorMessage } from '@/features/projetos/utils/extractProjetoApiErrorMessage';
import { ProdutoSoftwareTipoFetchErrorAlert } from '@/features/projetos/components/ProdutoSoftwareTipoFetchErrorAlert';
import {
    isProdutoSoftwareTipoDisabledError,
    mensagemProdutoSoftwareTipoDisabled,
} from '@/features/projetos/utils/produtoSoftwareTipoKillSwitch';
import { useProjetoWriteGates } from '@/features/projetos/hooks/useProjetoWriteGates';
import { ModalDuplicarRelease } from '@/features/projetos/projeto-produto-releases/components/ModalDuplicarRelease';
import { ModalOverridePublicacaoRelease } from '@/features/projetos/projeto-produto-releases/components/ModalOverridePublicacaoRelease';
import {
    buildOverridePublicacaoReleaseBody,
    isReleasePublicacaoGateError,
    mensagemReleasePublicacaoGate,
} from '@/features/projetos/projeto-produto-releases/utils/releasePublicacaoGate';
import { recordProdutoReleasePublished } from '@/lib/telemetry/produtoSoftwareTelemetry';
import {
    RELEASE_STATUS_LABEL,
    SUPERFICIE_STATUS_LABEL,
    type ProdutoReleaseDetalhe,
    type ProdutoReleaseStatus,
    type ProdutoReleaseSuperficie,
    type ProdutoReleaseSuperficieStatus,
} from '@/features/projetos/projeto-produto-releases/types';
import {
    projetoProdutoReleaseDetailQueryKey,
    projetoProdutoReleasesQueryKey,
} from '@/features/projetos/projeto-produto-releases/utils/produtoQueryKeys';
import { LoadingState } from '@/components/ui/LoadingState';

type ReleaseApiResponse = { data: ProdutoReleaseDetalhe };

type UpdateReleaseVars = {
    status?: ProdutoReleaseStatus;
    override_publicacao?: boolean;
    motivo_override?: string;
};

type UpdateSuperficiesVars = {
    superficies: Array<{
        projeto_id: number;
        status: ProdutoReleaseSuperficieStatus;
    }>;
};

/** Body opcional do POST marcar-prontas (omitir = todas). */
type MarcarProntasVars = {
    projeto_ids?: number[];
};

type MarcarProntasApiResponse = {
    data: ProdutoReleaseDetalhe;
    message?: string;
};

/** Rascunho local do checklist: chave = `projeto_id` da superfície. */
type DraftSuperficieStatuses = Partial<Record<number, ProdutoReleaseSuperficieStatus>>;

const SUPERFICIE_STATUS_OPTIONS = Object.entries(SUPERFICIE_STATUS_LABEL).map(([value, label]) => ({
    value,
    label,
}));

const RELEASE_STATUS_OPTIONS = Object.entries(RELEASE_STATUS_LABEL).map(([value, label]) => ({
    value,
    label,
}));

export function ProjetoProdutoReleaseDetalheScreen() {
    const params = useParams();
    const router = useRouter();
    const projetoId = params?.id as string;
    const releaseId = params?.releaseId as string;

    const { canEditar, canOverrideUat, tooltipSemPermissao } = useProjetoWriteGates();

    const [overrideGate, setOverrideGate] = useState<{ message: string } | null>(null);
    const [draftStatuses, setDraftStatuses] = useState<DraftSuperficieStatuses>({});
    const [duplicarOpen, setDuplicarOpen] = useState(false);

    useEffect(() => {
        setDraftStatuses({});
    }, [projetoId, releaseId]);

    const detailQueryKey = projetoProdutoReleaseDetailQueryKey(projetoId, releaseId);

    const { data, isLoading, isError, error, refetch } = useQueryCache<ReleaseApiResponse>({
        queryKey: detailQueryKey,
        endpoint: API_ENDPOINTS.projetos.releases.show(projetoId, releaseId),
        enabled: Boolean(projetoId && releaseId),
    });

    const updateReleaseMutation = useMutationCache<unknown, UpdateReleaseVars>({
        endpoint: API_ENDPOINTS.projetos.releases.update(projetoId, releaseId),
        method: 'PATCH',
        invalidateQueries: [detailQueryKey, projetoProdutoReleasesQueryKey(projetoId)],
        buildBody: (vars) => {
            if (vars.override_publicacao === true && vars.motivo_override) {
                return {
                    status: 'publicada' as const,
                    override_publicacao: true,
                    motivo_override: vars.motivo_override,
                };
            }
            return { status: vars.status };
        },
    });

    const updateSuperficiesMutation = useMutationCache<unknown, UpdateSuperficiesVars>({
        endpoint: API_ENDPOINTS.projetos.releases.updateSuperficies(projetoId, releaseId),
        method: 'PATCH',
        invalidateQueries: [detailQueryKey, projetoProdutoReleasesQueryKey(projetoId)],
    });

    /** TASK-PPS-061 — POST bulk readiness (body vazio = todas as superfícies). */
    const marcarProntasMutation = useMutationCache<MarcarProntasApiResponse, MarcarProntasVars>({
        endpoint: API_ENDPOINTS.projetos.releases.marcarProntas(projetoId, releaseId),
        method: 'POST',
        invalidateQueries: [detailQueryKey, projetoProdutoReleasesQueryKey(projetoId)],
        buildBody: (vars) =>
            vars.projeto_ids?.length ? { projeto_ids: vars.projeto_ids } : {},
        retry: 0,
    });

    const release = data?.data;

    const getEffectiveStatus = (row: ProdutoReleaseSuperficie): ProdutoReleaseSuperficieStatus =>
        draftStatuses[row.projeto_id] ?? row.status;

    const dirtySuperficies = useMemo((): UpdateSuperficiesVars['superficies'] => {
        if (!release?.superficies?.length) return [];
        return release.superficies
            .filter((s) => {
                const draft = draftStatuses[s.projeto_id];
                return draft != null && draft !== s.status;
            })
            .map((s) => ({
                projeto_id: s.projeto_id,
                status: draftStatuses[s.projeto_id] as ProdutoReleaseSuperficieStatus,
            }));
    }, [release?.superficies, draftStatuses]);

    const isChecklistDirty = dirtySuperficies.length > 0;

    const prontasCount = useMemo(() => {
        if (!release?.superficies?.length) return 0;
        return release.superficies.filter(
            (s) => (draftStatuses[s.projeto_id] ?? s.status) === 'pronto',
        ).length;
    }, [release?.superficies, draftStatuses]);

    const bloqueadasCount = useMemo(() => {
        if (!release?.superficies?.length) return 0;
        return release.superficies.filter(
            (s) => (draftStatuses[s.projeto_id] ?? s.status) === 'bloqueado',
        ).length;
    }, [release?.superficies, draftStatuses]);

    /**
     * Preferir `readiness` do show (TASK-PPS-060); com rascunho local dirty, recalcular.
     */
    const readinessEfectivo = useMemo(() => {
        const total = release?.superficies?.length ?? release?.readiness?.total ?? 0;
        if (isChecklistDirty || !release?.readiness) {
            const prontas = prontasCount;
            const bloqueadas = bloqueadasCount;
            const pendentes = Math.max(0, total - prontas - bloqueadas);
            return {
                total,
                prontas,
                pendentes,
                bloqueadas,
                todas_prontas: total > 0 && prontas === total,
            };
        }
        return release.readiness;
    }, [
        release?.superficies?.length,
        release?.readiness,
        isChecklistDirty,
        prontasCount,
        bloqueadasCount,
    ]);

    const handleMarcarTodasProntas = () => {
        if (!release || !canEditar) return;
        const total = readinessEfectivo.total;
        const bloqueadas = readinessEfectivo.bloqueadas;
        const content =
            bloqueadas > 0
                ? `Vai marcar as ${total} superfície${total === 1 ? '' : 's'} como prontas, incluindo ${bloqueadas} actualmente bloqueada${bloqueadas === 1 ? '' : 's'}. Alterações locais do checklist serão descartadas.`
                : `Vai marcar as ${total} superfície${total === 1 ? '' : 's'} como prontas numa única ação. Alterações locais do checklist serão descartadas.`;

        void confirmDialog({
            title: 'Marcar todas prontas?',
            content,
            okText: 'Marcar todas prontas',
            onOk: async () => {
                try {
                    const response = await marcarProntasMutation.mutateAsync({});
                    setDraftStatuses({});
                    const bulk = response?.data?.bulk;
                    const atualizados = bulk?.atualizados ?? total;
                    message.success(
                        atualizados === 1
                            ? '1 superfície marcada como pronta.'
                            : `${atualizados} superfícies marcadas como prontas.`,
                    );
                } catch (err) {
                    if (isProdutoSoftwareTipoDisabledError(err)) {
                        message.warning(mensagemProdutoSoftwareTipoDisabled(err));
                        return;
                    }
                    message.error(
                        extractProjetoApiErrorMessage(
                            err,
                            'Não foi possível marcar as superfícies como prontas.',
                        ),
                    );
                }
            },
        });
    };

    const handleStatusChange = async (status: ProdutoReleaseStatus) => {
        try {
            await updateReleaseMutation.mutateAsync({ status });
            setOverrideGate(null);
            if (status === 'publicada') {
                recordProdutoReleasePublished({
                    projeto_id: Number(projetoId),
                    release_id: Number(releaseId),
                    overridden: false,
                });
            }
            message.success(
                status === 'publicada' ? 'Release publicada.' : 'Status da release atualizado.',
            );
        } catch (err) {
            if (isProdutoSoftwareTipoDisabledError(err)) {
                message.warning(mensagemProdutoSoftwareTipoDisabled(err));
                return;
            }
            if (
                status === 'publicada' &&
                isReleasePublicacaoGateError(err) &&
                canOverrideUat
            ) {
                setOverrideGate({ message: mensagemReleasePublicacaoGate(err) });
                return;
            }
            if (status === 'publicada' && isReleasePublicacaoGateError(err) && !canOverrideUat) {
                message.error(
                    tooltipSemPermissao('publicar com override') +
                        ' ' +
                        mensagemReleasePublicacaoGate(err),
                );
                return;
            }
            message.error(
                extractProjetoApiErrorMessage(err, 'Não foi possível atualizar o status da release.'),
            );
        }
    };

    const handleOverridePublicacao = async (motivo: string) => {
        const body = buildOverridePublicacaoReleaseBody(motivo);
        if (!body) {
            message.error(`Informe um motivo entre 10 e 500 caracteres.`);
            return;
        }
        try {
            await updateReleaseMutation.mutateAsync({
                status: 'publicada',
                override_publicacao: true,
                motivo_override: body.motivo_override,
            });
            setOverrideGate(null);
            recordProdutoReleasePublished({
                projeto_id: Number(projetoId),
                release_id: Number(releaseId),
                overridden: true,
            });
            message.success('Release publicada com override (registrado na auditoria).');
        } catch (err) {
            if (isProdutoSoftwareTipoDisabledError(err)) {
                message.warning(mensagemProdutoSoftwareTipoDisabled(err));
                setOverrideGate(null);
                return;
            }
            if (isReleasePublicacaoGateError(err)) {
                setOverrideGate({ message: mensagemReleasePublicacaoGate(err) });
                return;
            }
            message.error(
                extractProjetoApiErrorMessage(err, 'Não foi possível publicar a release com override.'),
            );
        }
    };

    const handleDraftStatusChange = (
        superficie: ProdutoReleaseSuperficie,
        status: ProdutoReleaseSuperficieStatus,
    ) => {
        setDraftStatuses((prev) => {
            const next = { ...prev };
            if (status === superficie.status) {
                delete next[superficie.projeto_id];
            } else {
                next[superficie.projeto_id] = status;
            }
            return next;
        });
    };

    const handleDescartarChecklist = () => {
        setDraftStatuses({});
    };

    /**
     * Envia todas as superfícies com status alterado num único PATCH
     * (`.../releases/{id}/superficies`), evitando corrida de N requests.
     */
    const handleSalvarChecklist = async () => {
        if (dirtySuperficies.length === 0) return;
        const count = dirtySuperficies.length;
        try {
            await updateSuperficiesMutation.mutateAsync({ superficies: dirtySuperficies });
            setDraftStatuses({});
            message.success(
                count === 1
                    ? 'Checklist atualizado.'
                    : `Checklist atualizado (${count} superfícies).`,
            );
        } catch (err) {
            if (isProdutoSoftwareTipoDisabledError(err)) {
                message.warning(mensagemProdutoSoftwareTipoDisabled(err));
                return;
            }
            message.error(
                extractProjetoApiErrorMessage(err, 'Não foi possível salvar o checklist.'),
            );
        }
    };

    if (isError) {
        return (
            <ProjetoLayout projetoId={projetoId} pageTitle="Release" titleSection="Release">
                <ProdutoSoftwareTipoFetchErrorAlert
                    error={error}
                    fallbackMessage="Não foi possível carregar a release"
                    onRetry={() => void refetch()}
                />
            </ProjetoLayout>
        );
    }

    if (isLoading || !release) {
        return (
            <ProjetoLayout projetoId={projetoId} pageTitle="Release" titleSection="Release">
                <LoadingState label="Carregando release…" />
            </ProjetoLayout>
        );
    }

    const savingChecklist = updateSuperficiesMutation.isPending;
    const markingProntas = marcarProntasMutation.isPending;
    const checklistBusy = savingChecklist || markingProntas;

    const columns = [
        {
            title: 'Superfície',
            dataIndex: 'codigo_superficie',
            key: 'codigo_superficie',
            width: 110,
            render: (codigo: string | null) => (codigo ? <Tag>{codigo}</Tag> : '—'),
        },
        {
            title: 'Subprojeto',
            dataIndex: 'nome',
            key: 'nome',
            render: (nome: string, row: ProdutoReleaseSuperficie) => (
                <Link href={`/projetos/${row.projeto_id}`}>{nome}</Link>
            ),
        },
        {
            title: 'Versão da superfície',
            key: 'versao',
            render: (_: unknown, row: ProdutoReleaseSuperficie) =>
                row.versao?.nome ?? (
                    <Typography.Text type="secondary">Não vinculada</Typography.Text>
                ),
        },
        {
            title: 'Sprint estabilização',
            key: 'sprint',
            render: (_: unknown, row: ProdutoReleaseSuperficie) => row.sprint?.nome ?? '—',
        },
        {
            title: 'Status',
            key: 'status',
            width: 180,
            render: (_: unknown, row: ProdutoReleaseSuperficie) => (
                <Tooltip
                    title={
                        !canEditar ? tooltipSemPermissao('editar o checklist da release') : undefined
                    }
                >
                    <Select<ProdutoReleaseSuperficieStatus>
                        size="small"
                        style={{ width: '100%' }}
                        value={getEffectiveStatus(row)}
                        options={SUPERFICIE_STATUS_OPTIONS}
                        onChange={(value) => handleDraftStatusChange(row, value)}
                        disabled={checklistBusy || !canEditar}
                        aria-label={`Status da superfície ${row.codigo_superficie ?? row.nome ?? row.projeto_id}`}
                        data-testid={`release-superficie-status-${row.projeto_id}`}
                    />
                </Tooltip>
            ),
        },
    ];

    const todasProntas = readinessEfectivo.todas_prontas;
    const semSuperficies = readinessEfectivo.total === 0;
    const marcarProntasDisabled =
        !canEditar || semSuperficies || todasProntas || checklistBusy;
    const marcarProntasTooltip = !canEditar
        ? tooltipSemPermissao('marcar superfícies como prontas')
        : semSuperficies
          ? 'Sem superfícies no checklist desta release.'
          : todasProntas
            ? 'Todas as superfícies já estão prontas.'
            : undefined;

    const marcarTodasProntasButton = (
        <Button
            icon={<ListChecks size={16} aria-hidden />}
            disabled={marcarProntasDisabled}
            loading={markingProntas}
            onClick={handleMarcarTodasProntas}
            data-testid={
                canEditar ? 'release-marcar-todas-prontas' : 'release-marcar-todas-prontas-disabled'
            }
        >
            Marcar todas prontas
        </Button>
    );

    const duplicarButton = (
        <Button
            icon={<Copy size={16} aria-hidden />}
            disabled={!canEditar}
            onClick={() => setDuplicarOpen(true)}
            data-testid={canEditar ? 'release-duplicar' : 'release-duplicar-disabled'}
        >
            Duplicar
        </Button>
    );

    return (
        <ProjetoLayout
            projetoId={projetoId}
            pageTitle={release.nome}
            titleSection={`Release ${release.codigo}`}
            headerAction={
                <Space wrap size="small" role="toolbar" aria-label="Ações da release">
                    <Link href={`/projetos/${projetoId}/produto/releases`}>
                        <Button icon={<ArrowLeft size={16} aria-hidden />} aria-label="Voltar à lista de releases">
                            Voltar à lista
                        </Button>
                    </Link>
                    {canEditar ? (
                        duplicarButton
                    ) : (
                        <Tooltip title={tooltipSemPermissao('duplicar releases')}>
                            <span>{duplicarButton}</span>
                        </Tooltip>
                    )}
                </Space>
            }
        >
            <Descriptions bordered size="small" column={{ xs: 1, sm: 2 }} style={{ marginBottom: 24 }}>
                <Descriptions.Item label="Nome">{release.nome}</Descriptions.Item>
                <Descriptions.Item label="Código">{release.codigo}</Descriptions.Item>
                <Descriptions.Item label="Status">
                    <Tooltip
                        title={
                            !canEditar ? tooltipSemPermissao('alterar o status da release') : undefined
                        }
                    >
                        <Select<ProdutoReleaseStatus>
                            size="small"
                            style={{ minWidth: 200, maxWidth: '100%' }}
                            value={release.status}
                            options={RELEASE_STATUS_OPTIONS}
                            onChange={(value) => void handleStatusChange(value)}
                            loading={updateReleaseMutation.isPending}
                            disabled={!canEditar}
                            data-testid="release-status-select"
                            aria-label="Status da release"
                        />
                    </Tooltip>
                </Descriptions.Item>
                <Descriptions.Item label="Data alvo">{release.data_alvo ?? '—'}</Descriptions.Item>
                <Descriptions.Item label="Publicação">{release.data_publicacao ?? '—'}</Descriptions.Item>
                <Descriptions.Item label="Checklist">
                    {readinessEfectivo.prontas}/{readinessEfectivo.total} prontas
                    {readinessEfectivo.bloqueadas > 0 ? (
                        <Typography.Text type="danger" style={{ marginLeft: 8 }}>
                            ({readinessEfectivo.bloqueadas} bloqueada
                            {readinessEfectivo.bloqueadas === 1 ? '' : 's'})
                        </Typography.Text>
                    ) : null}
                    {isChecklistDirty ? (
                        <Typography.Text type="warning" style={{ marginLeft: 8 }}>
                            ({dirtySuperficies.length} pendente
                            {dirtySuperficies.length === 1 ? '' : 's'} de salvar)
                        </Typography.Text>
                    ) : null}
                </Descriptions.Item>
                {release.notas ? (
                    <Descriptions.Item label="Notas" span={2}>
                        {release.notas}
                    </Descriptions.Item>
                ) : null}
                {release.criado_por != null || release.atualizado_por != null ? (
                    <Descriptions.Item label="Auditoria" span={2}>
                        <Typography.Text type="secondary" data-testid="release-audit-trail">
                            {release.criado_por != null ? `Criado por #${release.criado_por}` : null}
                            {release.criado_por != null && release.atualizado_por != null
                                ? ' · '
                                : null}
                            {release.atualizado_por != null
                                ? `Atualizado por #${release.atualizado_por}`
                                : null}
                        </Typography.Text>
                    </Descriptions.Item>
                ) : null}
            </Descriptions>

            {todasProntas ? (
                <Alert
                    type="success"
                    showIcon
                    icon={<CheckCircle2 size={16} aria-hidden />}
                    message="Todas as superfícies prontas"
                    description="A release pode avançar para estabilização ou publicação conforme o processo do produto."
                    style={{ marginBottom: 16 }}
                    data-testid="release-readiness-todas-prontas"
                />
            ) : release.status === 'publicada' ? (
                <Alert
                    type="warning"
                    showIcon
                    message="Publicada com checklist incompleto"
                    description="Esta release foi publicada com superfícies ainda não prontas (override auditado ou estado legado)."
                    style={{ marginBottom: 16 }}
                />
            ) : (
                <Alert
                    type="info"
                    showIcon
                    message="Checklist incompleto"
                    description="Ao marcar a release como Publicada com superfícies pendentes, será pedido um motivo de override (auditoria)."
                    style={{ marginBottom: 16 }}
                />
            )}

            {isChecklistDirty ? (
                <Alert
                    type="warning"
                    showIcon
                    message="Alterações pendentes no checklist"
                    description='Os status das superfícies só são gravados ao clicar em "Salvar checklist" (um único envio).'
                    style={{ marginBottom: 16 }}
                    data-testid="release-checklist-dirty-alert"
                />
            ) : null}

            <ContentCard
                title="Checklist por superfície"
                headerActions={
                    <Space wrap size="small">
                        {marcarProntasTooltip ? (
                            <Tooltip title={marcarProntasTooltip}>
                                <span>{marcarTodasProntasButton}</span>
                            </Tooltip>
                        ) : (
                            marcarTodasProntasButton
                        )}
                        {canEditar ? (
                            <>
                                {isChecklistDirty ? (
                                    <Button
                                        onClick={handleDescartarChecklist}
                                        disabled={checklistBusy}
                                        data-testid="release-checklist-descartar"
                                    >
                                        Descartar
                                    </Button>
                                ) : null}
                                <Button
                                    type="primary"
                                    icon={<Save size={16} aria-hidden />}
                                    disabled={!isChecklistDirty || markingProntas}
                                    loading={savingChecklist}
                                    onClick={() => void handleSalvarChecklist()}
                                    data-testid="release-checklist-salvar"
                                >
                                    Salvar checklist
                                </Button>
                            </>
                        ) : (
                            <Tooltip title={tooltipSemPermissao('editar o checklist da release')}>
                                <span>
                                    <Button
                                        type="primary"
                                        disabled
                                        icon={<Save size={16} aria-hidden />}
                                    >
                                        Salvar checklist
                                    </Button>
                                </span>
                            </Tooltip>
                        )}
                    </Space>
                }
            >
                <Table<ProdutoReleaseSuperficie>
                    rowKey="id"
                    columns={columns}
                    dataSource={release.superficies}
                    pagination={false}
                    size="small"
                    scroll={{ x: 'max-content' }}
                    locale={{
                        emptyText:
                            'Sem superfícies — adicione subprojetos ao programa para preencher o checklist.',
                    }}
                />
            </ContentCard>

            {canOverrideUat ? (
                <ModalOverridePublicacaoRelease
                    open={overrideGate !== null}
                    gateMessage={overrideGate?.message ?? ''}
                    confirmLoading={updateReleaseMutation.isPending}
                    onCancel={() => setOverrideGate(null)}
                    onConfirm={(motivo) => void handleOverridePublicacao(motivo)}
                />
            ) : null}

            <ModalDuplicarRelease
                open={duplicarOpen}
                projetoId={projetoId}
                origem={release}
                onClose={() => setDuplicarOpen(false)}
                onDuplicated={(nova) => {
                    if (nova?.id) {
                        router.push(`/projetos/${projetoId}/produto/releases/${nova.id}`);
                    } else {
                        void refetch();
                    }
                }}
            />
        </ProjetoLayout>
    );
}
