package com.ruoyi.web.modules.industryservice.support;

import java.util.Date;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Function;
import org.springframework.util.CollectionUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.web.modules.industryservice.domain.vo.YakAssetSyncResultVo;

/**
 * 第三方养殖基础数据（圈舍/计划/批次等）批量同步执行器。
 * <p>
 * 封装「逐条 persist + 统计 insert/update/fail」的通用循环，
 * 供 {@link com.ruoyi.web.modules.industryservice.service.FarmEnclosureSyncService} 等编排类复用。
 * </p>
 *
 * <h3>容错</h3>
 * <p>
 * 单条 {@code persistFn} 抛异常时捕获并记入 {@link YakAssetSyncResultVo#getFailMessages()}，
 * 继续处理后续记录；与 {@code REQUIRES_NEW} 事务配合，已成功落库的行不回滚。
 * </p>
 */
public final class FarmingDataSyncExecutor
{
    private FarmingDataSyncExecutor()
    {
    }

    /**
     * 批量执行同步持久化。
     *
     * @param rows      第三方拉取的全量列表
     * @param persistFn 单条持久化函数，返回 true=新增 false=更新
     * @param keyFn     失败明细中的标识（通常为 external_id）
     * @return 汇总结果
     */
    public static <T> YakAssetSyncResultVo execute(List<T> rows, BiFunction<T, Date, Boolean> persistFn,
            Function<T, String> keyFn)
    {
        YakAssetSyncResultVo result = new YakAssetSyncResultVo();
        Date syncTime = new Date();
        if (CollectionUtils.isEmpty(rows))
        {
            result.setSyncTime(syncTime);
            return result;
        }
        for (T row : rows)
        {
            try
            {
                boolean inserted = persistFn.apply(row, syncTime);
                if (inserted)
                {
                    result.setInsertCount(result.getInsertCount() + 1);
                }
                else
                {
                    result.setUpdateCount(result.getUpdateCount() + 1);
                }
            }
            catch (Exception e)
            {
                result.setFailCount(result.getFailCount() + 1);
                String key = row != null && keyFn != null ? StringUtils.nvl(keyFn.apply(row), "?") : "?";
                result.getFailMessages().add(key + ": " + e.getMessage());
            }
        }
        result.setSyncTime(syncTime);
        return result;
    }
}
