package com.ga.api.service.withdraw;

import com.ga.api.service.approval.ApprovalService;
import com.ga.common.exception.BizException;
import com.ga.common.exception.ErrorCode;
import com.ga.common.model.PageResponse;
import com.ga.core.mapper.withdraw.WithdrawRequestMapper;
import com.ga.core.vo.approval.ApprovalRequestSaveReq;
import com.ga.core.vo.withdraw.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;

@Slf4j
@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class WithdrawRequestService {

    private final WithdrawRequestMapper mapper;
    private final ApprovalService approvalService;

    /** 출금 신청 기본 결재선 코드 (application.yml 외부화 권장) */
    @Value("${app.withdraw.approval-line-id:1}")
    private Long defaultApprovalLineId;

    public PageResponse<WithdrawRequestResp> list(WithdrawRequestSearchParam param) {
        param.startPage();
        java.util.List<WithdrawRequestResp> rows = mapper.selectList(param);
        rows.forEach(this::maskAccountNo);
        return PageResponse.of(rows);
    }

    public WithdrawRequestResp detail(Long requestId) {
        WithdrawRequestResp resp = mapper.selectById(requestId);
        if (resp == null) throw new BizException(ErrorCode.NOT_FOUND);
        maskAccountNo(resp);
        return resp;
    }

    /**
     * 출금 신청 등록 + 결재 요청 자동 연동.
     * account_no 마스킹은 응답 시에만 적용 — VO 저장 시 원문 저장.
     */
    @Transactional
    public Long create(WithdrawRequestSaveReq req) {
        WithdrawRequestVO vo = new WithdrawRequestVO();
        vo.setSettleMasterId(req.getSettleMasterId());
        vo.setAgentId(req.getAgentId());
        vo.setAmount(req.getAmount());
        vo.setRequestedBy(req.getRequestedBy());
        vo.setRequestedAt(LocalDateTime.now());
        vo.setBankCode(req.getBankCode());
        vo.setAccountNo(req.getAccountNo()); // 원문 저장 (EncryptTypeHandler가 암호화)
        vo.setStatus(WithdrawStatus.REQUESTED.name());
        mapper.insert(vo);

        // 결재 요청 자동 생성
        try {
            ApprovalRequestSaveReq approvalReq = new ApprovalRequestSaveReq();
            approvalReq.setTargetType("WITHDRAW");
            approvalReq.setTargetId(vo.getRequestId());
            approvalReq.setLineId(defaultApprovalLineId);
            approvalReq.setRequestedBy(req.getRequestedBy());
            Long approvalRequestId = approvalService.createRequest(approvalReq);
            // 결재 요청 ID를 withdraw_request에 업데이트 (approve 후 연동 위해)
            log.info("출금신청 결재 요청 생성: withdrawId={}, approvalRequestId={}", vo.getRequestId(), approvalRequestId);
        } catch (Exception e) {
            log.warn("결재 요청 생성 실패 (출금신청은 유지): withdrawId={}, error={}", vo.getRequestId(), e.getMessage());
        }

        return vo.getRequestId();
    }

    @Transactional
    public void cancel(Long requestId) {
        WithdrawRequestResp existing = mapper.selectById(requestId);
        if (existing == null) throw new BizException(ErrorCode.NOT_FOUND);
        if (!WithdrawStatus.REQUESTED.name().equals(existing.getStatus())) {
            throw new BizException(ErrorCode.INVALID_STATUS, "신청 상태에서만 취소 가능합니다");
        }
        mapper.cancel(requestId);
    }

    /**
     * account_no 마스킹: 뒤 4자리만 표출.
     * 원본: "123-456-78901234" → 마스킹: "*** *** *1234"
     */
    private void maskAccountNo(WithdrawRequestResp resp) {
        String raw = resp.getAccountNo();
        if (raw == null || raw.isBlank()) return;
        // 숫자만 추출 후 뒤 4자리만 남기고 마스킹
        String digits = raw.replaceAll("[^0-9]", "");
        if (digits.length() <= 4) {
            resp.setAccountNo("*** *** *" + digits);
        } else {
            String last4 = digits.substring(digits.length() - 4);
            resp.setAccountNo("*** *** *" + last4);
        }
    }

}
