package com.ga.batch.settlement.step;

import com.ga.batch.settlement.SettlementContext;
import com.ga.core.mapper.accounting.ContractAccountingEntryMapper;
import com.ga.core.vo.accounting.ContractAccountingEntryVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.configuration.annotation.JobScope;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.stereotype.Component;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;

/**
 * Step 8b — accountingEntryGenerate: 회계 자동분개
 *
 * 정산월 기준 recruit_ledger + maintain_ledger → contract_accounting_entry INSERT.
 * - 차변(8350 지급수수료) / 대변(2530 미지급금) 한 쌍을 단일 행으로 저장.
 * - journal_no는 NULL(미전기). 마감 UI에서 채번.
 * - 멱등성: 재실행 시 해당 정산월의 미전기 분개를 먼저 삭제 후 재생성(마감 채번분은 보존).
 */
@Slf4j
@Component
@JobScope
@RequiredArgsConstructor
public class AccountingEntryGenerateStep implements Tasklet {

    private final SettlementContext ctx;
    private final ContractAccountingEntryMapper accountingMapper;

    private static final int BATCH_SIZE = 500;

    @Override
    public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) {
        String settleMonth = ctx.getSettleMonth();
        log.info("[AccountingEntry] settleMonth={}", settleMonth);

        // 멱등성: 이번 정산월의 미전기 분개 제거 후 재생성 (마감 채번된 분개는 보존)
        int deleted = accountingMapper.deleteUnpostedBySettleMonth(settleMonth);
        if (deleted > 0) {
            log.info("[AccountingEntry] deleted {} unposted entries before regenerate", deleted);
        }

        List<ContractAccountingEntryVO> source = accountingMapper.selectBySettleMonth(settleMonth);
        if (source.isEmpty()) {
            log.info("[AccountingEntry] no ledger records for month={}", settleMonth);
            return RepeatStatus.FINISHED;
        }

        LocalDate today = LocalDate.now();
        List<ContractAccountingEntryVO> batch = new ArrayList<>(BATCH_SIZE);
        int total = 0;

        for (ContractAccountingEntryVO entry : source) {
            if (entry.getAmount() == null || entry.getAmount().signum() == 0) continue;
            entry.setEntryDate(today);
            entry.setJournalNo(null);

            batch.add(entry);
            if (batch.size() >= BATCH_SIZE) {
                accountingMapper.insertBatch(batch);
                total += batch.size();
                batch.clear();
            }
        }
        if (!batch.isEmpty()) {
            accountingMapper.insertBatch(batch);
            total += batch.size();
        }

        log.info("[AccountingEntry] inserted {} entries for month={}", total, settleMonth);
        return RepeatStatus.FINISHED;
    }
}
