import { useState, useCallback } from 'react';
import { useParams, useSearchParams, useNavigate } from 'react-router-dom';
import { batchApi, type JobExecutionDetailDto, type StepExecutionDto, type FailedRecordDto } from '../api/batchApi';
import { formatDateTime, formatDuration, calculateDuration } from '../utils/formatters';
import { usePoller } from '../hooks/usePoller';
import StatusBadge from '../components/StatusBadge';
import EmptyState from '../components/EmptyState';
import LoadingSpinner from '../components/LoadingSpinner';
import Pagination from '../components/Pagination';
import DetailStatCard from '../components/DetailStatCard';
import ApiLogSection from '../components/ApiLogSection';
import InfoItem from '../components/InfoItem';
import GuideModal, { HelpButton } from '../components/GuideModal';

const POLLING_INTERVAL_MS = 5000;

const EXECUTION_DETAIL_GUIDE = [
    {
        title: '실행 기본 정보',
        content: '실행의 시작/종료 시간, 소요 시간, 종료 코드, 에러 메시지 등 기본 정보를 보여줍니다.\n실행 중인 경우 5초마다 자동으로 갱신됩니다.',
    },
    {
        title: '처리 통계',
        content: '4개의 통계 카드로 전체 처리 현황을 요약합니다.\n• 읽기(Read): 외부 API에서 조회한 건수\n• 쓰기(Write): DB에 저장된 건수\n• 건너뜀(Skip): 처리하지 않은 건수\n• 필터(Filter): 조건에 의해 제외된 건수',
    },
    {
        title: 'Step 실행 정보',
        content: '배치 작업은 하나 이상의 Step으로 구성됩니다.\n각 Step의 상태, 처리 건수, 커밋/롤백 횟수를 확인할 수 있습니다.\nAPI 호출 정보에서는 총 호출 수, 성공/에러 수, 평균 응답 시간을 보여줍니다.',
    },
    {
        title: 'API 호출 로그',
        content: '각 Step에서 호출한 외부 API의 상세 로그를 확인할 수 있습니다.\n요청 URL, 응답 코드, 응답 시간 등을 페이지 단위로 조회합니다.',
    },
    {
        title: '실패 건 관리',
        content: '처리 중 실패한 레코드가 있으면 목록으로 표시됩니다.\n• 실패 건 재수집: 실패한 데이터를 다시 수집합니다\n• 일괄 RESOLVED: 모든 실패 건을 해결됨으로 처리합니다\n• 재시도 초기화: 재시도 횟수를 초기화하여 자동 재수집 대상에 포함시킵니다',
    },
];

interface StepCardProps {
    step: StepExecutionDto;
    jobName: string;
    jobExecutionId: number;
}

function StepCard({ step, jobName, jobExecutionId }: StepCardProps) {
    const stats = [
        { label: '읽기', value: step.readCount },
        { label: '쓰기', value: step.writeCount },
        { label: '커밋', value: step.commitCount },
        { label: '롤백', value: step.rollbackCount },
        { label: '읽기 건너뜀', value: step.readSkipCount },
        { label: '처리 건너뜀', value: step.processSkipCount },
        { label: '쓰기 건너뜀', value: step.writeSkipCount },
        { label: '필터', value: step.filterCount },
    ];

    return (
        <div className="bg-wing-surface rounded-xl shadow-md p-6">
            <div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between mb-4">
                <div className="flex items-center gap-3">
                    <h3 className="text-base font-semibold text-wing-text">
                        {step.stepName}
                    </h3>
                    <StatusBadge status={step.status} />
                </div>
                <span className="text-sm text-wing-muted">
                    {step.duration != null
                        ? formatDuration(step.duration)
                        : calculateDuration(step.startTime, step.endTime)}
                </span>
            </div>

            <div className="grid grid-cols-2 gap-2 text-sm mb-3">
                <div className="text-wing-muted">
                    시작: <span className="text-wing-text">{formatDateTime(step.startTime)}</span>
                </div>
                <div className="text-wing-muted">
                    종료: <span className="text-wing-text">{formatDateTime(step.endTime)}</span>
                </div>
            </div>

            <div className="grid grid-cols-2 sm:grid-cols-4 gap-3">
                {stats.map(({ label, value }) => (
                    <div
                        key={label}
                        className="rounded-lg bg-wing-card px-3 py-2 text-center"
                    >
                        <p className="text-lg font-bold text-wing-text">
                            {value.toLocaleString()}
                        </p>
                        <p className="text-xs text-wing-muted">{label}</p>
                    </div>
                ))}
            </div>

            {/* API 호출 정보: apiLogSummary가 있으면 개별 로그 리스트, 없으면 기존 apiCallInfo 요약 */}
            {step.apiLogSummary ? (
                <div className="mt-4 rounded-lg bg-blue-50 border border-blue-200 p-3">
                    <p className="text-xs font-medium text-blue-700 mb-2">API 호출 정보</p>
                    <div className="grid grid-cols-3 sm:grid-cols-6 gap-2">
                        <div className="rounded bg-white px-2 py-1.5 text-center">
                            <p className="text-sm font-bold text-wing-text">{step.apiLogSummary.totalCalls.toLocaleString()}</p>
                            <p className="text-[10px] text-wing-muted">총 호출</p>
                        </div>
                        <div className="rounded bg-white px-2 py-1.5 text-center">
                            <p className="text-sm font-bold text-emerald-600">{step.apiLogSummary.successCount.toLocaleString()}</p>
                            <p className="text-[10px] text-wing-muted">성공</p>
                        </div>
                        <div className="rounded bg-white px-2 py-1.5 text-center">
                            <p className={`text-sm font-bold ${step.apiLogSummary.errorCount > 0 ? 'text-red-500' : 'text-wing-text'}`}>
                                {step.apiLogSummary.errorCount.toLocaleString()}
                            </p>
                            <p className="text-[10px] text-wing-muted">에러</p>
                        </div>
                        <div className="rounded bg-white px-2 py-1.5 text-center">
                            <p className="text-sm font-bold text-blue-600">{Math.round(step.apiLogSummary.avgResponseMs).toLocaleString()}</p>
                            <p className="text-[10px] text-wing-muted">평균(ms)</p>
                        </div>
                        <div className="rounded bg-white px-2 py-1.5 text-center">
                            <p className="text-sm font-bold text-red-500">{step.apiLogSummary.maxResponseMs.toLocaleString()}</p>
                            <p className="text-[10px] text-wing-muted">최대(ms)</p>
                        </div>
                        <div className="rounded bg-white px-2 py-1.5 text-center">
                            <p className="text-sm font-bold text-emerald-500">{step.apiLogSummary.minResponseMs.toLocaleString()}</p>
                            <p className="text-[10px] text-wing-muted">최소(ms)</p>
                        </div>
                    </div>

                    {step.apiLogSummary.totalCalls > 0 && (
                        <ApiLogSection stepExecutionId={step.stepExecutionId} summary={step.apiLogSummary} />
                    )}
                </div>
            ) : step.apiCallInfo && (
                <div className="mt-4 rounded-lg bg-blue-50 border border-blue-200 p-3">
                    <p className="text-xs font-medium text-blue-700 mb-2">API 호출 정보</p>
                    <div className="grid grid-cols-2 sm:grid-cols-4 gap-2 text-xs">
                        <div>
                            <span className="text-blue-500">URL:</span>{' '}
                            <span className="text-blue-900 font-mono break-all">{step.apiCallInfo.apiUrl}</span>
                        </div>
                        <div>
                            <span className="text-blue-500">Method:</span>{' '}
                            <span className="text-blue-900 font-semibold">{step.apiCallInfo.method}</span>
                        </div>
                        <div>
                            <span className="text-blue-500">호출:</span>{' '}
                            <span className="text-blue-900">{step.apiCallInfo.completedCalls} / {step.apiCallInfo.totalCalls}</span>
                        </div>
                        {step.apiCallInfo.lastCallTime && (
                            <div>
                                <span className="text-blue-500">최종:</span>{' '}
                                <span className="text-blue-900">{step.apiCallInfo.lastCallTime}</span>
                            </div>
                        )}
                    </div>
                </div>
            )}

            {/* 호출 실패 데이터 토글 */}
            {step.failedRecords && step.failedRecords.length > 0 && (
                <FailedRecordsToggle records={step.failedRecords} jobName={jobName} jobExecutionId={jobExecutionId} />
            )}

            {step.exitMessage && (
                <div className="mt-4 rounded-lg bg-red-50 border border-red-200 p-3">
                    <p className="text-xs font-medium text-red-700 mb-1">Exit Message</p>
                    <p className="text-xs text-red-600 whitespace-pre-wrap break-words">
                        {step.exitMessage}
                    </p>
                </div>
            )}
        </div>
    );
}

export default function ExecutionDetail() {
    const { id: paramId } = useParams<{ id: string }>();
    const [searchParams] = useSearchParams();
    const navigate = useNavigate();

    const executionId = paramId
        ? Number(paramId)
        : Number(searchParams.get('id'));

    const [detail, setDetail] = useState<JobExecutionDetailDto | null>(null);
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState<string | null>(null);
    const [guideOpen, setGuideOpen] = useState(false);

    const isRunning = detail
        ? detail.status === 'STARTED' || detail.status === 'STARTING'
        : false;

    const loadDetail = useCallback(async () => {
        if (!executionId || isNaN(executionId)) {
            setError('유효하지 않은 실행 ID입니다.');
            setLoading(false);
            return;
        }
        try {
            const data = await batchApi.getExecutionDetail(executionId);
            setDetail(data);
            setError(null);
        } catch (err) {
            setError(
                err instanceof Error
                    ? err.message
                    : '실행 상세 정보를 불러오지 못했습니다.',
            );
        } finally {
            setLoading(false);
        }
    }, [executionId]);

    /* 실행중인 경우 5초 폴링, 완료 후에는 1회 로드로 충분하지만 폴링 유지 */
    usePoller(loadDetail, isRunning ? POLLING_INTERVAL_MS : 30_000, [
        executionId,
    ]);

    if (loading) return <LoadingSpinner />;

    if (error || !detail) {
        return (
            <div className="space-y-4">
                <button
                    onClick={() => navigate('/executions')}
                    className="inline-flex items-center gap-1 text-sm text-wing-muted hover:text-wing-text transition-colors"
                >
                    <span>&larr;</span> 목록으로
                </button>
                <EmptyState
                    icon="&#x26A0;"
                    message={error || '실행 정보를 찾을 수 없습니다.'}
                />
            </div>
        );
    }

    const jobParams = Object.entries(detail.jobParameters);

    return (
        <div className="space-y-6">
            {/* 상단 내비게이션 */}
            <button
                onClick={() => navigate(-1)}
                className="inline-flex items-center gap-1 text-sm text-wing-muted hover:text-wing-text transition-colors"
            >
                <span>&larr;</span> 목록으로
            </button>

            {/* Job 기본 정보 */}
            <div className="bg-wing-surface rounded-xl shadow-md p-6">
                <div className="flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between">
                    <div>
                        <div className="flex items-center gap-2">
                            <h1 className="text-2xl font-bold text-wing-text">
                                실행 #{detail.executionId}
                            </h1>
                            <HelpButton onClick={() => setGuideOpen(true)} />
                        </div>
                        <p className="mt-1 text-sm text-wing-muted">
                            {detail.jobName}
                        </p>
                    </div>
                    <StatusBadge status={detail.status} className="text-sm" />
                </div>

                <div className="mt-6 grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 text-sm">
                    <InfoItem label="시작시간" value={formatDateTime(detail.startTime)} />
                    <InfoItem label="종료시간" value={formatDateTime(detail.endTime)} />
                    <InfoItem
                        label="소요시간"
                        value={
                            detail.duration != null
                                ? formatDuration(detail.duration)
                                : calculateDuration(detail.startTime, detail.endTime)
                        }
                    />
                    <InfoItem label="Exit Code" value={detail.exitCode} />
                    {detail.exitMessage && (
                        <div className="sm:col-span-2 lg:col-span-3">
                            <InfoItem label="Exit Message" value={detail.exitMessage} />
                        </div>
                    )}
                </div>
            </div>

            {/* 실행 통계 카드 4개 */}
            <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
                <DetailStatCard
                    label="읽기 (Read)"
                    value={detail.readCount}
                    gradient="bg-gradient-to-br from-blue-500 to-blue-600"
                    icon="&#x1F4E5;"
                />
                <DetailStatCard
                    label="쓰기 (Write)"
                    value={detail.writeCount}
                    gradient="bg-gradient-to-br from-emerald-500 to-emerald-600"
                    icon="&#x1F4E4;"
                />
                <DetailStatCard
                    label="건너뜀 (Skip)"
                    value={detail.skipCount}
                    gradient="bg-gradient-to-br from-amber-500 to-amber-600"
                    icon="&#x23ED;"
                />
                <DetailStatCard
                    label="필터 (Filter)"
                    value={detail.filterCount}
                    gradient="bg-gradient-to-br from-purple-500 to-purple-600"
                    icon="&#x1F50D;"
                />
            </div>

            {/* Job Parameters */}
            {jobParams.length > 0 && (
                <div className="bg-wing-surface rounded-xl shadow-md p-6">
                    <h2 className="text-lg font-semibold text-wing-text mb-4">
                        Job Parameters
                    </h2>
                    <div className="overflow-x-auto">
                        <table className="w-full text-sm text-left">
                            <thead className="bg-wing-card text-xs uppercase text-wing-muted">
                                <tr>
                                    <th className="px-6 py-3 font-medium">Key</th>
                                    <th className="px-6 py-3 font-medium">Value</th>
                                </tr>
                            </thead>
                            <tbody className="divide-y divide-wing-border/50">
                                {jobParams.map(([key, value]) => (
                                    <tr
                                        key={key}
                                        className="hover:bg-wing-hover transition-colors"
                                    >
                                        <td className="px-6 py-3 font-mono text-wing-text">
                                            {key}
                                        </td>
                                        <td className="px-6 py-3 text-wing-muted break-all">
                                            {value}
                                        </td>
                                    </tr>
                                ))}
                            </tbody>
                        </table>
                    </div>
                </div>
            )}

            {/* Step 실행 정보 */}
            <div>
                <h2 className="text-lg font-semibold text-wing-text mb-4">
                    Step 실행 정보
                    <span className="ml-2 text-sm font-normal text-wing-muted">
                        ({detail.stepExecutions.length}개)
                    </span>
                </h2>
                {detail.stepExecutions.length === 0 ? (
                    <EmptyState message="Step 실행 정보가 없습니다." />
                ) : (
                    <div className="space-y-4">
                        {detail.stepExecutions.map((step) => (
                            <StepCard
                                key={step.stepExecutionId}
                                step={step}
                                jobName={detail.jobName}
                                jobExecutionId={executionId}
                            />
                        ))}
                    </div>
                )}
            </div>

            <GuideModal
                open={guideOpen}
                onClose={() => setGuideOpen(false)}
                pageTitle="실행 상세"
                sections={EXECUTION_DETAIL_GUIDE}
            />
        </div>
    );
}

const FAILED_PAGE_SIZE = 10;

function FailedRecordsToggle({ records, jobName, jobExecutionId }: { records: FailedRecordDto[]; jobName: string; jobExecutionId: number }) {
    const [open, setOpen] = useState(false);
    const [showConfirm, setShowConfirm] = useState(false);
    const [showResolveConfirm, setShowResolveConfirm] = useState(false);
    const [retrying, setRetrying] = useState(false);
    const [resolving, setResolving] = useState(false);
    const [showResetConfirm, setShowResetConfirm] = useState(false);
    const [resetting, setResetting] = useState(false);
    const [page, setPage] = useState(0);
    const navigate = useNavigate();

    const failedRecords = records.filter((r) => r.status === 'FAILED');
    const totalPages = Math.ceil(records.length / FAILED_PAGE_SIZE);
    const pagedRecords = records.slice(page * FAILED_PAGE_SIZE, (page + 1) * FAILED_PAGE_SIZE);

    const statusColor = (status: string) => {
        switch (status) {
            case 'RESOLVED': return 'text-emerald-600 bg-emerald-50';
            case 'RETRY_PENDING': return 'text-amber-600 bg-amber-50';
            default: return 'text-red-600 bg-red-50';
        }
    };

    const MAX_RETRY_COUNT = 3;

    const retryStatusLabel = (record: FailedRecordDto) => {
        if (record.status !== 'FAILED') return null;
        if (record.retryCount >= MAX_RETRY_COUNT) return { label: '재시도 초과', color: 'text-red-600 bg-red-100' };
        if (record.retryCount > 0) return { label: `재시도 ${record.retryCount}/${MAX_RETRY_COUNT}`, color: 'text-amber-600 bg-amber-100' };
        return { label: '대기', color: 'text-blue-600 bg-blue-100' };
    };

    const exceededRecords = failedRecords.filter((r) => r.retryCount >= MAX_RETRY_COUNT);

    const handleRetry = async () => {
        setRetrying(true);
        try {
            const result = await batchApi.retryFailedRecords(jobName, failedRecords.length, jobExecutionId);
            if (result.success) {
                setShowConfirm(false);
                if (result.executionId) {
                    navigate(`/executions/${result.executionId}`);
                } else {
                    alert(result.message || '재수집이 요청되었습니다.');
                }
            } else {
                alert(result.message || '재수집 실행에 실패했습니다.');
            }
        } catch {
            alert('재수집 실행에 실패했습니다.');
        } finally {
            setRetrying(false);
        }
    };

    const handleResolve = async () => {
        setResolving(true);
        try {
            const ids = failedRecords.map((r) => r.id);
            await batchApi.resolveFailedRecords(ids);
            setShowResolveConfirm(false);
            navigate(0);
        } catch {
            alert('일괄 RESOLVED 처리에 실패했습니다.');
        } finally {
            setResolving(false);
        }
    };

    const handleResetRetry = async () => {
        setResetting(true);
        try {
            const ids = exceededRecords.map((r) => r.id);
            await batchApi.resetRetryCount(ids);
            setShowResetConfirm(false);
            navigate(0);
        } catch {
            alert('재시도 초기화에 실패했습니다.');
        } finally {
            setResetting(false);
        }
    };

    return (
        <div className="mt-4 rounded-lg bg-red-50 border border-red-200 p-3">
            <div className="flex items-center justify-between">
                <button
                    onClick={() => setOpen((v) => !v)}
                    className="inline-flex items-center gap-1 text-xs font-medium text-red-600 hover:text-red-800 transition-colors"
                >
                    <svg
                        className={`w-3 h-3 transition-transform ${open ? 'rotate-90' : ''}`}
                        fill="none" viewBox="0 0 24 24" stroke="currentColor"
                    >
                        <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
                    </svg>
                    호출 실패 데이터 ({records.length.toLocaleString()}건, FAILED {failedRecords.length}건)
                </button>

                {failedRecords.length > 0 && (
                    <div className="flex items-center gap-1.5">
                        {exceededRecords.length > 0 && (
                            <button
                                onClick={() => setShowResetConfirm(true)}
                                className="inline-flex items-center gap-1 px-2.5 py-1 text-xs font-medium text-amber-700 bg-amber-50 hover:bg-amber-100 border border-amber-200 rounded-md transition-colors"
                            >
                                <svg className="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                                    <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
                                </svg>
                                재시도 초기화 ({exceededRecords.length}건)
                            </button>
                        )}
                        <button
                            onClick={() => setShowResolveConfirm(true)}
                            className="inline-flex items-center gap-1 px-2.5 py-1 text-xs font-medium text-emerald-700 bg-emerald-50 hover:bg-emerald-100 border border-emerald-200 rounded-md transition-colors"
                        >
                            <svg className="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                                <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
                            </svg>
                            일괄 RESOLVED ({failedRecords.length}건)
                        </button>
                        <button
                            onClick={() => setShowConfirm(true)}
                            className="inline-flex items-center gap-1 px-2.5 py-1 text-xs font-medium text-white bg-red-500 hover:bg-red-600 rounded-md transition-colors"
                        >
                            <svg className="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                                <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
                            </svg>
                            실패 건 재수집 ({failedRecords.length}건)
                        </button>
                    </div>
                )}
            </div>

            {open && (
                <div className="mt-2">
                    <div className="overflow-x-auto">
                        <table className="w-full text-xs text-left">
                            <thead className="bg-red-100 text-red-700">
                                <tr>
                                    <th className="px-2 py-1.5 font-medium">Record Key</th>
                                    <th className="px-2 py-1.5 font-medium">에러 메시지</th>
                                    <th className="px-2 py-1.5 font-medium text-center">재시도</th>
                                    <th className="px-2 py-1.5 font-medium text-center">상태</th>
                                    <th className="px-2 py-1.5 font-medium">생성 시간</th>
                                </tr>
                            </thead>
                            <tbody className="divide-y divide-red-100">
                                {pagedRecords.map((record) => (
                                    <tr
                                        key={record.id}
                                        className="bg-white hover:bg-red-50"
                                    >
                                        <td className="px-2 py-1.5 font-mono text-red-900">
                                            {record.recordKey}
                                        </td>
                                        <td className="px-2 py-1.5 text-red-600 max-w-[200px] truncate" title={record.errorMessage || ''}>
                                            {record.errorMessage || '-'}
                                        </td>
                                        <td className="px-2 py-1.5 text-center">
                                            {(() => {
                                                const info = retryStatusLabel(record);
                                                return info ? (
                                                    <span className={`inline-flex px-1.5 py-0.5 text-[10px] font-medium rounded-full ${info.color}`}>
                                                        {info.label}
                                                    </span>
                                                ) : (
                                                    <span className="text-wing-muted">-</span>
                                                );
                                            })()}
                                        </td>
                                        <td className="px-2 py-1.5 text-center">
                                            <span className={`inline-flex px-1.5 py-0.5 text-[10px] font-medium rounded-full ${statusColor(record.status)}`}>
                                                {record.status}
                                            </span>
                                        </td>
                                        <td className="px-2 py-1.5 text-red-500 whitespace-nowrap">
                                            {formatDateTime(record.createdAt)}
                                        </td>
                                    </tr>
                                ))}
                            </tbody>
                        </table>
                    </div>
                    <Pagination
                        page={page}
                        totalPages={totalPages}
                        totalElements={records.length}
                        pageSize={FAILED_PAGE_SIZE}
                        onPageChange={setPage}
                    />
                </div>
            )}

            {/* 재수집 확인 다이얼로그 */}
            {showConfirm && (
                <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/40">
                    <div className="bg-white rounded-xl shadow-2xl p-6 w-full max-w-md mx-4">
                        <h3 className="text-lg font-semibold text-wing-text mb-2">
                            실패 건 재수집 확인
                        </h3>
                        <p className="text-sm text-wing-muted mb-3">
                            다음 {failedRecords.length}건의 IMO에 대해 재수집을 실행합니다.
                        </p>
                        <div className="bg-gray-50 rounded-lg p-3 mb-4 max-h-40 overflow-y-auto">
                            <div className="flex flex-wrap gap-1">
                                {failedRecords.map((r) => (
                                    <span
                                        key={r.id}
                                        className="inline-flex px-2 py-0.5 text-xs font-mono bg-red-100 text-red-700 rounded"
                                    >
                                        {r.recordKey}
                                    </span>
                                ))}
                            </div>
                        </div>
                        <div className="flex justify-end gap-2">
                            <button
                                onClick={() => setShowConfirm(false)}
                                disabled={retrying}
                                className="px-4 py-2 text-sm font-medium text-wing-muted bg-gray-100 hover:bg-gray-200 rounded-lg transition-colors disabled:opacity-50"
                            >
                                취소
                            </button>
                            <button
                                onClick={handleRetry}
                                disabled={retrying}
                                className="px-4 py-2 text-sm font-medium text-white bg-red-500 hover:bg-red-600 rounded-lg transition-colors disabled:opacity-50 inline-flex items-center gap-1"
                            >
                                {retrying ? (
                                    <>
                                        <div className="h-3.5 w-3.5 animate-spin rounded-full border-2 border-white border-t-transparent" />
                                        실행 중...
                                    </>
                                ) : (
                                    '재수집 실행'
                                )}
                            </button>
                        </div>
                    </div>
                </div>
            )}

            {/* 일괄 RESOLVED 확인 다이얼로그 */}
            {showResolveConfirm && (
                <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/40">
                    <div className="bg-white rounded-xl shadow-2xl p-6 w-full max-w-md mx-4">
                        <h3 className="text-lg font-semibold text-wing-text mb-2">
                            일괄 RESOLVED 확인
                        </h3>
                        <p className="text-sm text-wing-muted mb-4">
                            FAILED 상태의 {failedRecords.length}건을 RESOLVED로 변경합니다.
                            이 작업은 되돌릴 수 없습니다.
                        </p>
                        <div className="flex justify-end gap-2">
                            <button
                                onClick={() => setShowResolveConfirm(false)}
                                disabled={resolving}
                                className="px-4 py-2 text-sm font-medium text-wing-muted bg-gray-100 hover:bg-gray-200 rounded-lg transition-colors disabled:opacity-50"
                            >
                                취소
                            </button>
                            <button
                                onClick={handleResolve}
                                disabled={resolving}
                                className="px-4 py-2 text-sm font-medium text-white bg-emerald-500 hover:bg-emerald-600 rounded-lg transition-colors disabled:opacity-50 inline-flex items-center gap-1"
                            >
                                {resolving ? (
                                    <>
                                        <div className="h-3.5 w-3.5 animate-spin rounded-full border-2 border-white border-t-transparent" />
                                        처리 중...
                                    </>
                                ) : (
                                    'RESOLVED 처리'
                                )}
                            </button>
                        </div>
                    </div>
                </div>
            )}

            {/* 재시도 초기화 확인 다이얼로그 */}
            {showResetConfirm && (
                <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/40">
                    <div className="bg-white rounded-xl shadow-2xl p-6 w-full max-w-md mx-4">
                        <h3 className="text-lg font-semibold text-wing-text mb-2">
                            재시도 초기화 확인
                        </h3>
                        <p className="text-sm text-wing-muted mb-4">
                            재시도 횟수를 초과한 {exceededRecords.length}건의 retryCount를 0으로 초기화합니다.
                            초기화 후 다음 배치 실행 시 자동 재수집 대상에 포함됩니다.
                        </p>
                        <div className="flex justify-end gap-2">
                            <button
                                onClick={() => setShowResetConfirm(false)}
                                disabled={resetting}
                                className="px-4 py-2 text-sm font-medium text-wing-muted bg-gray-100 hover:bg-gray-200 rounded-lg transition-colors disabled:opacity-50"
                            >
                                취소
                            </button>
                            <button
                                onClick={handleResetRetry}
                                disabled={resetting}
                                className="px-4 py-2 text-sm font-medium text-white bg-amber-500 hover:bg-amber-600 rounded-lg transition-colors disabled:opacity-50 inline-flex items-center gap-1"
                            >
                                {resetting ? (
                                    <>
                                        <div className="h-3.5 w-3.5 animate-spin rounded-full border-2 border-white border-t-transparent" />
                                        처리 중...
                                    </>
                                ) : (
                                    '초기화 실행'
                                )}
                            </button>
                        </div>
                    </div>
                </div>
            )}
        </div>
    );
}

