package kr.or.bok.rtgs.common.ops

import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Value
import org.springframework.boot.autoconfigure.AutoConfiguration
import org.springframework.boot.autoconfigure.AutoConfigureAfter
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate
import org.springframework.context.annotation.Bean
import org.springframework.jdbc.core.JdbcTemplate
import org.springframework.scheduling.annotation.EnableScheduling
import org.springframework.scheduling.annotation.Scheduled
import javax.sql.DataSource

/**
 * B5 서비스 하트비트 — 모든 서비스(공통 자동설정)가 주기적으로 `service_heartbeat`에 생존 신호를 남긴다.
 * 헤드리스(Sequencer/Dior/Hermes/Prada) 포함 전 서비스의 liveness를 **DB로** 확인(LouisVuitton 대시보드).
 * DataSource가 있는 서비스에만 활성화. 스키마(service_heartbeat)는 Flyway가 보장.
 */
@AutoConfiguration
@AutoConfigureAfter(name = ["org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration"])
@ConditionalOnSingleCandidate(DataSource::class)
@EnableScheduling
open class HeartbeatAutoConfiguration {
    @Bean
    open fun heartbeatWriter(
        dataSource: DataSource,
        @Value("\${spring.application.name:rtgs}") service: String,
        @Value("\${rtgs.center-id:DC1}") center: String,
    ): HeartbeatWriter = HeartbeatWriter(JdbcTemplate(dataSource), service, center)
}

class HeartbeatWriter(
    private val jdbc: JdbcTemplate,
    private val service: String,
    private val center: String,
) {
    private val log = LoggerFactory.getLogger(javaClass)
    private val pid = ProcessHandle.current().pid()

    @Scheduled(fixedDelayString = "\${rtgs.heartbeat-ms:5000}")
    fun beat() {
        try {
            jdbc.update(
                """
                INSERT INTO service_heartbeat(service, center, last_seen, pid)
                VALUES (?, ?, ?, ?)
                ON CONFLICT (service, center) DO UPDATE SET last_seen = EXCLUDED.last_seen, pid = EXCLUDED.pid
                """.trimIndent(),
                service, center, System.currentTimeMillis(), pid,
            )
        } catch (e: Exception) {
            // 기동 초기 테이블 미생성 등 일시 오류는 다음 주기에 자동 회복(노이즈 최소화).
            log.debug("heartbeat skip: {}", e.message)
        }
    }
}
