package com.kingdee.eas.custom.integration.riskcontrol.service.impl;

import com.kingdee.bos.BOSException;
import com.kingdee.bos.Context;
import com.kingdee.bos.dao.IObjectPK;
import com.kingdee.bos.dao.ormapping.ObjectUuidPK;
import com.kingdee.bos.util.BOSUuid;
import com.kingdee.eas.basedata.person.IPerson;
import com.kingdee.eas.basedata.person.PersonFactory;
import com.kingdee.eas.basedata.person.PersonInfo;
import com.kingdee.eas.common.EASBizException;
import com.kingdee.eas.custom.integration.base.util.SHRApiUtils;
import com.kingdee.eas.custom.integration.beisen.dto.FailDetail;
import com.kingdee.eas.custom.integration.riskcontrol.dto.BatchComplaintDonationDeductRequest;
import com.kingdee.eas.custom.integration.riskcontrol.dto.ComplaintDonationDeductRequest;
import com.kingdee.eas.custom.integration.riskcontrol.dto.ComplaintDonationDeductResponse;
import com.kingdee.eas.custom.integration.riskcontrol.service.ComplaintDonationDeductService;
import com.kingdee.eas.custom.integration.riskcontrol.validator.ComplaintDonationDeductValidator;
import com.kingdee.eas.hr.base.ApproveTypeEnum;
import com.kingdee.eas.hr.base.HRBillStateEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 投诉乐捐扣除数据同步服务实现
 */
@Service
public class ComplaintDonationDeductServiceImpl implements ComplaintDonationDeductService {

    private static final Logger logger = LoggerFactory.getLogger(ComplaintDonationDeductServiceImpl.class);

    /** 提报方案名称 */
    private static final String DECLARE_SCHEME_NAME = "投诉乐捐扣除数据";

    // ==================== LookupResult ====================

    private static class LookupResult<T> {
        final T data;
        final String error;

        private LookupResult(T data, String error) {
            this.data = data;
            this.error = error;
        }

        static <T> LookupResult<T> ok(T data) {
            return new LookupResult<>(data, null);
        }

        static <T> LookupResult<T> fail(String error) {
            return new LookupResult<>(null, error);
        }
    }

    // ==================== 主方法 ====================

    @Override
    public ComplaintDonationDeductResponse writeComplaintDonationDeduct(BatchComplaintDonationDeductRequest request) {
        logger.info("开始批量同步投诉乐捐扣除数据 - 记录数: {}",
                request.getRecords() != null ? request.getRecords().size() : 0);

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        ComplaintDonationDeductResponse response = new ComplaintDonationDeductResponse();
        List<ComplaintDonationDeductRequest> records = request.getRecords();

        if (records == null || records.isEmpty()) {
            logger.warn("投诉乐捐扣除数据同步 - 记录列表为空");
            return response;
        }

        try {
            Context ctx = SHRApiUtils.getContext();
            IPerson iPerson = PersonFactory.getLocalInstance(ctx);

            // 缓存
            Map<String, Object> schemeCache = new HashMap<>();
            Map<String, Object> violationTypeCache = new HashMap<>();

            int totalCount = records.size();
            AtomicInteger successCount = new AtomicInteger(0);
            AtomicInteger failCount = new AtomicInteger(0);

            for (ComplaintDonationDeductRequest record : records) {
                try {
                    String identifier = buildFailIdentifier(record);
                    String dateStr = record.getVoucherDate();

                    // 1. 校验
                    String validateError = ComplaintDonationDeductValidator.validateAndGetError(record);
                    if (validateError != null) {
                        recordFail(response, failCount, identifier, "校验失败: " + validateError);
                        logger.warn("投诉乐捐扣除数据校验失败 - 标识: {}, 原因: {}", identifier, validateError);
                        continue;
                    }

                    Date voucherDate = sdf.parse(dateStr);

                    // 2. 查人员
                    LookupResult<PersonInfo> personR = lookupPerson(iPerson, record.getPersonNumber());
                    if (personR.error != null) {
                        recordFail(response, failCount, identifier, personR.error);
                        logger.warn("投诉乐捐扣除数据同步失败 - 工号: {}, 日期: {}, 原因: {}",
                                record.getPersonNumber(), dateStr, personR.error);
                        continue;
                    }

                    // 3. 查违规类型
                    LookupResult<Object> violationTypeR = lookupViolationType(ctx,
                            record.getViolationTypeCode(), violationTypeCache);
                    if (violationTypeR.error != null) {
                        recordFail(response, failCount, identifier, violationTypeR.error);
                        logger.warn("投诉乐捐扣除数据同步失败 - 工号: {}, 日期: {}, 原因: {}",
                                record.getPersonNumber(), dateStr, violationTypeR.error);
                        continue;
                    }

                    // 4. 查提报方案
                    LookupResult<Object> schemeR = lookupDeclareScheme(ctx,
                            DECLARE_SCHEME_NAME, schemeCache);
                    if (schemeR.error != null) {
                        recordFail(response, failCount, identifier, schemeR.error);
                        logger.warn("投诉乐捐扣除数据同步失败 - 工号: {}, 日期: {}, 原因: {}",
                                record.getPersonNumber(), dateStr, schemeR.error);
                        continue;
                    }

                    // 5. 创建提报单
                    String billId = createDeclareBill(ctx, personR.data, violationTypeR.data,
                            schemeR.data, record, voucherDate);
                    if (billId == null) {
                        recordFail(response, failCount, identifier, "创建提报单失败");
                        logger.warn("投诉乐捐扣除数据同步失败 - 工号: {}, 日期: {}, 原因: 创建提报单返回空ID",
                                record.getPersonNumber(), dateStr);
                        continue;
                    }

                    // 6. 自动审批
                    auditDeclareBill(ctx, billId);

                    response.addCreatedBillId(billId);
                    successCount.incrementAndGet();
                    logger.debug("投诉乐捐扣除数据同步成功 - 工号: {}, 日期: {}, 提报单ID: {}",
                            record.getPersonNumber(), dateStr, billId);

                } catch (Exception e) {
                    failCount.incrementAndGet();
                    String identifier = buildFailIdentifier(record);
                    String reason = e.getMessage() != null ? e.getMessage() : "未知错误";
                    response.addFailDetail(new FailDetail(identifier, reason));
                    logger.warn("投诉乐捐扣除数据同步失败 - 工号: {}, 日期: {}, 原因: {}",
                            record.getPersonNumber(), record.getVoucherDate(), reason);
                }
            }

            response.setTotalCount(totalCount);
            response.setSuccessCount(successCount.get());
            response.setFailCount(failCount.get());

            logger.info("投诉乐捐扣除数据同步完成 - 总条数: {}, 成功: {}, 失败: {}, 提报单数: {}",
                    totalCount, successCount.get(), failCount.get(), response.getCreatedBillIds().size());

        } catch (BOSException e) {
            throw new RuntimeException(e);
        }
        return response;
    }

    // ==================== 失败处理 ====================

    private void recordFail(ComplaintDonationDeductResponse response, AtomicInteger failCount,
                            String identifier, String reason) {
        failCount.incrementAndGet();
        response.addFailDetail(new FailDetail(identifier, reason));
    }

    // ==================== 查找方法 ====================

    private LookupResult<PersonInfo> lookupPerson(IPerson iPerson, String personNumber) throws BOSException, EASBizException {
        PersonInfo info = iPerson.getPersonByStr("number", personNumber);
        if (info == null) {
            return LookupResult.fail("sHR系统中不存在工号为" + personNumber + "的人员");
        }
        return LookupResult.ok(info);
    }

    /**
     * 查找违规类型（带缓存）。
     * TODO: 替换为实际的 BOS 实体和 Factory 调用。
     */
    private LookupResult<Object> lookupViolationType(Context ctx, String violationTypeCode,
                                                     Map<String, Object> cache) throws BOSException {
        if (cache.containsKey(violationTypeCode)) {
            return LookupResult.ok(cache.get(violationTypeCode));
        }
        // TODO: 替换为实际实体查询
        // ViolationTypeCollection col = ViolationTypeFactory.getLocalInstance(ctx)
        //         .getViolationTypeCollection("where number = '" + escapeSql(violationTypeCode) + "'");
        // if (col != null && !col.isEmpty()) {
        //     Object info = col.get(0);
        //     cache.put(violationTypeCode, info);
        //     return LookupResult.ok(info);
        // }
        return LookupResult.fail("sHR系统中不存在编码为" + violationTypeCode + "的违规类型");
    }

    /**
     * 查找提报方案（带缓存）。
     * TODO: 替换为实际的 BOS 实体和 Factory 调用。
     */
    private LookupResult<Object> lookupDeclareScheme(Context ctx, String schemeName,
                                                     Map<String, Object> cache) throws BOSException {
        if (cache.containsKey(schemeName)) {
            return LookupResult.ok(cache.get(schemeName));
        }
        // TODO: 替换为实际实体查询
        // HrDeclareSchemeCollection col = HrDeclareSchemeFactory.getLocalInstance(ctx)
        //         .getHrDeclareSchemeCollection("where name = '" + escapeSql(schemeName) + "'");
        // if (col != null && !col.isEmpty()) {
        //     Object info = col.get(0);
        //     cache.put(schemeName, info);
        //     return LookupResult.ok(info);
        // }
        return LookupResult.fail("sHR系统中不存在提报方案[" + schemeName + "]");
    }

    // ==================== 提报单操作 ====================

    /**
     * 创建提报单。
     * TODO: 替换为实际的 BOS 实体 addnew 调用。
     */
    private String createDeclareBill(Context ctx, PersonInfo person, Object violationType,
                                     Object scheme, ComplaintDonationDeductRequest record,
                                     Date voucherDate) throws BOSException {
        // TODO: 替换为实际实体创建
        // HrDeclareBillInfo billInfo = new HrDeclareBillInfo();
        // billInfo.setPerson(person);
        // billInfo.setDeclareScheme((HrDeclareSchemeInfo) scheme);
        // billInfo.setViolationType((ViolationTypeInfo) violationType);
        // billInfo.setComplaintFineAmount(record.getComplaintFineAmount());
        // billInfo.setViolationDonationAmount(record.getViolationDonationAmount());
        // billInfo.setVoucherDate(voucherDate);
        // billInfo.setRemark(record.getRemark());
        // billInfo.setApplyDate(new Date());
        // billInfo.setBillState(HRBillStateEnum.SAVED);
        // billInfo.setApproveType(ApproveTypeEnum.DIRECT);
        //
        // IHrDeclareBill billIns = HrDeclareBillFactory.getLocalInstance(ctx);
        // IObjectPK pk = billIns.addnew(billInfo);
        // return pk.getKeyValue("id");

        logger.info("TODO: 创建提报单 - 工号: {}, 违规类型: {}, 方案: {}, 罚款: {}, 乐捐: {}, 日期: {}",
                record.getPersonNumber(), record.getViolationTypeCode(), DECLARE_SCHEME_NAME,
                record.getComplaintFineAmount(), record.getViolationDonationAmount(), record.getVoucherDate());
        return null;
    }

    /**
     * 直接审批提报单（自动生效）。
     * TODO: 替换为实际的 BOS 实体 auditEntryEffect 调用。
     */
    private void auditDeclareBill(Context ctx, String billId) throws BOSException {
        // TODO: 替换为实际审批调用
        // IHrDeclareBill billIns = HrDeclareBillFactory.getLocalInstance(ctx);
        // billIns.auditEntryEffect(BOSUuid.read(billId));

        logger.info("TODO: 自动审批提报单 - billId: {}", billId);
    }

    // ==================== 工具方法 ====================

    private String buildFailIdentifier(ComplaintDonationDeductRequest request) {
        return request.getPersonNumber() + "##" + request.getVoucherDate();
    }
}
