/**
 * 체결강도 상승 감지 실시간 표시
 * - 10초마다 /api/signal 폴링
 * - 감지된 종목 WS 구독으로 실시간 가격/체결강도 갱신
 * - 각 카드에 체결강도 히스토리 미니 라인차트 표시
 */
(function () {
    const gridEl     = document.getElementById('signalGrid');
    const emptyEl    = document.getElementById('signalEmpty');
    const updatedEl  = document.getElementById('signalUpdatedAt');
    const INTERVAL   = 10 * 1000;
    const MAX_HISTORY = 60; // 최대 60개 포인트 유지

    let currentCodes = [];

    // 종목별 체결강도 히스토리 (카드 재렌더링 시에도 유지)
    const cntrHistory = new Map(); // code → number[]

    function fmtNum(n) {
        if (n == null) return '-';
        return Math.abs(n).toLocaleString('ko-KR');
    }
    function fmtRate(f) {
        if (f == null) return '-';
        return (f >= 0 ? '+' : '') + f.toFixed(2) + '%';
    }
    function fmtCntr(f) {
        return f ? f.toFixed(2) : '-';
    }
    function rateClass(f) {
        if (f > 0) return 'text-red-500';
        if (f < 0) return 'text-blue-500';
        return 'text-gray-500';
    }
    function rateBadgeClass(f) {
        if (f > 0) return 'bg-red-50 text-red-500';
        if (f < 0) return 'bg-blue-50 text-blue-500';
        return 'bg-gray-100 text-gray-500';
    }

    // 체결강도 히스토리에 값 추가
    function recordCntr(code, value) {
        if (value == null || value === 0) return;
        if (!cntrHistory.has(code)) cntrHistory.set(code, []);
        const arr = cntrHistory.get(code);
        arr.push(value);
        if (arr.length > MAX_HISTORY) arr.shift();
    }

    // canvas에 체결강도 라인차트 그리기
    function drawChart(code) {
        const canvas = document.getElementById(`sg-chart-${code}`);
        if (!canvas) return;
        const data = cntrHistory.get(code) || [];
        if (data.length < 2) return;

        // canvas 픽셀 크기를 실제 표시 크기에 맞춤 (선명도 유지)
        const rect = canvas.getBoundingClientRect();
        const dpr  = window.devicePixelRatio || 1;
        const w    = Math.floor(rect.width  * dpr);
        const h    = Math.floor(rect.height * dpr);
        if (w === 0 || h === 0) return;
        if (canvas.width !== w || canvas.height !== h) {
            canvas.width  = w;
            canvas.height = h;
        }

        const ctx   = canvas.getContext('2d');
        const pad   = 3 * dpr; // 상하 여백
        const drawH = h - pad * 2;

        ctx.clearRect(0, 0, w, h);

        const min   = Math.min(...data);
        const max   = Math.max(...data);
        const range = max - min || 1;
        const step  = w / (data.length - 1);

        const getY = val => h - pad - ((val - min) / range) * drawH;

        // 그라디언트 필
        const lastX = (data.length - 1) * step;
        const grad  = ctx.createLinearGradient(0, pad, 0, h);
        grad.addColorStop(0, 'rgba(249,115,22,0.35)');
        grad.addColorStop(1, 'rgba(249,115,22,0)');

        ctx.beginPath();
        data.forEach((val, i) => {
            const x = i * step;
            const y = getY(val);
            i === 0 ? ctx.moveTo(x, y) : ctx.lineTo(x, y);
        });
        ctx.lineTo(lastX, h);
        ctx.lineTo(0, h);
        ctx.closePath();
        ctx.fillStyle = grad;
        ctx.fill();

        // 라인
        ctx.beginPath();
        data.forEach((val, i) => {
            const x = i * step;
            const y = getY(val);
            i === 0 ? ctx.moveTo(x, y) : ctx.lineTo(x, y);
        });
        ctx.strokeStyle = '#f97316';
        ctx.lineWidth   = 1.5 * dpr;
        ctx.lineJoin    = 'round';
        ctx.stroke();

        // 마지막 포인트 강조
        const lastVal = data[data.length - 1];
        ctx.beginPath();
        ctx.arc(lastX, getY(lastVal), 2.5 * dpr, 0, Math.PI * 2);
        ctx.fillStyle = '#f97316';
        ctx.fill();
    }

    // 신호 유형 뱃지 HTML 생성
    function signalTypeBadge(s) {
        if (!s.signalType) return '';
        const map = {
            '강한매수':  'bg-red-600 text-white border-red-700',
            '매수우세':  'bg-orange-400 text-white border-orange-500',
            '물량소화':  'bg-yellow-100 text-yellow-700 border-yellow-300',
            '추격위험':  'bg-gray-800 text-white border-gray-900',
            '약한상승':  'bg-gray-100 text-gray-500 border-gray-300',
        };
        const cls = map[s.signalType] || 'bg-gray-100 text-gray-500';
        return `<span class="border ${cls} text-xs px-1.5 py-0.5 rounded font-bold">${s.signalType}</span>`;
    }

    // 1시간 이내 상승 확률 뱃지 HTML 생성
    function riseProbBadge(s) {
        if (!s.riseLabel) return '';
        const isVeryHigh = s.riseLabel === '매우 높음';
        const cls = isVeryHigh
            ? 'bg-emerald-500 text-white border border-emerald-600'
            : 'bg-teal-100 text-teal-700 border border-teal-200';
        const icon = isVeryHigh ? '🚀' : '📈';
        return `<span class="${cls} text-xs px-1.5 py-0.5 rounded font-bold" title="상승확률점수: ${s.riseScore}점">${icon} ${s.riseLabel}</span>`;
    }

    // 호재/악재/중립 뱃지 HTML 생성 ("정보없음"은 빈 문자열 반환)
    function sentimentBadge(s) {
        const map = {
            '호재': 'bg-green-100 text-green-700 border border-green-200',
            '악재': 'bg-red-100 text-red-600 border border-red-200',
            '중립': 'bg-gray-100 text-gray-500',
        };
        const cls = map[s.sentiment];
        if (!cls) return '';
        const title = s.sentimentReason ? ` title="${s.sentimentReason}"` : '';
        return `<span class="${cls} text-xs px-1.5 py-0.5 rounded font-semibold"${title}>${s.sentiment}</span>`;
    }

    // 연속 상승 횟수에 따른 뱃지 텍스트
    function risingBadge(n) {
        if (n >= 4) return `<span class="bg-red-500 text-white text-xs px-1.5 py-0.5 rounded font-bold">🔥${n}연속</span>`;
        if (n >= 2) return `<span class="bg-orange-400 text-white text-xs px-1.5 py-0.5 rounded font-bold">▲${n}연속</span>`;
        return `<span class="bg-yellow-100 text-yellow-700 text-xs px-1.5 py-0.5 rounded font-semibold">↑상승</span>`;
    }

    // 복합 지표 섹션 HTML 생성 (거래량 배수 · 매도잔량비 · 가격 위치)
    function complexIndicators(s) {
        const rows = [];

        // 거래량 증가율
        if (s.volRatio > 0) {
            let volCls = 'text-gray-500';
            let volLabel = `${s.volRatio.toFixed(1)}배`;
            if (s.volRatio >= 10) { volCls = 'text-gray-400 line-through'; volLabel += ' ⚠과열'; }
            else if (s.volRatio >= 5)  volCls = 'text-orange-400';
            else if (s.volRatio >= 2)  volCls = 'text-green-600 font-semibold';
            else if (s.volRatio >= 1)  volCls = 'text-green-500';
            rows.push(`<div class="flex justify-between">
                <span class="text-gray-400">거래량 증가</span>
                <span class="${volCls}">${volLabel}</span>
            </div>`);
        }

        // 매도/매수 잔량비
        if (s.totalAskVol > 0 && s.totalBidVol > 0) {
            const ratio = s.askBidRatio.toFixed(2);
            let ratioCls = 'text-gray-500';
            let ratioLabel = `${ratio} (`;
            if (s.askBidRatio <= 0.7)       { ratioCls = 'text-green-600 font-semibold'; ratioLabel += '매수 강세)'; }
            else if (s.askBidRatio <= 1.0)  { ratioCls = 'text-green-500'; ratioLabel += '매수 우세)'; }
            else if (s.askBidRatio <= 1.5)  { ratioCls = 'text-gray-500'; ratioLabel += '균형)'; }
            else                            { ratioCls = 'text-blue-500'; ratioLabel += '매도 우세)'; }
            rows.push(`<div class="flex justify-between">
                <span class="text-gray-400">매도/매수 잔량</span>
                <span class="${ratioCls} text-xs">${ratioLabel}</span>
            </div>`);
        }

        // 가격 위치 (장중 저가~고가 내 %)
        if (s.pricePos !== undefined) {
            const pos = s.pricePos.toFixed(0);
            let posCls = 'text-gray-500';
            if (s.pricePos >= 80)       posCls = 'text-red-500 font-semibold';
            else if (s.pricePos >= 60)  posCls = 'text-orange-400';
            else if (s.pricePos <= 30)  posCls = 'text-blue-400';
            rows.push(`<div class="flex justify-between">
                <span class="text-gray-400">가격 위치</span>
                <span class="${posCls}">${pos}%</span>
            </div>`);
        }

        if (rows.length === 0) return '';
        return `<div class="mt-2 pt-2 border-t border-gray-100 space-y-1 text-sm">${rows.join('')}</div>`;
    }

    // 익일 추세 예상 리포팅 HTML 생성
    function nextDayBadge(s) {
        const trendMap = {
            '상승': { bg: 'bg-red-50 border-red-200',   icon: '▲', cls: 'text-red-500'  },
            '하락': { bg: 'bg-blue-50 border-blue-200', icon: '▼', cls: 'text-blue-500' },
            '횡보': { bg: 'bg-gray-50 border-gray-200', icon: '─', cls: 'text-gray-500' },
        };

        // LLM 결과가 없으면 "분석 중..." 표시
        if (!s.nextDayTrend) {
            return `<div class="mt-2 pt-2 border-t border-gray-100">
                <div class="flex items-center justify-between">
                    <span class="text-xs text-gray-400">익일 추세</span>
                    <span class="text-xs text-gray-400 animate-pulse">분석 중...</span>
                </div>
            </div>`;
        }

        const style = trendMap[s.nextDayTrend] || trendMap['횡보'];
        const confBadge = s.nextDayConf
            ? `<span class="text-xs text-gray-400 ml-1">(${s.nextDayConf})</span>`
            : '';
        const reasonTip = s.nextDayReason ? ` title="${s.nextDayReason}"` : '';
        return `<div class="mt-2 pt-2 border-t border-gray-100">
            <div class="flex items-center justify-between">
                <span class="text-xs text-gray-400">익일 추세</span>
                <span class="${style.bg} ${style.cls} border text-xs px-2 py-0.5 rounded font-bold"${reasonTip}>
                    ${style.icon} ${s.nextDayTrend}${confBadge}
                </span>
            </div>
            ${s.nextDayReason ? `<p class="text-xs text-gray-400 mt-1 truncate" title="${s.nextDayReason}">${s.nextDayReason}</p>` : ''}
        </div>`;
    }

    // AI 목표가 뱃지 HTML 생성
    function targetPriceBadge(s) {
        if (!s.targetPrice || s.targetPrice === 0) return '';
        const diff = s.targetPrice - s.currentPrice;
        const pct  = ((diff / s.currentPrice) * 100).toFixed(1);
        const sign = diff >= 0 ? '+' : '';
        const cls  = diff >= 0 ? 'bg-purple-50 text-purple-600 border border-purple-200' : 'bg-gray-100 text-gray-500';
        const title = s.targetReason ? ` title="${s.targetReason}"` : '';
        return `<div class="flex justify-between items-center mt-2 pt-2 border-t border-purple-50">
            <span class="text-xs text-gray-400">AI 목표가</span>
            <span class="${cls} text-xs px-2 py-0.5 rounded font-semibold"${title}>
                ${fmtNum(s.targetPrice)}원 <span class="opacity-70">(${sign}${pct}%)</span>
            </span>
        </div>`;
    }

    // 시그널 종목 카드 HTML 생성
    function makeCard(s) {
        const diff = s.cntrStr - s.prevCntrStr;
        const rising = s.risingCount || 1;
        return `
        <a href="/stock/${s.code}" id="sg-${s.code}"
           class="block bg-white rounded-xl shadow-sm hover:shadow-md transition-shadow p-5 border border-orange-100">
            <div class="flex justify-between items-start mb-3">
                <span class="text-sm text-gray-400 font-mono">${s.code}</span>
                <div class="flex items-center gap-1.5 flex-wrap justify-end">
                    ${signalTypeBadge(s)}
                    ${riseProbBadge(s)}
                    ${risingBadge(rising)}
                    ${sentimentBadge(s)}
                    <span id="sg-rate-${s.code}" class="text-sm px-2.5 py-0.5 rounded-full font-semibold ${rateBadgeClass(s.changeRate)}">
                        ${fmtRate(s.changeRate)}
                    </span>
                </div>
            </div>
            <p class="font-bold text-gray-800 text-base truncate mb-1">${s.name}</p>
            <p id="sg-price-${s.code}" class="text-2xl font-bold ${rateClass(s.changeRate)} mb-3">${fmtNum(s.currentPrice)}원</p>
            <div class="pt-3 border-t border-gray-50 text-sm space-y-1.5">
                <div class="flex justify-between">
                    <span class="text-gray-400">체결강도</span>
                    <span id="sg-cntr-${s.code}" class="font-bold text-orange-500">${fmtCntr(s.cntrStr)}</span>
                </div>
                <div class="flex justify-between">
                    <span class="text-gray-400">직전 대비</span>
                    <span class="text-gray-500">${fmtCntr(s.prevCntrStr)} → <span class="text-green-500 font-semibold">+${diff.toFixed(2)}</span></span>
                </div>
                <div class="flex justify-between">
                    <span class="text-gray-400">거래량</span>
                    <span id="sg-vol-${s.code}" class="text-gray-600">${fmtNum(s.volume)}</span>
                </div>
                ${complexIndicators(s)}
                ${targetPriceBadge(s)}
                ${nextDayBadge(s)}
            </div>
            <!-- 체결강도 미니 라인차트 -->
            <canvas id="sg-chart-${s.code}"
                style="width:100%;height:48px;display:block;margin-top:12px;"
                class="rounded-sm"></canvas>
        </a>`;
    }

    // 카드 삽입 후 canvas 초기화 및 초기값 기록
    function initChart(code, cntrStr) {
        recordCntr(code, cntrStr);
        drawChart(code);
    }

    // WebSocket 실시간 가격 수신 시 카드 업데이트
    function updateCard(code, data) {
        const priceEl = document.getElementById(`sg-price-${code}`);
        const rateEl  = document.getElementById(`sg-rate-${code}`);
        const cntrEl  = document.getElementById(`sg-cntr-${code}`);
        const volEl   = document.getElementById(`sg-vol-${code}`);
        if (!priceEl) return;

        const rate = data.changeRate ?? 0;
        priceEl.textContent = fmtNum(data.currentPrice) + '원';
        priceEl.className   = `text-lg font-bold ${rateClass(rate)}`;
        rateEl.textContent  = fmtRate(rate);
        rateEl.className    = `text-xs px-2 py-0.5 rounded-full font-semibold ${rateBadgeClass(rate)}`;
        if (cntrEl && data.cntrStr !== undefined) {
            cntrEl.textContent = fmtCntr(data.cntrStr);
        }
        if (volEl) volEl.textContent = fmtNum(data.volume);

        // 체결강도 히스토리 기록 후 차트 갱신
        if (data.cntrStr != null && data.cntrStr !== 0) {
            recordCntr(code, data.cntrStr);
            drawChart(code);
        }
    }

    // 이전 구독 종목 해제 후 신규 종목 구독
    function resubscribe(newCodes) {
        currentCodes.forEach(code => {
            if (!newCodes.includes(code)) stockWS.unsubscribe(code);
        });
        newCodes.forEach(code => {
            if (!currentCodes.includes(code)) {
                stockWS.subscribe(code);
                stockWS.onPrice(code, data => updateCard(code, data));
            }
        });
        currentCodes = newCodes;
    }

    // /api/signal 조회 후 그리드 렌더링
    async function fetchAndRender() {
        try {
            const resp = await fetch('/api/signal');
            if (!resp.ok) throw new Error('조회 실패');
            const signals = await resp.json();

            const now = new Date();
            updatedEl.textContent = now.toTimeString().slice(0, 8) + ' 기준';

            if (!Array.isArray(signals) || signals.length === 0) {
                gridEl.innerHTML = '';
                if (emptyEl) emptyEl.classList.remove('hidden');
                resubscribe([]);
                return;
            }

            if (emptyEl) emptyEl.classList.add('hidden');
            gridEl.innerHTML = signals.map(makeCard).join('');

            // 카드 삽입 후 각 종목 초기 체결강도 기록 및 차트 초기화
            signals.forEach(s => initChart(s.code, s.cntrStr));

            resubscribe(signals.map(s => s.code));
        } catch (e) {
            console.error('시그널 조회 실패:', e);
        }
    }

    let pollTimer = null;

    function startPolling() {
        if (pollTimer) return;
        fetchAndRender();
        pollTimer = setInterval(fetchAndRender, INTERVAL);
    }

    function stopPolling() {
        if (pollTimer) {
            clearInterval(pollTimer);
            pollTimer = null;
        }
        // 그리드 비우기
        gridEl.innerHTML = '';
        if (emptyEl) {
            emptyEl.textContent = '스캐너가 꺼져 있습니다. 버튼을 눌러 켜주세요.';
            emptyEl.classList.remove('hidden');
        }
        resubscribe([]);
    }

    // 토글 버튼 상태 적용
    const toggleBtn = document.getElementById('scannerToggleBtn');
    function applyState(enabled) {
        if (!toggleBtn) return;
        if (enabled) {
            toggleBtn.textContent = '● ON';
            toggleBtn.className = 'text-xs px-2.5 py-1 rounded-full font-semibold border transition-colors bg-green-100 text-green-700 border-green-300';
            startPolling();
        } else {
            toggleBtn.textContent = '○ OFF';
            toggleBtn.className = 'text-xs px-2.5 py-1 rounded-full font-semibold border transition-colors bg-gray-100 text-gray-400 border-gray-300';
            stopPolling();
        }
    }

    // 페이지 로드 시 백엔드 상태 조회
    fetch('/api/scanner/status')
        .then(r => r.json())
        .then(d => applyState(d.enabled))
        .catch(() => applyState(true)); // 실패 시 켜짐으로 fallback

    // 토글 버튼 클릭
    if (toggleBtn) {
        toggleBtn.addEventListener('click', async () => {
            try {
                const resp = await fetch('/api/scanner/toggle', { method: 'POST' });
                const data = await resp.json();
                applyState(data.enabled);
            } catch (e) {
                console.error('스캐너 토글 실패:', e);
            }
        });
    }
})();

// 시그널 판단 기준 모달 열기/닫기
(function () {
    const btn   = document.getElementById('signalGuideBtn');
    const modal = document.getElementById('signalGuideModal');
    const close = document.getElementById('signalGuideClose');
    if (!btn || !modal) return;

    btn.addEventListener('click', () => modal.classList.remove('hidden'));
    close.addEventListener('click', () => modal.classList.add('hidden'));
    // 모달 바깥 클릭 시 닫기
    modal.addEventListener('click', e => {
        if (e.target === modal) modal.classList.add('hidden');
    });
    // ESC 키로 닫기
    document.addEventListener('keydown', e => {
        if (e.key === 'Escape') modal.classList.add('hidden');
    });
})();