// ═══════════════════════════════════════════════════════════════
// fastRecord — 변수 / 모달 헬퍼
// ═══════════════════════════════════════════════════════════════
let fastCurrentSessionId = null;
let fastChart            = null;
let fastLivePollTimer    = null;
let fastChartTagNames    = null;   // 현재 차트에 그려진 태그 목록 (재생성 필요 여부 판단용)
let fastDbConnected      = false;  // DB 연결 상태

function fastModalClose() {
    document.getElementById('modal-fast-new').style.display = 'none';
}

// ═══════════════════════════════════════════════════════════════
// fastRecord — API 함수
// ═══════════════════════════════════════════════════════════════

/** DB 연결 테스트 후 세션 목록 로드 */
async function fastDbConnect() {
    const statusEl = document.getElementById('fast-db-status');
    const btnEl    = document.getElementById('btn-fast-db-connect');
    statusEl.textContent = 'DB 접속 중...';
    statusEl.style.color = 'var(--t2)';
    btnEl.disabled = true;

    try {
        const res = await fetch('/api/fast/sessions');
        if (!res.ok) throw new Error('DB 응답 없음');
        const data = await res.json();

        fastDbConnected = true;
        statusEl.textContent = 'DB 연결됨';
        statusEl.style.color = '#4caf50';
        btnEl.style.display = 'none';

        await fastSessionsLoad();
    } catch (e) {
        console.error('[fast] DB 접속 실패:', e);
        statusEl.textContent = 'DB 미연결';
        statusEl.style.color = 'var(--red,#e55)';
        btnEl.disabled = false;
        alert('DB 연결에 실패했습니다. 다시 시도해주세요.');
    }
}

async function fastSessionsLoad() {
    const res = await fetch('/api/fast/sessions');
    if (!res.ok) {
        // DB 연결 안 된 상태 — 세션 목록 비우기
        const list = document.getElementById('fast-session-list');
        list.innerHTML = '<span style="color:var(--t3);font-size:12px;padding:4px 0">DB 연결이 필요합니다. "DB 접속" 버튼을 눌러주세요.</span>';
        return;
    }
    const data = await res.json();

    fastDbConnected = true;
    const statusEl = document.getElementById('fast-db-status');
    if (statusEl) {
        statusEl.textContent = 'DB 연결됨';
        statusEl.style.color = '#4caf50';
    }
    const btnEl = document.getElementById('btn-fast-db-connect');
    if (btnEl) btnEl.style.display = 'none';

    const list = document.getElementById('fast-session-list');
    list.innerHTML = '';

    if (!data.items || data.items.length === 0) {
        list.innerHTML = '<span style="color:var(--t3);font-size:12px;padding:4px 0">세션이 없습니다. + 신규를 눌러 시작하세요.</span>';
        return;
    }

    const statusColor = {
        Running: '#4caf50', Completed: '#4363d8',
        Cancelled: '#888',  Failed: '#e55',
        RowLimitReached: '#f58231', Pending: '#aaa'
    };
    const statusLabel = {
        Running: '실행중', Completed: '완료', Cancelled: '취소',
        Failed: '실패', RowLimitReached: '행제한', Pending: '대기'
    };

    data.items.forEach(s => {
        const isActive = s.id === fastCurrentSessionId;
        const dot   = statusColor[s.status] ?? '#aaa';
        const label = statusLabel[s.status] ?? s.status;

        const chip = document.createElement('div');
        chip.dataset.id = s.id;
        chip.style.cssText = [
            'display:flex;flex-direction:column;gap:3px',
            'padding:7px 11px;border-radius:var(--r)',
            `background:${isActive ? 'rgba(229,85,85,.12)' : 'var(--s3)'}`,
            `border:1px solid ${isActive ? 'var(--red,#e55)' : 'var(--bd)'}`,
            'cursor:pointer;min-width:120px;max-width:200px',
            'transition:border-color .15s,background .15s'
        ].join(';');

        chip.innerHTML = `
            <div style="display:flex;align-items:center;gap:5px">
                <span style="width:8px;height:8px;border-radius:50%;background:${dot};flex-shrink:0"></span>
                <span style="font-weight:600;font-size:12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1" title="${esc(s.name)}">${esc(s.name)}</span>
                ${s.pinned ? '<span style="font-size:11px">📌</span>' : ''}
                <button data-del="${s.id}" title="삭제" style="margin-left:2px;background:none;border:none;color:var(--t2);cursor:pointer;font-size:13px;line-height:1;padding:0 2px;flex-shrink:0">×</button>
            </div>
            <div style="font-size:11px;color:var(--t2)">${label} · ${s.tagCount}태그 · ${s.samplingMs}ms</div>
            <div style="font-size:10px;color:var(--t3)">${fastFormatDuration(s.durationSec)} · ${fastFormatDateTime(s.startedAt).slice(0,10)}</div>
        `;
        chip.querySelector('[data-del]').addEventListener('click', e => {
            e.stopPropagation();
            fastDelete(s.id);
        });
        chip.onclick = () => fastSelect(s.id);
        list.appendChild(chip);
    });
}

async function fastStart() {
    const name = document.getElementById('fast-session-name').value.trim();
    if (!name) { alert('세션 이름을 입력하세요.'); return; }

    const select   = document.getElementById('fast-tag-select');
    const tags     = Array.from(select.selectedOptions).map(o => o.value);
    if (tags.length === 0) { alert('태그를 최소 1개 이상 선택하세요.'); return; }
    if (tags.length > 8)   { alert('태그는 최대 8개까지 선택 가능합니다.'); return; }

    const samplingMs    = parseInt(document.getElementById('fast-sampling-ms').value);
    const durationSec   = parseInt(document.getElementById('fast-duration-sec').value);
    const retVal        = document.getElementById('fast-retention-days').value.trim();
    const retentionDays = retVal ? parseInt(retVal) : null;

    const res = await fetch('/api/fast/start', {
        method:  'POST',
        headers: { 'Content-Type': 'application/json' },
        body:    JSON.stringify({ name, samplingMs, durationSec, tagList: tags, retentionDays })
    });

    if (!res.ok) {
        const err = await res.json();
        alert('오류: ' + (err.error ?? '알 수 없는 오류'));
        return;
    }

    const data = await res.json();
    fastModalClose();
    await fastSessionsLoad();
    fastSelect(data.id);
}

async function fastStop(id) {
    if (!confirm('세션을 중지하시겠습니까?')) return;
    const res = await fetch(`/api/fast/${id}/stop`, { method: 'POST' });
    if (!res.ok) { alert('중지 실패'); return; }
    fastLivePollStop();
    await fastSessionsLoad();
    await fastSelect(id);
}

async function fastDelete(id) {
    if (!confirm('세션과 수집 데이터를 삭제하시겠습니까?')) return;
    const res = await fetch(`/api/fast/${id}`, { method: 'DELETE' });
    if (!res.ok) { alert('삭제 실패'); return; }
    fastLivePollStop();
    fastCurrentSessionId = null;
    fastClearChart();
    document.getElementById('fast-session-title').textContent = '세션 상세';
    ['btn-fast-stop','btn-fast-export-xlsx','btn-fast-export-csv','btn-fast-delete','btn-fast-pin']
        .forEach(btnId => document.getElementById(btnId).style.display = 'none');
    await fastSessionsLoad();
}

async function fastPin(id) {
    const btn    = document.getElementById('btn-fast-pin');
    const pinned = btn.textContent.trim() === '고정';
    const res    = await fetch(`/api/fast/${id}/pin`, {
        method:  'POST',
        headers: { 'Content-Type': 'application/json' },
        body:    JSON.stringify({ pinned })
    });
    if (!res.ok) { alert('고정 변경 실패'); return; }
    await fastSessionsLoad();
    await fastSelect(id);
}

async function fastSelect(id) {
    fastCurrentSessionId = id;

    // 칩 active 스타일 즉시 갱신
    document.querySelectorAll('#fast-session-list > div').forEach(chip => {
        const isActive = parseInt(chip.dataset.id) === id;
        chip.style.background   = isActive ? 'rgba(229,85,85,.12)' : 'var(--s3)';
        chip.style.borderColor  = isActive ? 'var(--red,#e55)'     : 'var(--bd)';
    });

    const res = await fetch(`/api/fast/${id}`);
    if (!res.ok) { alert('세션 조회 실패'); return; }
    const session = await res.json();

    document.getElementById('fast-session-title').textContent = `${session.name} (${session.status})`;

    const isRunning  = session.status === 'Running';
    const isFinished = !isRunning;

    document.getElementById('btn-fast-stop').style.display        = isRunning  ? 'inline-block' : 'none';
    document.getElementById('btn-fast-export-xlsx').style.display = isFinished ? 'inline-block' : 'none';
    document.getElementById('btn-fast-export-csv').style.display  = isFinished ? 'inline-block' : 'none';
    document.getElementById('btn-fast-delete').style.display      = 'inline-block';
    document.getElementById('btn-fast-pin').style.display         = 'inline-block';
    document.getElementById('btn-fast-pin').textContent           = session.pinned ? '고정 해제' : '고정';

    await fastRenderChart();
    await fastUpdateProgress(session);

    if (isRunning) fastLivePollStart();
    else           fastLivePollStop();
}

// ═══════════════════════════════════════════════════════════════
// fastRecord — 차트
// ═══════════════════════════════════════════════════════════════

async function fastRenderChart() {
    if (!fastCurrentSessionId) return;

    const res = await fetch(`/api/fast/${fastCurrentSessionId}/records`);
    if (!res.ok) return;
    const data = await res.json();

    const container = document.getElementById('fast-chart-container');

    if (!data.items || data.items.length === 0) {
        container.innerHTML = '<div class="text-center text-muted pt-5">수집된 데이터가 없습니다.</div>';
        return;
    }

    // Long 포맷 → PIVOT (recorded_at 기준 그룹화)
    const grouped = {};
    for (const r of data.items) {
        if (!grouped[r.recordedAt]) grouped[r.recordedAt] = {};
        grouped[r.recordedAt][r.tagName] = parseFloat(r.value) || null;
    }

    const times    = Object.keys(grouped).sort();
    const timesNum = times.map(t => new Date(t).getTime() / 1000); // uPlot: Unix seconds

    // uPlot data: [[x...], [y1...], [y2...], ...]
    const uData    = [timesNum, ...data.tagNames.map(tag => times.map(t => grouped[t][tag] ?? null))];

    // 동일 태그 구성이면 setData()로 인플레이스 업데이트 → zoom/pan 상태 유지
    const tagsKey = data.tagNames.join('\0');
    if (fastChart && fastChartTagNames === tagsKey) {
        fastChart.setData(uData, false);   // false = 스케일 유지 (zoom 보존)
        return;
    }

    // 최초 생성 또는 태그 구성 변경 시 차트 재생성
    fastChartTagNames = tagsKey;
    fastClearChart();

    const opts = {
        title:  'fastRecord 트렌드',
        width:  container.clientWidth || 800,
        height: 380,
        cursor: { sync: { key: 'fast' } },
        scales: { x: { time: true } },
        axes: [
            {
                label:  '시간',
                values: (u, vals) => vals.map(v => new Date(v * 1000).toLocaleTimeString('ko-KR'))
            },
            { label: '값' }
        ],
        series: [
            {},
            ...data.tagNames.map(tag => ({
                label:  tag,
                stroke: fastTagColor(tag),
                width:  2
            }))
        ]
    };

    fastChart = new uPlot(opts, uData, container);
}

function fastClearChart() {
    fastChartTagNames = null;
    if (fastChart) {
        fastChart.destroy();
        fastChart = null;
    }
    document.getElementById('fast-chart-container').innerHTML = '';
}

// ═══════════════════════════════════════════════════════════════
// fastRecord — 라이브 폴링
// ═══════════════════════════════════════════════════════════════

function fastLivePollStart() {
    if (fastLivePollTimer) return;
    fastLivePollTimer = setInterval(async () => {
        if (!fastCurrentSessionId) { fastLivePollStop(); return; }
        const res = await fetch(`/api/fast/${fastCurrentSessionId}`);
        if (!res.ok) return;
        const session = await res.json();
        await fastUpdateProgress(session);
        await fastRenderChart();
        if (session.status !== 'Running') {
            fastLivePollStop();
            await fastSelect(fastCurrentSessionId);
        }
    }, 2000);
}

function fastLivePollStop() {
    if (fastLivePollTimer) {
        clearInterval(fastLivePollTimer);
        fastLivePollTimer = null;
    }
}

async function fastUpdateProgress(session) {
    const elapsed  = Math.floor((Date.now() - new Date(session.startedAt).getTime()) / 1000);
    const progress = Math.min((elapsed / session.durationSec) * 100, 100);

    document.getElementById('fast-progress-bar').style.width = `${progress}%`;

    const expectedRows = Math.floor(elapsed / (session.samplingMs / 1000)) * session.tagList?.length ?? 0;
    document.getElementById('fast-progress-text').textContent =
        `${session.rowCount.toLocaleString()} / ~${expectedRows.toLocaleString()} (${progress.toFixed(1)}%)`;
    document.getElementById('fast-elapsed-time').textContent =
        `경과: ${fastFormatDuration(Math.min(elapsed, session.durationSec))} / ${fastFormatDuration(session.durationSec)}`;
}

// ═══════════════════════════════════════════════════════════════
// fastRecord — 유틸
// ═══════════════════════════════════════════════════════════════

function fastFormatDuration(seconds) {
    const h = Math.floor(seconds / 3600);
    const m = Math.floor((seconds % 3600) / 60);
    const s = seconds % 60;
    if (h > 0) return `${h}h ${m}m`;
    if (m > 0) return `${m}m ${s}s`;
    return `${s}s`;
}

function fastFormatDateTime(dt) {
    return new Date(dt).toLocaleString('ko-KR');
}

function fastTagColor(tag) {
    const palette = ['#e6194b','#3cb44b','#4363d8','#f58231','#911eb4',
                     '#42d4f4','#f032e6','#bfef45','#469990','#fabed4'];
    let sum = 0;
    for (let i = 0; i < tag.length; i++) sum += tag.charCodeAt(i);
    return palette[sum % palette.length];
}

// ═══════════════════════════════════════════════════════════════
// fastRecord — 이벤트 리스너
// ═══════════════════════════════════════════════════════════════

paneInit.fast = function() {
    fastSessionsLoad();

    const bind = (id, fn) => {
        const el = document.getElementById(id);
        if (el && !el.dataset.fastBound) { el.addEventListener('click', fn); el.dataset.fastBound = '1'; }
    };

    // DB 접속 버튼
    bind('btn-fast-db-connect', fastDbConnect);

    // + 신규 버튼 — DB 연결 확인 후 모달 열기
    bind('btn-fast-new', async () => {
        if (!fastDbConnected) {
            alert('데이터베이스 접속을 먼저 완료해주세요. "DB 접속" 버튼을 눌러주세요.');
            return;
        }

        const select = document.getElementById('fast-tag-select');
        select.innerHTML = '<option disabled>로딩 중...</option>';
        document.getElementById('fast-session-name').value   = '';
        document.getElementById('fast-retention-days').value = '';
        document.getElementById('modal-fast-new').style.display = 'flex';

        try {
            const res = await fetch('/api/gateway/tags?limit=500');
            if (res.ok) {
                const data = await res.json();
                select.innerHTML = '';
                (data || []).forEach(p => {
                    const opt = document.createElement('option');
                    opt.value = p.tagName;
                    opt.textContent = p.tagName;
                    select.appendChild(opt);
                });
            } else {
                select.innerHTML = '<option disabled>태그 목록 로드 실패</option>';
            }
        } catch (e) {
            console.error('[fast] 태그 목록 로드 실패:', e);
            select.innerHTML = '<option disabled>태그 목록 로드 실패</option>';
        }
    });

    // btn-fast-start: onclick="fastStart()" 으로 HTML에서 직접 처리

    bind('btn-fast-stop', () => {
        if (fastCurrentSessionId) fastStop(fastCurrentSessionId);
    });

    bind('btn-fast-delete', () => {
        if (fastCurrentSessionId) fastDelete(fastCurrentSessionId);
    });

    bind('btn-fast-pin', () => {
        if (fastCurrentSessionId) fastPin(fastCurrentSessionId);
    });

    // Excel Export
    bind('btn-fast-export-xlsx', async () => {
        if (!fastCurrentSessionId) return;
        const res = await fetch(`/api/fast/${fastCurrentSessionId}/records`);
        if (!res.ok) return;
        const data = await res.json();

        // Long → Wide (배열의 배열 형식으로 XLSX.utils.aoa_to_sheet에 전달)
        const timeMap = {};
        for (const r of data.items) {
            if (!timeMap[r.recordedAt]) timeMap[r.recordedAt] = {};
            timeMap[r.recordedAt][r.tagName] = r.value;
        }

        const rows = [['recorded_at', ...data.tagNames]];
        for (const t of Object.keys(timeMap).sort()) {
            rows.push([new Date(t).toLocaleString('ko-KR'),
                       ...data.tagNames.map(tag => timeMap[t][tag] ?? '')]);
        }

        const ws = XLSX.utils.aoa_to_sheet(rows);
        const wb = XLSX.utils.book_new();
        XLSX.utils.book_append_sheet(wb, ws, 'fastRecord');
        XLSX.writeFile(wb, `fast-${fastCurrentSessionId}-${new Date().toISOString().slice(0,10)}.xlsx`);
    });

    // CSV Export (서버 스트리밍)
    bind('btn-fast-export-csv', async () => {
        if (!fastCurrentSessionId) return;
        const res  = await fetch(`/api/fast/${fastCurrentSessionId}/csv`);
        if (!res.ok) return;
        const blob = await res.blob();
        const url  = URL.createObjectURL(blob);
        const a    = document.createElement('a');
        a.href     = url;
        a.download = `fast-${fastCurrentSessionId}-${new Date().toISOString().slice(0,10)}.csv`;
        a.click();
        URL.revokeObjectURL(url);
    });

    // 탭 전환 시 세션 목록 갱신
    document.querySelectorAll('[href="#pane-fast"]').forEach(a => {
        if (!a.dataset.fastTabBound) {
            a.addEventListener('show.bs.tab', () => fastSessionsLoad());
            a.dataset.fastTabBound = '1';
        }
    });
};
