'use client';

/**
 * Meu token pessoal Cursor (ADR-0085 / S4).
 * Status sem plaintext; rotate mostra uma vez; nunca grava em localStorage.
 */

import React, { useCallback, useState } from 'react';
import {
    Alert,
    Button,
    Card,
    Collapse,
    Descriptions,
    Input,
    Modal,
    Popconfirm,
    Space,
    Spin,
    Table,
    Tag,
    Tooltip,
    Typography,
} from 'antd';
import type { ColumnsType } from 'antd/es/table';
import { useQueryClient } from '@tanstack/react-query';
import { message } from '@/lib/feedback/message';
import apiClient from '@/lib/api/client';
import { API_ENDPOINTS } from '@/lib/api/endpoints';
import { getLaravelApiErrorMessage } from '@/lib/api/laravelApiErrorMessage';
import { queryKeys } from '@/lib/cache/queryKeys';
import { useQueryCache } from '@/hooks/useQueryCache';
import {
    cursorUserTokenStatusLabel,
    extractCursorUserTokenPlainFromRotateBody,
    formatCursorUserTokenDate,
    type ProjetoCursorUserTokenHistoricoItem,
    type ProjetoCursorUserTokenRotateEnvelope,
    type ProjetoCursorUserTokenStatus,
} from './projetoCursorUserToken';

export type ProjetoCursorUserTokenSectionProps = {
    projetoId: string;
};

export function ProjetoCursorUserTokenSection({ projetoId }: ProjetoCursorUserTokenSectionProps) {
    const queryClient = useQueryClient();

    const [rotateConfirmOpen, setRotateConfirmOpen] = useState(false);
    const [deviceLabel, setDeviceLabel] = useState('');
    const [rotating, setRotating] = useState(false);
    const [revoking, setRevoking] = useState(false);
    const [tokenModalOpen, setTokenModalOpen] = useState(false);
    const [plainToken, setPlainToken] = useState<string | null>(null);

    const {
        data: envelope,
        isLoading,
        error,
        refetch,
    } = useQueryCache<{ data: ProjetoCursorUserTokenStatus }>({
        queryKey: queryKeys.projetos.cursorUserToken(projetoId),
        endpoint: API_ENDPOINTS.projetos.cursorUserToken.show(projetoId),
        enabled: Boolean(projetoId),
    });

    const { data: historicoEnvelope, isLoading: historicoLoading } = useQueryCache<{
        data: ProjetoCursorUserTokenHistoricoItem[];
    }>({
        queryKey: queryKeys.projetos.cursorUserTokenHistorico(projetoId),
        endpoint: API_ENDPOINTS.projetos.cursorUserToken.historico(projetoId),
        enabled: Boolean(projetoId),
    });

    const status = envelope?.data;
    const historico = historicoEnvelope?.data ?? [];
    const statusError = error
        ? getLaravelApiErrorMessage(error, 'Não foi possível carregar o estado do seu token Cursor.')
        : null;

    const invalidate = useCallback(async () => {
        await queryClient.invalidateQueries({
            queryKey: queryKeys.projetos.cursorUserToken(projetoId),
        });
        await queryClient.invalidateQueries({
            queryKey: queryKeys.projetos.cursorUserTokenHistorico(projetoId),
        });
        await queryClient.invalidateQueries({
            queryKey: queryKeys.projetos.cursorUserTokens(projetoId),
        });
        await queryClient.invalidateQueries({
            queryKey: queryKeys.projetos.conectar(projetoId),
        });
    }, [queryClient, projetoId]);

    const historicoColumns: ColumnsType<ProjetoCursorUserTokenHistoricoItem> = [
        {
            title: 'Prefixo',
            dataIndex: 'token_prefix',
            key: 'token_prefix',
            render: (v: string) => <Typography.Text code>{v}</Typography.Text>,
        },
        {
            title: 'Estado',
            dataIndex: 'ativo',
            key: 'ativo',
            render: (ativo: boolean) => (
                <Tag color={ativo ? 'success' : 'default'}>{ativo ? 'Ativo' : 'Revogado'}</Tag>
            ),
        },
        {
            title: 'Dispositivo',
            dataIndex: 'device_label',
            key: 'device_label',
            render: (v: string | null) => v?.trim() || '—',
        },
        {
            title: 'Rotação',
            dataIndex: 'rotated_at',
            key: 'rotated_at',
            render: (v: string | null) => formatCursorUserTokenDate(v),
        },
        {
            title: 'Revogado em',
            dataIndex: 'revoked_at',
            key: 'revoked_at',
            render: (v: string | null) => formatCursorUserTokenDate(v),
        },
    ];

    const closeTokenModal = useCallback(() => {
        setTokenModalOpen(false);
        setPlainToken(null);
    }, []);

    const handleRotate = useCallback(async () => {
        setRotating(true);
        try {
            const label = deviceLabel.trim();
            const res = await apiClient.post<ProjetoCursorUserTokenRotateEnvelope>(
                API_ENDPOINTS.projetos.cursorUserToken.rotate(projetoId),
                label ? { device_label: label } : {},
            );
            const plain = extractCursorUserTokenPlainFromRotateBody(res.data);
            if (!plain) {
                message.error(
                    'A rotação concluiu, mas o token não veio na resposta. Contate o suporte.',
                );
                await invalidate();
                setRotateConfirmOpen(false);
                return;
            }
            setPlainToken(plain);
            setRotateConfirmOpen(false);
            setTokenModalOpen(true);
            message.success('Token pessoal gerado. Copie agora — não será mostrado de novo.');
            await invalidate();
        } catch (e: unknown) {
            message.error(
                getLaravelApiErrorMessage(
                    e,
                    'Não foi possível gerar o token. Verifique o addon VS Code/Cursor e o acesso ao projeto.',
                ),
            );
        } finally {
            setRotating(false);
        }
    }, [projetoId, deviceLabel, invalidate]);

    const copyToken = useCallback(async () => {
        if (!plainToken) return;
        try {
            await navigator.clipboard.writeText(plainToken);
            message.success(
                'Token copiado. Coloque em .cursor/config.local.json como "user_token" (header X-Cursor-User-Token).',
            );
        } catch {
            message.error('Não foi possível copiar. Selecione o texto e copie manualmente.');
        }
    }, [plainToken]);

    const handleRevoke = useCallback(async () => {
        setRevoking(true);
        try {
            await apiClient.post(API_ENDPOINTS.projetos.cursorUserToken.revoke(projetoId));
            message.success('Seu token pessoal Cursor foi revogado.');
            await invalidate();
        } catch (e: unknown) {
            message.error(
                getLaravelApiErrorMessage(e, 'Não foi possível revogar o token pessoal Cursor.'),
            );
        } finally {
            setRevoking(false);
        }
    }, [projetoId, invalidate]);

    const configurado = Boolean(status?.token_configurado);

    return (
        <>
            <Card
                title="Meu token Cursor (autor)"
                size="small"
                style={{ marginBottom: 16 }}
                data-testid="cursor-user-token-section"
                extra={
                    <Space wrap size="small">
                        <Tooltip title="Gera um novo token pessoal e invalida o anterior">
                            <Button
                                type="primary"
                                loading={rotating}
                                onClick={() => setRotateConfirmOpen(true)}
                                data-testid="cursor-user-token-rotate"
                            >
                                {configurado ? 'Rotacionar' : 'Gerar token'}
                            </Button>
                        </Tooltip>
                        <Popconfirm
                            title="Revogar seu token pessoal?"
                            description="O pack no seu PC deixa de autenticar ações com autor até gerar outro."
                            okText="Revogar"
                            cancelText="Cancelar"
                            okButtonProps={{ danger: true, loading: revoking }}
                            disabled={!configurado || revoking}
                            onConfirm={() => void handleRevoke()}
                        >
                            <Button
                                danger
                                disabled={!configurado || revoking}
                                loading={revoking}
                                data-testid="cursor-user-token-revoke"
                            >
                                Revogar
                            </Button>
                        </Popconfirm>
                    </Space>
                }
            >
                <Alert
                    type="info"
                    showIcon
                    style={{ marginBottom: 16 }}
                    message="Header X-Cursor-User-Token"
                    description={
                        <>
                            Identifica <Typography.Text strong>você</Typography.Text> nas ações do
                            Cursor (fila, sync, bugs). É diferente do token de{' '}
                            <Typography.Text strong>projeto</Typography.Text> (
                            <Typography.Text code>X-Project-Token</Typography.Text>
                            ), usado por máquina/logs. Coloque o valor em{' '}
                            <Typography.Text code>user_token</Typography.Text> no{' '}
                            <Typography.Text code>.cursor/config.local.json</Typography.Text> (nunca
                            no Git).
                        </>
                    }
                />

                {statusError ? (
                    <Alert
                        type="error"
                        showIcon
                        style={{ marginBottom: 16 }}
                        message={statusError}
                        action={
                            <Button size="small" onClick={() => void refetch()}>
                                Tentar novamente
                            </Button>
                        }
                    />
                ) : null}

                {isLoading && !status ? (
                    <div style={{ textAlign: 'center', padding: 16 }}>
                        <Spin size="small" />
                    </div>
                ) : (
                    <Descriptions size="small" column={{ xs: 1, sm: 2, md: 3 }}>
                        <Descriptions.Item label="Estado">
                            <Tag color={configurado ? 'success' : 'default'}>
                                {status ? cursorUserTokenStatusLabel(status) : '—'}
                            </Tag>
                        </Descriptions.Item>
                        <Descriptions.Item label="Prefixo">
                            <Typography.Text code>
                                {status?.token_prefix?.trim() || '—'}
                            </Typography.Text>
                        </Descriptions.Item>
                        <Descriptions.Item label="Dispositivo">
                            {status?.device_label?.trim() || '—'}
                        </Descriptions.Item>
                        <Descriptions.Item label="Último uso">
                            {formatCursorUserTokenDate(status?.last_used_at)}
                        </Descriptions.Item>
                        <Descriptions.Item label="Última rotação">
                            {formatCursorUserTokenDate(status?.rotated_at)}
                        </Descriptions.Item>
                        <Descriptions.Item label="Expira em">
                            {formatCursorUserTokenDate(status?.expires_at)}
                        </Descriptions.Item>
                    </Descriptions>
                )}

                <Collapse
                    ghost
                    style={{ marginTop: 8 }}
                    items={[
                        {
                            key: 'historico',
                            label: 'Histórico das minhas emissões',
                            children: historicoLoading ? (
                                <div style={{ textAlign: 'center', padding: 12 }}>
                                    <Spin size="small" />
                                </div>
                            ) : (
                                <Table<ProjetoCursorUserTokenHistoricoItem>
                                    size="small"
                                    rowKey="id"
                                    columns={historicoColumns}
                                    dataSource={historico}
                                    pagination={false}
                                    locale={{ emptyText: 'Nenhuma emissão registrada ainda.' }}
                                    scroll={{ x: true }}
                                />
                            ),
                        },
                    ]}
                />
            </Card>

            <Modal
                title={configurado ? 'Confirmar rotação do token pessoal' : 'Gerar token pessoal'}
                open={rotateConfirmOpen}
                onCancel={() => {
                    if (!rotating) setRotateConfirmOpen(false);
                }}
                onOk={() => void handleRotate()}
                okText={configurado ? 'Rotacionar agora' : 'Gerar agora'}
                cancelText="Cancelar"
                confirmLoading={rotating}
                destroyOnHidden
                width={480}
            >
                <Alert
                    type="warning"
                    showIcon
                    style={{ marginBottom: 12 }}
                    message={
                        configurado
                            ? 'O token atual deixa de autenticar'
                            : 'Guarde o valor imediatamente'
                    }
                    description="O plaintext só aparece uma vez. Atualize o user_token no config.local.json do pack."
                />
                <Typography.Paragraph style={{ marginBottom: 8 }}>
                    Rótulo do dispositivo (opcional)
                </Typography.Paragraph>
                <Input
                    value={deviceLabel}
                    onChange={(e) => setDeviceLabel(e.target.value)}
                    placeholder="Ex.: Notebook trabalho"
                    maxLength={120}
                    data-testid="cursor-user-token-device-label"
                />
            </Modal>

            <Modal
                title="Token pessoal — copie agora"
                open={tokenModalOpen}
                onCancel={closeTokenModal}
                footer={
                    <Space wrap>
                        <Button
                            type="primary"
                            onClick={() => void copyToken()}
                            data-testid="cursor-user-token-copy"
                        >
                            Copiar token
                        </Button>
                        <Button onClick={closeTokenModal}>Já guardei</Button>
                    </Space>
                }
                destroyOnHidden
                width={520}
            >
                <Alert
                    type="warning"
                    showIcon
                    style={{ marginBottom: 12 }}
                    message="Só é mostrado uma vez"
                    description='Salve em .cursor/config.local.json como "user_token". Depois de fechar, não será possível ver o valor de novo.'
                />
                <Typography.Paragraph type="secondary" style={{ marginBottom: 8 }}>
                    Header: <Typography.Text code>X-Cursor-User-Token</Typography.Text>
                </Typography.Paragraph>
                <Input.TextArea
                    value={plainToken ?? ''}
                    readOnly
                    autoSize={{ minRows: 3, maxRows: 6 }}
                    style={{ fontFamily: 'monospace', fontSize: 12 }}
                    data-testid="cursor-user-token-plaintext"
                />
            </Modal>
        </>
    );
}
