from datetime import datetime
import time
import os
from pathlib import Path
from dotenv import load_dotenv
from modules.services.kis import KISClient

class MacroAnalyzer:
    """
    KIS API를 활용한 거시경제(시장 지수) 분석 모듈
    yfinance 대신 한국투자증권 API를 사용하여 안정적인 KOSPI, KOSDAQ 데이터를 수집함.
    """
    
    @staticmethod
    def get_macro_status(kis_client):
        """
        시장 주요 지수(KOSPI, KOSDAQ)를 조회하여 시장 위험도를 평가함.
        Args:
            kis_client (KISClient): 인증된 KIS API 클라이언트 인스턴스
            
        Returns:
            dict: 시장 상태 (SAFE, CAUTION, DANGER) 및 지표 데이터
        """
        indicators = {
            "KOSPI": "0001",
            "KOSDAQ": "1001",
            "KOSPI200": "0028",
        }

        results = {}
        risk_score = 0

        print("🌍 [Macro] Fetching market indices via KIS API...")

        for name, code in indicators.items():
            data = kis_client.get_current_index(code)
            time.sleep(0.6)  # Rate Limit 방지 (초당 2회 제한)

            if data and data.get('price', 0) != 0:
                results[name] = data
                print(f"   - {name}: {data['price']} ({data['change']}%)")

                # 리스크 평가 로직 (2% 이상 폭락 장이면 위험)
                change = data['change']
                if change <= -2.0:
                    risk_score += 2 # 패닉 상태
                elif change <= -1.0:
                    risk_score += 1 # 주의 상태
            else:
                results[name] = {"price": 0, "change": 0, "high": 0, "low": 0,
                                 "prev_close": 0, "volume": 0, "trade_value": 0}
        
        # [신규] 시장 스트레스 지수(MSI) 추가
        time.sleep(0.6)
        kospi_stress = MacroAnalyzer.calculate_stress_index(kis_client, "0001")
        results['MSI'] = kospi_stress
        print(f"   - Market Stress Index: {kospi_stress}")

        if kospi_stress >= 50:
            risk_score += 2
        elif kospi_stress >= 30:
            risk_score += 1

        # [v2.0] KOSPI/KOSDAQ 연동 위험도 (둘 다 하락 시 더 위험)
        kospi_change = results.get('KOSPI', {}).get('change', 0)
        kosdaq_change = results.get('KOSDAQ', {}).get('change', 0)
        if kospi_change <= -1.0 and kosdaq_change <= -1.0:
            risk_score += 1  # 양대 지수 동반 하락
            print(f"   ⚠️ Both KOSPI({kospi_change}%) & KOSDAQ({kosdaq_change}%) declining!")

        # [v2.0] 급반등 감지 (전일 급락 후 반등 = 불안정)
        if kospi_change >= 2.0 and kospi_stress >= 30:
            risk_score = max(risk_score, 1)  # 급반등이지만 스트레스 높으면 CAUTION 유지
            print(f"   📈 Sharp rebound detected but MSI still elevated")

        # 시장 상태 정의
        status = "SAFE"
        if risk_score >= 3:
            status = "DANGER"
        elif risk_score >= 1:
            status = "CAUTION"

        return {
            "status": status,
            "risk_score": risk_score,
            "indicators": results
        }

    @staticmethod
    def calculate_stress_index(kis_client, market_code="0001"):
        """
        시장 스트레스 지수(MSI) 계산
        - 0~100 사이의 값 (높을수록 위험)
        - 요소: 변동성(Volatility), 추세 이격도(MA Divergence)
        """
        import numpy as np
        
        # 일봉 데이터 조회 (약 3개월치 = 60일 이상)
        prices = kis_client.get_daily_index_price(market_code, period="D")
        if not prices or len(prices) < 20:
            return 0
            
        prices = np.array(prices)
        
        # 1. 역사적 변동성 (20일)
        # 로그 수익률 계산
        returns = np.diff(np.log(prices)) 
        # 연환산 변동성 (Trading days = 252)
        volatility = np.std(returns[-20:]) * np.sqrt(252) * 100 
        
        # 2. 이동평균 이격도
        ma20 = np.mean(prices[-20:])
        current_price = prices[-1]
        disparity = (current_price - ma20) / ma20 * 100
        
        # 3. 스트레스 점수 산출
        # 변동성이 20% 넘어가면 위험, 이격도가 -5% 이하면 위험
        stress_score = 0
        
        # 변동성 기여 (평소 10~15%, 30% 이상 공포)
        # 10 이하면 0점, 40 이상이면 60점 만점
        v_score = min(max((volatility - 10) * 2, 0), 60)
        
        # 하락 추세 기여 (-10% 이격이면 +40점)
        d_score = 0
        if disparity < 0:
            d_score = min(abs(disparity) * 4, 40)
            
        total_stress = v_score + d_score
        return round(total_stress, 2)

if __name__ == "__main__":
    # 테스트를 위한 코드
    load_dotenv(Path(__file__).parent.parent.parent.parent / ".env")
    
    # 환경변수 로딩 및 클라이언트 초기화
    if os.getenv("KIS_ENV_TYPE") == "real":
        app_key = os.getenv("KIS_REAL_APP_KEY")
        app_secret = os.getenv("KIS_REAL_APP_SECRET")
        account = os.getenv("KIS_REAL_ACCOUNT")
        is_virtual = False
    else:
        app_key = os.getenv("KIS_VIRTUAL_APP_KEY")
        app_secret = os.getenv("KIS_VIRTUAL_APP_SECRET")
        account = os.getenv("KIS_VIRTUAL_ACCOUNT")
        is_virtual = True
        
    kis = KISClient(app_key, app_secret, account, is_virtual)
    
    # 토큰 발급 (필요 시)
    kis.ensure_token()
    
    # 분석 실행
    report = MacroAnalyzer.get_macro_status(kis)
    print("\n📊 [Macro Report]")
    print(f"Status: {report['status']}")
    print(f"Data: {report['indicators']}")
