import AutoTradeTable.orderNo
import kotlinx.serialization.Serializable
import model.AppConfig
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
import org.jetbrains.exposed.sql.javatime.datetime
import org.jetbrains.exposed.sql.transactions.transaction
import java.io.File
import java.time.LocalDateTime


object TradeStatus {
    const val PENDING_BUY = "PENDING_BUY"   // 매수 주문 중
    const val MONITORING = "MONITORING"     // 매수 체결 후 감시 중
    const val SELLING = "SELLING"           // 손절/익절 매도 주문 중
    const val EXPIRED = "EXPIRED"           // 서버와 불일치 (유저 판단 대기)
    const val COMPLETED = "COMPLETED"       // 거래 종료
}

// 1. 앱 설정 테이블
object ConfigTable : Table("app_config") {
    val id = integer("id").autoIncrement()
    val realAppKey = varchar("real_app_key", 255).default("")
    val realSecretKey = varchar("real_secret_key", 255).default("")
    val realAccountNo = varchar("real_account_no", 20).default("")
    val vtsAppKey = varchar("vts_app_key", 255).default("")
    val vtsSecretKey = varchar("vts_secret_key", 255).default("")
    val vtsAccountNo = varchar("vts_account_no", 20).default("")
    val isSimulation = bool("is_simulation").default(true)
    val modelPath = varchar("model_path", 512).default("")
    val embedModelPath = varchar("embed_model_path", 512).default("")
    val htsId = varchar("hts_id", 50).default("") // HTS ID 컬럼 추가
    override val primaryKey = PrimaryKey(id)
}

// 2. 자동매매 감시 테이블
object AutoTradeTable : Table("auto_trades") {
    val id = integer("id").autoIncrement()
    val stockCode = varchar("stock_code", 20)
    val stockName = varchar("stock_name", 100)
    val quantity = integer("quantity").default(0)
    val profitRate = double("profit_rate").default(0.0)
    val stopLossRate = double("stop_loss_rate").default(0.0)
    val targetPrice = double("target_price").default(0.0)
    val stopLossPrice = double("stop_loss_price").default(0.0)
    val orderNo = varchar("order_no", 50).uniqueIndex()
    val status = varchar("status", 20).default("PENDING_BUY")
    val isDomestic = bool("is_domestic").default(true)
    override val primaryKey = PrimaryKey(id)
}


// 3. 거래 내역 테이블
object TradeLogTable : Table("trade_logs") {
    val id = long("id").autoIncrement()
    val stockCode = varchar("stock_code", 20)
    val stockName = varchar("stock_name", 50)
    val tradeType = varchar("trade_type", 10)
    val price = double("price")
    val quantity = integer("quantity")
    val timestamp = datetime("timestamp")
    val logMessage = text("log_message")
    override val primaryKey = PrimaryKey(id)
}

object DatabaseFactory {
    fun init() {
        val dbPath = File("db/autotrade_db").absolutePath
        Database.connect(
            "jdbc:h2:$dbPath;DB_CLOSE_DELAY=-1;",
            driver = "org.h2.Driver"
        )

        transaction {

            // 테이블 생성 (AutoTradeTable 포함)
            SchemaUtils.createMissingTablesAndColumns(ConfigTable, TradeLogTable, AutoTradeTable)
        }
    }


    /**
     * 새로운 자동매매 건 등록 (주로 PENDING_BUY 상태로 시작)
     */
    fun saveAutoTrade(item: AutoTradeItem) = transaction {
        AutoTradeTable.insert {
            it[stockCode] = item.code
            it[stockName] = item.name
            it[quantity] = item.quantity
            it[profitRate] = item.profitRate
            it[stopLossRate] = item.stopLossRate
            it[targetPrice] = item.targetPrice
            it[stopLossPrice] = item.stopLossPrice
            it[orderNo] = item.orderNo
            it[status] = item.status
            it[isDomestic] = item.isDomestic
        }
    }

    /**
     * 상태 변경 및 가격 업데이트 (예: PENDING_BUY -> MONITORING)
     */
    fun updateAutoTrade(item: AutoTradeItem) = transaction {
        val id = item.id ?: return@transaction
        AutoTradeTable.update({ AutoTradeTable.id eq id }) {
            it[targetPrice] = item.targetPrice
            it[stopLossPrice] = item.stopLossPrice
            it[orderNo] = item.orderNo
            it[status] = item.status
        }
    }

    /**
     * 감시 중인 모든 종목 리스트 반환 (ActiveTradeSection UI용)
     */
    fun getActiveAutoTrades(): List<AutoTradeItem> = transaction {
        AutoTradeTable.select {
            AutoTradeTable.status inList listOf("MONITORING", "SELLING", "PENDING_BUY")
        }.map { mapToAutoTradeItem(it) }
    }

    /**
     * 종목코드로 현재 감시 중인 설정이 있는지 확인 (UI 체크박스 상태용)
     */
    fun findConfigByCode(code: String): AutoTradeItem? = transaction {
        AutoTradeTable.select {
            (AutoTradeTable.stockCode eq code) and (AutoTradeTable.status eq "MONITORING")
        }.lastOrNull()?.let { mapToAutoTradeItem(it) }
    }

    fun deleteAutoTrade(id: Int) = transaction {
        AutoTradeTable.deleteWhere { AutoTradeTable.id eq id }
    }

    private fun mapToAutoTradeItem(it: ResultRow) = AutoTradeItem(
        id = it[AutoTradeTable.id],
        code = it[AutoTradeTable.stockCode],
        name = it[AutoTradeTable.stockName],
        quantity = it[AutoTradeTable.quantity],
        profitRate = it[AutoTradeTable.profitRate],
        stopLossRate = it[AutoTradeTable.stopLossRate],
        targetPrice = it[AutoTradeTable.targetPrice],
        stopLossPrice = it[AutoTradeTable.stopLossPrice],
        orderNo = it[AutoTradeTable.orderNo],
        status = it[AutoTradeTable.status],
        isDomestic = it[AutoTradeTable.isDomestic]
    )

    // --- 기존 설정 및 로그 관련 함수 ---

    fun saveTradeLog(code: String, name: String, type: String, price: Double, qty: Int, msg: String) {
        transaction {
            TradeLogTable.insert {
                it[stockCode] = code
                it[stockName] = name
                it[tradeType] = type
                it[TradeLogTable.price] = price
                it[quantity] = qty
                it[timestamp] = LocalDateTime.now()
                it[logMessage] = msg
            }
        }
    }

    fun findConfigByAccount(accountNo: String): AppConfig? = transaction {
        ConfigTable.select {
            (ConfigTable.realAccountNo eq accountNo) or (ConfigTable.vtsAccountNo eq accountNo)
        }.lastOrNull()?.let {
            AppConfig(
                realAppKey = it[ConfigTable.realAppKey],
                realSecretKey = it[ConfigTable.realSecretKey],
                realAccountNo = it[ConfigTable.realAccountNo],
                vtsAppKey = it[ConfigTable.vtsAppKey],
                vtsSecretKey = it[ConfigTable.vtsSecretKey],
                vtsAccountNo = it[ConfigTable.vtsAccountNo],
                isSimulation = it[ConfigTable.isSimulation],
                htsId = it[ConfigTable.htsId], // htsId 로드
                modelPath = it[ConfigTable.modelPath],
                embedModelPath = it[ConfigTable.embedModelPath],
            )
        }
    }

    fun saveConfig(config: AppConfig) {
        transaction {
            ConfigTable.deleteAll()
            ConfigTable.insert {
                it[realAppKey] = config.realAppKey
                it[realSecretKey] = config.realSecretKey
                it[vtsAppKey] = config.vtsAppKey
                it[vtsSecretKey] = config.vtsSecretKey
                it[realAccountNo] = config.realAccountNo
                it[vtsAccountNo] = config.vtsAccountNo
                it[isSimulation] = config.isSimulation
                it[htsId] = config.htsId
                it[modelPath] = config.modelPath
                it[embedModelPath] = config.embedModelPath
            }
        }
    }

    fun saveOrUpdate(item: AutoTradeItem) = transaction {
        val existing = AutoTradeTable.select { AutoTradeTable.orderNo eq item.orderNo }.firstOrNull()
        if (existing == null) {
            AutoTradeTable.insert {
                it[orderNo] = item.orderNo
                it[stockCode] = item.code
                it[stockName] = item.name
                it[status] = item.status
                it[targetPrice] = item.targetPrice
                it[stopLossPrice] = item.stopLossPrice
                it[quantity] = item.quantity
                it[isDomestic] = item.isDomestic
            }
        } else {
            AutoTradeTable.update({ AutoTradeTable.orderNo eq item.orderNo }) {
                it[status] = item.status
                it[targetPrice] = item.targetPrice
                it[stopLossPrice] = item.stopLossPrice
            }
        }
    }

    /**
     * 주문번호로 항목 조회 (가장 핵심적인 식별자)
     */
    fun findByOrderNo(orderNo: String): AutoTradeItem? = transaction {
        AutoTradeTable.select { AutoTradeTable.orderNo eq orderNo }
            .map { mapToAutoTradeItem(it) }
            .singleOrNull()
    }

    /**
     * 서버 동기화: DB에는 PENDING_BUY/MONITORING인데 서버 미체결 내역에 없는 경우 EXPIRED로 변경
     */
    fun syncWithServer(serverOrderNos: List<String>) = transaction {
        AutoTradeTable.update({
            (AutoTradeTable.status inList listOf(TradeStatus.PENDING_BUY, TradeStatus.MONITORING)) and
                    (AutoTradeTable.orderNo notInList serverOrderNos)
        }) {
            it[status] = TradeStatus.EXPIRED
        }
    }

    /**
     * 상태 업데이트 및 주문번호 갱신 (예: 매수체결 시 신규 익절 주문번호로 교체)
     */
    fun updateStatusAndOrderNo(id: Int, newStatus: String, newOrderNo: String? = null) = transaction {
        AutoTradeTable.update({ AutoTradeTable.id eq id }) {
            it[status] = newStatus
            if (newOrderNo != null) it[orderNo] = newOrderNo
        }
    }

    /**
     * 감시 중인 모든 종목 리스트 (Status별 필터링 용이하게 수정)
     */
    fun getAutoTradesByStatus(statusList: List<String>): List<AutoTradeItem> = transaction {
        AutoTradeTable.select { AutoTradeTable.status inList statusList }
            .map { mapToAutoTradeItem(it) }
    }

}

@Serializable
data class AutoTradeItem(
    val id: Int? = null,              // DB 식별자
    val orderNo: String,              // 핵심 키: KIS 주문번호 (odno)
    val code: String,                 // 종목 코드
    val name: String,                 // 종목 명

    // 상태 머신 (PENDING_BUY, MONITORING, SELLING, EXPIRED, COMPLETED)
    var status: String = "PENDING_BUY",

    // 가격 정보
    val orderedPrice: Double = 0.0,   // 주문 단가
    var targetPrice: Double = 0.0,    // 익절 목표가
    var stopLossPrice: Double = 0.0,  // 손절 목표가

    // 수량 정보
    val quantity: Int = 0,            // 총 주문 수량
    var remainedQuantity: Int = 0,    // 미체결 잔량 (서버 동기화용)

    val isDomestic: Boolean = true,
    val profitRate: Double = 0.0,     // 설정 시 사용한 목표 비율
    val stopLossRate: Double = 0.0
)