package service

import TradingDecision
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import model.CandleData
import network.KisTradeService
import network.NewsService
import java.time.LocalDateTime
import java.time.LocalTime
import java.time.ZoneId
import java.time.format.DateTimeFormatter
import kotlin.collections.List

import kotlin.math.*
// service/AutoTradingManager.kt
object AutoTradingManager {
    private val scope = CoroutineScope(Dispatchers.Default)
    val targetStocks = mutableListOf<String>()

    fun addStock(stockCode : String, result :(String, Boolean)->Unit) {
        targetStocks.add(stockCode)
        startTradingLoop(result)
    }

    fun startTradingLoop(result :(String, Boolean)->Unit) {
        scope.launch {
            println("🚀 10분 주기 자동 분석 및 매매 시작: ${LocalTime.now()}")
            targetStocks.forEach { stockCode ->
                launch { // 종목별 병렬 분석 (M3 Pro 파워 활용)
                    RagService.processStock(stockCode,result) {code ,decision ->
                        when (decision?.decision) {
                            "BUY" -> if (decision.confidence > 70) executeOrder(stockCode, "매수")
                            "SELL" -> executeOrder(stockCode, "매도")
                            else -> println("[$stockCode] 관망 유지: ${decision?.reason}")
                        }
                        result(decision.toString(),true)
                    }
                }
            }
            delay(10 * 60 * 1000) // 10분 대기
        }
    }



    private fun executeOrder(code: String, type: String) {
        // 실제 증권사 API 호출 로직 (한국투자증권, 키움 등)
        println("🔥 [주문 집행] $code $type 완료")
    }
}

object TechnicalAnalyzer {
    var monthly: List<CandleData> = emptyList()
    var weekly: List<CandleData> = emptyList()
    var daily: List<CandleData> = emptyList()
    var min30: List<CandleData> = emptyList()

    data class InvestmentScores(
        val ultraShort: Int, // 초단기 (분봉/에너지)
        val shortTerm: Int,  // 단기 (일봉/뉴스)
        val midTerm: Int,    // 중기 (주봉/재무)
        val longTerm: Int     // 장기 (월봉/펀더멘털)
    )

    fun calculateScores(
        financialScore: Int // 재무제표 점수 (성장률 등 기반)
    ): InvestmentScores {

        // 1. 초단기 (분봉 + 에너지 지표 위주)
        val ultra = (TechnicalAnalyzer.calculateMFI(min30, 14) * 0.4 +
                TechnicalAnalyzer.calculateStochastic(min30) * 0.3 +
                (if(TechnicalAnalyzer.calculateChange(min30.takeLast(10)) > 0) 30 else 0)).toInt()

        // 2. 단기 (일봉 추세 + OBV 에너지)
        val short = (TechnicalAnalyzer.calculateRSI(daily) * 0.3 +
                (if(TechnicalAnalyzer.calculateOBV(daily) > 0) 40 else 10) +
                (if(TechnicalAnalyzer.calculateChange(daily.takeLast(3)) > 0) 30 else 0)).toInt()

        // 3. 중기 (주봉 + 재무 점수 혼합)
        val mid = (if(TechnicalAnalyzer.calculateChange(weekly) > 0) 40 else 10) +
                (financialScore * 0.6).toInt()

        // 4. 장기 (월봉 + 섹터/기업 펀더멘털)
        val long = (if(TechnicalAnalyzer.calculateChange(monthly) > 0) 50 else 0) +
                (financialScore * 0.5).toInt()

        return InvestmentScores(
            ultraShort = ultra.coerceIn(0, 100),
            shortTerm = short.coerceIn(0, 100),
            midTerm = mid.coerceIn(0, 100),
            longTerm = long.coerceIn(0, 100)
        )
    }

    fun generateComprehensiveReport(): String {
        // [1] 단기 에너지 지표 계산 (최근 30분봉 기준)
        val obv = calculateOBV(min30)
        val mfi = calculateMFI(min30, 14)
        val adLine = calculateADLine(min30)

        // [2] 시계열별 가격 변동 및 추세 요약
        val m10 = min30.takeLast(10)
        val change10 = calculateChange(m10)
        val change30 = calculateChange(min30)
        val changeDaily = calculateChange(daily.takeLast(2)) // 전일 대비

        // [3] 이평선 및 가격 위치
        val ma5 = m10.takeLast(5).map { it.stck_prpr.toDouble() }.average()
        val currentPrice = min30.last().stck_prpr.toDouble()
        val signal = ScalpingAnalyzer().analyze(min30.toScalpingList())
        // [4] 거래량 강도
        val avgVol30 = min30.map { it.cntg_vol.toLong() }.average()
        val recentVol5 = m10.takeLast(5).map { it.cntg_vol.toLong() }.average()
        val volStrength = if (avgVol30 > 0) recentVol5 / avgVol30 else 1.0
        val atr = calculateATR(min30)
        val stochK = calculateStochastic(min30)
        val priceRange30 = min30.maxOf { it.stck_hgpr.toDouble() } - min30.minOf { it.stck_lwpr.toDouble() }
        return """
            [초단기 기술적 스켈핑 분석]
                - 종합 스코어: ${signal.compositeScore} / 100
                - 매수 신호 발생 여부: ${if (signal.buySignal) "YES" else "NO"}
                - 성공 확률 예측: ${signal.successProbPct}%
                - 위험 등급: ${signal.riskLevel} (ATR 변동성 기반)
                - RSI: ${"%.1f".format(signal.rsi)} / 거래량 비율: ${"%.1f".format(signal.volRatio)}배
                - 권장 가격: 손절가(${signal.suggestedSlPrice.toInt()}원), 익절가(${signal.suggestedTpPrice.toInt()}원)
- 월봉/주봉 위치: ${if(calculateChange(monthly) > 0) "장기 상승" else "장기 하락"} / ${if(calculateChange(weekly) > 0) "중기 상승" else "중기 하락"}
- 일봉 대비: ${ "%.2f".format(changeDaily) }% 변동
- 30분 대비: ${ "%.2f".format(change30) }% 변동
- 10분 대비: ${ "%.2f".format(change10) }% 변동
- 이평선 상태: 현재가(${currentPrice.toInt()}) vs MA5(${ma5.toInt()}) -> ${if(currentPrice > ma5) "상단 위치" else "하단 위치"}
- OBV (누적 거래량 에너지): ${ "%.0f".format(obv) } (${if(obv > 0) "누적 매수 우위" else "누적 매도 우위"})
- MFI (자금 유입 지수): ${ "%.1f".format(mfi) } (과매수 기준: 80 / 과매도 기준: 20)
- A/D (누적 분산 라인): ${ "%.0f".format(adLine) } (종가 형성 위치와 거래량 결합 수치)
- 거래량 강도: 최근 5분 평균이 30분 평균의 ${ "%.1f".format(volStrength) }배 수준
- ATR (평균 변동폭): ${"%.0f".format(atr)}원 (최근 캔들 하나가 평균적으로 움직이는 크기)
- 30분 내 최대 진폭: ${"%.0f".format(priceRange30)}원 (최고가-최저가 차이)
- 스토캐스틱(%K): ${"%.1f".format(stochK)} (100에 가까울수록 최근 파동의 고점, 0에 가까울수록 저점)
- 변동성 강도: 현재 진폭이 ATR 대비 ${"%.1f".format(priceRange30 / atr)}배 수준으로 전개 중
- 30분봉 최고가: ${min30.maxOf { it.stck_hgpr.toInt() }}
- 30분봉 최저가: ${min30.minOf { it.stck_lwpr.toInt() }}
- RSI(14): ${ "%.1f".format(calculateRSI(min30)) }
        """.trimIndent()
    }

    /**
     * ATR (Average True Range): 최근 변동 폭의 평균. 그래프의 '출렁임' 크기를 측정
     */
    fun calculateATR(candles: List<CandleData>, period: Int = 14): Double {
        val sub = candles.takeLast(period + 1)
        val trList = mutableListOf<Double>()
        for (i in 1 until sub.size) {
            val high = sub[i].stck_hgpr.toDouble()
            val low = sub[i].stck_lwpr.toDouble()
            val prevClose = sub[i - 1].stck_prpr.toDouble()

            val tr = maxOf(high - low, Math.abs(high - prevClose), Math.abs(low - prevClose))
            trList.add(tr)
        }
        return trList.average()
    }

    /**
     * Stochastic (%K): 최근 가격 범위 내에서 현재가의 위치 (0~100)
     * 반복되는 파동(Ups and Downs)에서 현재가 고점인지 저점인지 판단
     */
    fun calculateStochastic(candles: List<CandleData>, period: Int = 14): Double {
        val sub = candles.takeLast(period)
        val highest = sub.maxOf { it.stck_hgpr.toDouble() }
        val lowest = sub.minOf { it.stck_lwpr.toDouble() }
        val current = sub.last().stck_prpr.toDouble()

        return if (highest != lowest) (current - lowest) / (highest - lowest) * 100 else 50.0
    }

    private fun calculateChange(list: List<CandleData>): Double {
        val start = list.first().stck_oprc.toDouble()
        val end = list.last().stck_prpr.toDouble()
        return if (start != 0.0) ((end - start) / start) * 100 else 0.0
    }

    private fun calculateRSI(list: List<CandleData>): Double {
        if (list.size < 2) return 50.0
        var gains = 0.0
        var losses = 0.0
        for (i in 1 until list.size) {
            val diff = list[i].stck_prpr.toDouble() - list[i - 1].stck_prpr.toDouble()
            if (diff > 0) gains += diff else losses -= diff
        }
        return if (gains + losses == 0.0) 50.0 else (gains / (gains + losses)) * 100
    }

    fun calculateOBV(candles: List<CandleData>): Double {
        var obv = 0.0
        for (i in 1 until candles.size) {
            val prevClose = candles[i - 1].stck_prpr.toDouble()
            val currClose = candles[i].stck_prpr.toDouble()
            val currVol = candles[i].cntg_vol.toDouble()

            when {
                currClose > prevClose -> obv += currVol
                currClose < prevClose -> obv -= currVol
            }
        }
        return obv
    }

    /**
     * MFI (Money Flow Index) 계산 (기간: 보통 14일)
     */
    fun calculateMFI(candles: List<CandleData>, period: Int = 14): Double {
        val subList = candles.takeLast(period + 1)
        var posFlow = 0.0
        var negFlow = 0.0

        for (i in 1 until subList.size) {
            val prevTypical = (subList[i-1].stck_hgpr.toDouble() + subList[i-1].stck_lwpr.toDouble() + subList[i-1].stck_prpr.toDouble()) / 3
            val currTypical = (subList[i].stck_hgpr.toDouble() + subList[i].stck_lwpr.toDouble() + subList[i].stck_prpr.toDouble()) / 3
            val moneyFlow = currTypical * subList[i].cntg_vol.toDouble()

            if (currTypical > prevTypical) posFlow += moneyFlow
            else if (currTypical < prevTypical) negFlow += moneyFlow
        }

        return if (negFlow == 0.0) 100.0 else 100 - (100 / (1+ (posFlow / negFlow)))
    }

    private fun calculateADLine(candles: List<CandleData>): Double {
        var ad = 0.0
        candles.forEach {
            val high = it.stck_hgpr.toDouble(); val low = it.stck_lwpr.toDouble(); val close = it.stck_prpr.toDouble()
            val mfv = if (high != low) ((close - low) - (high - close)) / (high - low) else 0.0
            ad += mfv * it.cntg_vol.toDouble()
        }
        return ad
    }

    fun clear() {
        monthly  = emptyList()
        weekly = emptyList()
        daily = emptyList()
        min30 = emptyList()
    }

}


class ScalpingAnalyzer {
    companion object {
        private const val SMA_SHORT = 10
        private const val SMA_LONG = 20
        private const val RSI_WINDOW = 14
        private const val VOL_WINDOW = 20
        private const val VOL_SURGE_THRESHOLD = 1.5
        private const val RSI_THRESHOLD = 50.0
        private const val BB_LOWER_POS = 0.2
        private const val BB_UPPER_POS = 0.8
        private const val ATR_WINDOW = 14
        private const val DEFAULT_SL_PCT = -0.5
        private const val DEFAULT_TP_PCT = 1.0
        private const val HIGH_SCORE_THRESHOLD = 80
    }

    fun computeRSI(closes: List<Double>, window: Int = RSI_WINDOW): List<Double> {
        val rsi = mutableListOf<Double>()
        if (closes.size < window + 1) return rsi
        for (i in window until closes.size) {
            val gains = mutableListOf<Double>()
            val losses = mutableListOf<Double>()
            for (j in (i - window + 1) until i + 1) {
                val delta = closes[j] - closes[j - 1]
                if (delta > 0) gains.add(delta) else losses.add(abs(delta))
            }
            val avgGain = gains.average()
            val avgLoss = losses.average()
            val rs = if (avgLoss > 0) avgGain / avgLoss else Double.POSITIVE_INFINITY
            rsi.add(100.0 - (100.0 / (1.0 + rs)))
        }
        return rsi
    }

    fun bollingerBands(closes: List<Double>, window: Int = SMA_LONG): Triple<List<Double>, List<Double>, List<Double>> {
        val sma = mutableListOf<Double>()
        val upper = mutableListOf<Double>()
        val lower = mutableListOf<Double>()
        for (i in window - 1 until closes.size) {
            val slice = closes.subList(i - window + 1, i + 1)
            val mean = slice.average()
            val std = sqrt(slice.map { (it - mean).pow(2.0) }.average()) * 2.0
            sma.add(mean)
            upper.add(mean + std)
            lower.add(mean - std)
        }
        return Triple(upper, sma, lower)
    }

    fun analyze(candles: List<Candle>): ScalpingSignalModel {
        if (candles.size < SMA_LONG) throw IllegalArgumentException("최소 20봉 필요")

        val closes = candles.map { it.close }
        val volumes = candles.map { it.volume }

        // 지표 계산
        val sma10 = simpleMovingAverage(closes, SMA_SHORT)
        val sma20 = simpleMovingAverage(closes, SMA_LONG)
        val rsiList = computeRSI(closes)
        val volAvg = simpleMovingAverage(volumes, VOL_WINDOW)
        val volRatioList = volumes.mapIndexed { i, v -> if (i >= VOL_WINDOW) v / volAvg[i - VOL_WINDOW] else 0.0 }
        val (bbUpper, bbMiddle, bbLower) = bollingerBands(closes)

        val current = candles.last()
        val idx = candles.size - 1
        val currentClose = current.close
        val sma10Now = if (sma10.size > 0) sma10.last() else 0.0
        val sma20Now = if (sma20.size > 0) sma20.last() else 0.0
        val rsiNow = if (rsiList.isNotEmpty()) rsiList.last() else 0.0
        val volRatioNow = volRatioList.last()
        val bbPos = if (bbUpper.isNotEmpty() && bbLower.isNotEmpty()) {
            (currentClose - bbLower.last()) / (bbUpper.last() - bbLower.last())
        } else 0.5

        // 신호 조건
        val maBull = currentClose > sma10Now && sma10Now > sma20Now
        val rsiBull = rsiNow > RSI_THRESHOLD
        val volSurge = volRatioNow > VOL_SURGE_THRESHOLD
        val bbGood = bbPos > BB_LOWER_POS && bbPos < BB_UPPER_POS
        val buySignal = maBull && rsiBull && volSurge && bbGood

        // 종합 스코어 (가중: MA 30%, RSI 20%, Vol 30%, BB 20%)
        val score = (if (maBull) 30 else 0) + (if (rsiBull) 20 else 0) +
                (minOf((volRatioNow - 1.0) * 30, 30.0)).toInt() + (if (bbGood) 20 else 0)

        // 위험도 (ATR proxy)
        val returns = closes.mapIndexed { i, c -> if (i > 0) (c - closes[i-1])/closes[i-1] * 100 else 0.0 }
        val atrProxy = if (returns.size >= ATR_WINDOW) {
            returns.subList(returns.size - ATR_WINDOW, returns.size).average()
        } else 1.0
        val riskLevel = when {
            abs(atrProxy) < 1 -> "Low"
            abs(atrProxy) < 2 -> "Medium"
            else -> "High"
        }

        // 성공 확률 & SL/TP
        val successProb = if (buySignal) 75.0 else 35.0 + (score / 100.0 * 20)
        val slPrice = currentClose * (1 + DEFAULT_SL_PCT / 100)
        val tpPrice = currentClose * (1 + DEFAULT_TP_PCT / 100)
        val rrRatio = abs(DEFAULT_TP_PCT / DEFAULT_SL_PCT)

        return ScalpingSignalModel(
            currentPrice = currentClose,
            buySignal = buySignal,
            compositeScore = minOf(score.toInt(), 100),
            successProbPct = successProb,
            riskLevel = riskLevel,
            rsi = rsiNow,
            volRatio = volRatioNow,
            suggestedSlPrice = slPrice,
            suggestedTpPrice = tpPrice,
            riskRewardRatio = rrRatio
        )
    }

    private fun simpleMovingAverage(values: List<Double>, window: Int): List<Double> {
        val sma = mutableListOf<Double>()
        for (i in window - 1 until values.size) {
            val slice = values.subList(i - window + 1, i + 1)
            sma.add(slice.average())
        }
        return sma
    }
}

data class Candle(
    val timestamp: Long,
    val open: Double,
    val high: Double,
    val low: Double,
    val close: Double,
    val volume: Double
)

data class ScalpingSignalModel(
    val currentPrice: Double,
    val buySignal: Boolean,
    val compositeScore: Int,  // 0-100: 종합 매수 추천도 (80+ 강매수)
    val successProbPct: Double,  // 성공 확률 추정 %
    val riskLevel: String,  // "Low", "Medium", "High"
    val rsi: Double,
    val volRatio: Double,
    val suggestedSlPrice: Double,  // 손절 가격
    val suggestedTpPrice: Double,  // 익절 가격
    val riskRewardRatio: Double
)

fun CandleData.toScalpingCandle(): Candle {
    // 1. 날짜(YYYYMMDD)와 시간(HHMMSS) 문자열 결합
    val dateTimeStr = "${this.stck_bsop_date}${this.stck_cntg_hour}"
    val formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss")

    // 2. 타임스탬프(Epoch Milliseconds) 계산
    val timestamp = try {
        val ldt = LocalDateTime.parse(dateTimeStr, formatter)
        ldt.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()
    } catch (e: Exception) {
        // 시간 파싱 실패 시 현재 시스템 시간 사용
        System.currentTimeMillis()
    }

    // 3. String 필드들을 Double로 변환하여 Candle 객체 생성
    return Candle(
        timestamp = timestamp,
        open = this.stck_oprc.toDoubleOrNull() ?: 0.0,
        high = this.stck_hgpr.toDoubleOrNull() ?: 0.0,
        low = this.stck_lwpr.toDoubleOrNull() ?: 0.0,
        close = this.stck_prpr.toDoubleOrNull() ?: 0.0, // stck_prpr가 종가 역할
        volume = this.cntg_vol.toDoubleOrNull() ?: 0.0
    )
}

/**
 * 리스트 전체를 변환하는 유틸리티
 */
fun List<CandleData>.toScalpingList(): List<Candle> {
    return this.map { it.toScalpingCandle() }
}
