package kr.or.bok.rtgs.hermes

import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import kr.or.bok.rtgs.common.ledger.Account
import kr.or.bok.rtgs.common.ledger.JournalLog
import kr.or.bok.rtgs.common.ledger.TransferRecord
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.autoconfigure.domain.EntityScan
import org.springframework.boot.runApplication
import org.springframework.context.annotation.Bean
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.data.jpa.repository.Modifying
import org.springframework.data.jpa.repository.Query
import org.springframework.data.jpa.repository.config.EnableJpaRepositories
import org.springframework.data.repository.query.Param
import org.springframework.scheduling.annotation.EnableScheduling

@SpringBootApplication
@EntityScan("kr.or.bok.rtgs.common.ledger")
@EnableJpaRepositories(considerNestedRepositories = true)
@EnableScheduling  // B3 gap 타임아웃 스케줄러
class HermesApplication {
    @Bean
    fun objectMapper(): ObjectMapper = jacksonObjectMapper()
}

interface AccountRepository : JpaRepository<Account, String>
interface JournalLogRepository : JpaRepository<JournalLog, Long>

interface TransferRepository : JpaRepository<TransferRecord, String> {
    /**
     * 거래 원장 원자적 upsert. 신규면 INSERT, 이미 있으면(Dior/타 소비자가 먼저 생성) UPDATE.
     * created_at은 최초 값 유지(갱신 제외). acsp_at(정산시각)은 Hermes가 기록하고, pdng_at은 SET에서
     * 제외해 Dior가 기록한 값을 보존한다. Dior-Hermes 동시 삽입 경합에서 중복키 예외 제거.
     */
    @Modifying
    @Query(
        value = """
            INSERT INTO transfer
              (bmi, global_seq, status, sender_code, receiver_code, amount, origin_center, created_at, updated_at, reason, acsp_at)
            VALUES
              (:bmi, :seq, :status, :sender, :receiver, :amount, :origin, :createdAt, :updatedAt, :reason, :acspAt)
            ON CONFLICT (bmi) DO UPDATE SET
              global_seq    = EXCLUDED.global_seq,
              status        = EXCLUDED.status,
              sender_code   = EXCLUDED.sender_code,
              receiver_code = EXCLUDED.receiver_code,
              amount        = EXCLUDED.amount,
              origin_center = EXCLUDED.origin_center,
              updated_at    = EXCLUDED.updated_at,
              reason        = EXCLUDED.reason,
              acsp_at       = EXCLUDED.acsp_at
        """,
        nativeQuery = true,
    )
    fun upsertTransfer(
        @Param("bmi") bmi: String,
        @Param("seq") seq: Long,
        @Param("status") status: String,
        @Param("sender") sender: String,
        @Param("receiver") receiver: String,
        @Param("amount") amount: Long,
        @Param("origin") origin: String,
        @Param("createdAt") createdAt: Long,
        @Param("updatedAt") updatedAt: Long,
        @Param("reason") reason: String?,
        @Param("acspAt") acspAt: Long,
    ): Int
}

fun main(args: Array<String>) {
    runApplication<HermesApplication>(*args)
}
