/**
 * v2.2.268 — 발굴 자동 편입 + 매수 시그널 진입 알림.
 *  - computeRecommendedBuy: 224일선 기반 매수권장가 자동 산출 규칙
 *  - detectBuyZoneEntries: 관망/고평가 → 매수사정권 전이 감지 + 중복 알림 방지
 */
import { computeRecommendedBuy } from '../src/features/stocks/stockDiscovery';
import { detectBuyZoneEntries } from '../src/features/stocks/signalClassifier';
import type { Stock } from '../src/features/stocks/types';

describe('computeRecommendedBuy — 224일선 기반 매수권장가', () => {
    test('현재가 > MA224 → MA224 (지지선 회귀 시 매수)', () => {
        expect(computeRecommendedBuy(12000, 10000)).toBe(10000);
    });

    test('현재가 ≤ MA224 → 현재가 × 0.97', () => {
        expect(computeRecommendedBuy(9000, 10000)).toBe(Math.round(9000 * 0.97));
    });

    test('MA224 없음(시세 부족) → 현재가 × 0.90 폴백', () => {
        expect(computeRecommendedBuy(10000, undefined)).toBe(9000);
    });

    test('현재가 없음/비정상 → undefined (권장가 미설정)', () => {
        expect(computeRecommendedBuy(undefined, 10000)).toBeUndefined();
        expect(computeRecommendedBuy(0, 10000)).toBeUndefined();
        expect(computeRecommendedBuy(-100)).toBeUndefined();
    });
});

describe('detectBuyZoneEntries — 매수사정권 진입 전이 감지', () => {
    const stock = (over: Partial<Stock>): Stock => ({
        이름: '테스트', 심볼: '000001',
        '3/4 필터': '[자동 평가] 충족 (ROE, 성장성, 유동성)',
        현재가: 9000, 매수권장가: '10,000',
        ...over,
    });

    test('신규 진입 (직전신호 없음 + 현재가 ≤ 권장가) → 알림 대상', () => {
        const store = [stock({})];
        const entered = detectBuyZoneEntries(store);
        expect(entered).toHaveLength(1);
        expect(entered[0].signal).toBe('BUY_ZONE');
        expect(store[0].직전신호).toBe('BUY_ZONE');
    });

    test('직전에도 매수사정권이었으면 중복 알림 안 함', () => {
        const store = [stock({ 직전신호: 'BUY_ZONE' })];
        expect(detectBuyZoneEntries(store)).toHaveLength(0);
        expect(store[0].직전신호).toBe('BUY_ZONE');
    });

    test('고평가 → 매수사정권 전이 → 알림 + 직전신호 갱신', () => {
        const store = [stock({ 직전신호: 'OVERVALUED' })];
        const entered = detectBuyZoneEntries(store);
        expect(entered).toHaveLength(1);
        expect(store[0].직전신호).toBe('BUY_ZONE');
    });

    test('필터 미충족(관망)은 가격이 권장가 아래여도 알림 없음', () => {
        const store = [stock({ '3/4 필터': '[자동 평가] 미충족 (사유: …)', 직전신호: 'HOLD' })];
        expect(detectBuyZoneEntries(store)).toHaveLength(0);
        expect(store[0].직전신호).toBe('HOLD');
    });

    test('매수권장가 없으면 BUY_ZONE 불가 → 알림 없음 (자동 산출의 존재 이유)', () => {
        const store = [stock({ 매수권장가: undefined })];
        expect(detectBuyZoneEntries(store)).toHaveLength(0);
        expect(store[0].직전신호).toBe('OVERVALUED');
    });

    test('매수사정권 이탈(가격 상승) → 직전신호가 OVERVALUED 로 → 재진입 시 다시 알림', () => {
        const store = [stock({})];
        detectBuyZoneEntries(store);                    // 1차 진입
        store[0].현재가 = 12000;                         // 권장가 위로 이탈
        expect(detectBuyZoneEntries(store)).toHaveLength(0);
        expect(store[0].직전신호).toBe('OVERVALUED');
        store[0].현재가 = 9500;                          // 재진입
        expect(detectBuyZoneEntries(store)).toHaveLength(1);
    });
});
