package network

import io.ktor.client.*
import io.ktor.client.call.*
import io.ktor.client.engine.cio.CIO
import io.ktor.client.plugins.contentnegotiation.*
import io.ktor.client.plugins.logging.DEFAULT
import io.ktor.client.plugins.logging.LogLevel
import io.ktor.client.plugins.logging.Logger
import io.ktor.client.plugins.logging.Logging
import io.ktor.client.request.*
import io.ktor.http.*
import io.ktor.serialization.kotlinx.json.*
import kotlinx.serialization.json.Json
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import model.KisSession
import model.TokenRequest
import model.TokenResponse
import java.time.LocalDateTime

class KisAuthService {
    private val client = HttpClient(CIO) {
        install(ContentNegotiation) {
            json(Json {
                ignoreUnknownKeys = true
                encodeDefaults = true // 기본값이 포함된 요청 바디를 정확히 전송하기 위해 필요
            })
        }
        // [수정] 모든 로그(Headers + Body)를 찍도록 설정
        install(Logging) {
            logger = Logger.DEFAULT
            level = LogLevel.NONE // 상세한 디버깅을 위해 ALL로 변경
        }
    }

    private fun getBaseUrl(isSimulation: Boolean) =
        if (isSimulation) "https://openapivts.koreainvestment.com:29443"
        else "https://openapi.koreainvestment.com:9443"

    /**
     * 실전(시세용)과 매매(모의/실전 선택) 토큰을 모두 갱신합니다.
     */
    suspend fun refreshAllTokens(): Boolean = coroutineScope {
        val config = KisSession.config

        // 1. 실전 시세용 토큰 발급 (Market Token)
        val marketTokenJob = async { fetchAccessToken(config.realAppKey, config.realSecretKey, false) }

        // 2. 매매용 토큰 발급 (Trade Token - 설정에 따라 VTS 또는 Real 사용)
        val tradeTokenJob = async {
            if (config.isSimulation) fetchAccessToken(config.vtsAppKey, config.vtsSecretKey, true)
            else marketTokenJob.await() // 실전 매매면 시세용 토큰과 동일함
        }

        val mResult = marketTokenJob.await()
        val tResult = tradeTokenJob.await()

        if (mResult.isSuccess && tResult.isSuccess) {
            val mData = mResult.getOrThrow()
            val tData = tResult.getOrThrow()

            // KisSession 업데이트
            KisSession.config = KisSession.config.copy(
                marketToken = mData.access_token,
                marketTokenExpiredAt = LocalDateTime.now().plusSeconds(mData.expires_in),
                tradeToken = tData.access_token,
                tradeTokenExpiredAt = LocalDateTime.now().plusSeconds(tData.expires_in),
            )
            true
        } else {
            false
        }
    }

    private suspend fun fetchAccessToken(appKey: String, secretKey: String, isSim: Boolean): Result<TokenResponse> {
        return try {
            val response = client.post("${getBaseUrl(isSim)}/oauth2/tokenP") {
                contentType(ContentType.Application.Json)
                setBody(TokenRequest("client_credentials", appKey, secretKey))
            }
            if (response.status == HttpStatusCode.OK) Result.success(response.body())
            else Result.failure(Exception("인증 실패: ${response.status}"))
        } catch (e: Exception) {
            Result.failure(e)
        }
    }
}