package com.ga.api.service.settle;

import com.ga.common.annotation.ExcelColumn;
import com.ga.common.excel.ExcelService;
import com.ga.common.model.PageResponse;
import com.ga.core.mapper.settle.ChargebackMapper;
import com.ga.core.vo.settle.ChargebackResp;
import com.ga.core.vo.settle.ChargebackSearchParam;
import jakarta.servlet.http.HttpServletResponse;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import org.apache.ibatis.cursor.Cursor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Iterator;
import java.util.List;

@Service
@RequiredArgsConstructor
public class ChargebackService {

    private final ChargebackMapper chargebackMapper;
    private final ExcelService excelService;

    @Transactional(readOnly = true)
    public PageResponse<ChargebackResp> list(ChargebackSearchParam param) {
        param.startPage();
        return PageResponse.of(chargebackMapper.selectList(param));
    }

    /**
     * 환수 목록 엑셀 다운로드.
     *
     * ga-core ChargebackMapper에 selectCursorForExcel 미존재(ga-core 수정 불가)로
     * selectList 전체 조회 후 List-backed Cursor로 exportLargeExcel 위임.
     * 대용량 환경에서는 ga-core에 selectCursorForExcel 추가 권장 (TODO).
     */
    @Transactional(readOnly = true)
    public void export(ChargebackSearchParam param, HttpServletResponse response) {
        List<ChargebackResp> rows = chargebackMapper.selectList(param);
        List<ChargebackExcelRow> excelRows = rows.stream().map(ChargebackExcelRow::from).toList();
        excelService.exportLargeExcel(
                "환수자료목록",
                ChargebackExcelRow.class,
                () -> new ListCursor<>(excelRows),
                response
        );
    }

    // ── 엑셀 출력용 VO (ga-core 수정 불가로 api 모듈 내 정의) ────────────
    @Data
    public static class ChargebackExcelRow {

        @ExcelColumn(header = "정산월",     order = 1, width = 10)
        private String settleMonth;

        @ExcelColumn(header = "증권번호",   order = 2, width = 16)
        private String policyNo;

        @ExcelColumn(header = "계약자명",   order = 3, width = 14)
        private String contractorName;

        @ExcelColumn(header = "설계사명",   order = 4, width = 12)
        private String agentName;

        @ExcelColumn(header = "경과월",     order = 5, width = 8)
        private Integer lapseMonth;

        @ExcelColumn(header = "환수율",     order = 6, width = 8)
        private BigDecimal cbRate;

        @ExcelColumn(header = "환수금액",   order = 7, width = 14)
        private BigDecimal cbAmount;

        @ExcelColumn(header = "지급금액",   order = 8, width = 14)
        private BigDecimal paidAmount;

        @ExcelColumn(header = "잔여금액",   order = 9, width = 14)
        private BigDecimal remainAmount;

        @ExcelColumn(header = "상태",       order = 10, width = 10)
        private String status;

        @ExcelColumn(header = "생성일시",   order = 11, width = 18, format = "yyyy-MM-dd HH:mm:ss")
        private LocalDateTime createdAt;

        static ChargebackExcelRow from(ChargebackResp r) {
            ChargebackExcelRow row = new ChargebackExcelRow();
            row.setSettleMonth(r.getSettleMonth());
            row.setPolicyNo(r.getPolicyNo());
            row.setContractorName(r.getContractorName());
            row.setAgentName(r.getAgentName());
            row.setLapseMonth(r.getLapseMonth());
            row.setCbRate(r.getCbRate());
            row.setCbAmount(r.getCbAmount());
            row.setPaidAmount(r.getPaidAmount());
            row.setRemainAmount(r.getRemainAmount());
            row.setStatus(r.getStatus());
            row.setCreatedAt(r.getCreatedAt());
            return row;
        }
    }

    /** List를 MyBatis Cursor 인터페이스로 감싸는 어댑터. */
    private static class ListCursor<T> implements Cursor<T> {
        private final List<T> list;
        ListCursor(List<T> list) { this.list = list; }

        @Override public boolean isOpen()      { return true;  }
        @Override public boolean isConsumed()  { return false; }
        @Override public int getCurrentIndex() { return -1;    }
        @Override public Iterator<T> iterator() { return list.iterator(); }
        @Override public void close()           { /* no-op */  }
    }
}
