package com.ga.api.service.withdraw;

import com.ga.common.adapter.bank.BankTransferAdapter;
import com.ga.common.adapter.bank.BankTransferRequest;
import com.ga.common.adapter.bank.BankTransferResponse;
import com.ga.common.adapter.bank.BankTransferStatus;
import com.ga.core.mapper.withdraw.WithdrawRequestMapper;
import com.ga.core.vo.withdraw.WithdrawRequestVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * 펌뱅킹 재시도 서비스 — transfer_status='FAILED' 이고 status='APPROVED' 인 출금을 어댑터로 재호출.
 * <p>
 * 운영: 매뉴얼 trigger(`POST /api/internal/bank-retry`) + cron 옵션(기본 비활성).
 * cron 활성화 시 yml 에 `app.bank-retry.cron=0 *&#47;10 * * * *` 형식으로 지정.
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class WithdrawBankRetryService {

    private static final int DEFAULT_BATCH_LIMIT = 50;

    private final WithdrawRequestMapper mapper;
    private final BankTransferAdapter bankTransferAdapter;

    @Value("${app.bank-retry.limit:50}")
    private int batchLimit;

    /** 재시도 1회 — 처리한 건수 반환. */
    @Transactional
    public int retryOnce() {
        int limit = batchLimit > 0 ? batchLimit : DEFAULT_BATCH_LIMIT;
        List<WithdrawRequestVO> failed = mapper.selectFailedTransfers(limit);
        if (failed.isEmpty()) return 0;

        log.info("[BANK-RETRY] 대상 {}건 재시도 시작", failed.size());
        int processed = 0;
        for (WithdrawRequestVO vo : failed) {
            try {
                BankTransferRequest req = BankTransferRequest.builder()
                        .withdrawRequestId(vo.getRequestId())
                        .bankCode(vo.getBankCode())
                        .accountNo(vo.getAccountNo())
                        .amount(vo.getAmount())
                        .memo("GA수수료 출금 #" + vo.getRequestId() + " (재시도)")
                        .build();
                BankTransferResponse resp = bankTransferAdapter.requestTransfer(req);

                boolean ok = resp != null && resp.getStatus() != BankTransferStatus.FAILED;
                String nextStatus = ok ? "SENT" : "APPROVED";
                String failReason = ok ? null : (resp != null ? resp.getResultMessage() : "no response");
                mapper.updateTransferResult(
                        vo.getRequestId(),
                        resp != null ? resp.getTxId() : null,
                        resp != null && resp.getStatus() != null ? resp.getStatus().name() : null,
                        nextStatus,
                        failReason
                );
                processed++;
            } catch (Exception e) {
                log.error("[BANK-RETRY] 재시도 중 어댑터 예외: requestId={}", vo.getRequestId(), e);
                mapper.updateTransferResult(
                        vo.getRequestId(), null, BankTransferStatus.FAILED.name(),
                        "APPROVED", e.getMessage()
                );
            }
        }
        log.info("[BANK-RETRY] 완료 — 처리 {}/{}건", processed, failed.size());
        return processed;
    }

    /**
     * cron 기반 자동 재시도.
     * yml 에 `app.bank-retry.cron` 미설정 시 매년 1월 1일 0시(=사실상 비활성)로 작동.
     */
    @Scheduled(cron = "${app.bank-retry.cron:0 0 0 1 1 ?}")
    public void scheduled() {
        try {
            retryOnce();
        } catch (Exception e) {
            log.error("[BANK-RETRY] 스케줄러 실패", e);
        }
    }
}
