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

import java.util.Date;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.web.modules.industryservice.domain.BizFarmingBatch;
import com.ruoyi.web.modules.industryservice.domain.BizPasture;
import com.ruoyi.web.modules.industryservice.domain.BizYakAsset;
import com.ruoyi.web.modules.industryservice.domain.BizYakFeedingRecord;
import com.ruoyi.web.modules.industryservice.domain.BizYakGrowthRecord;
import com.ruoyi.web.modules.industryservice.domain.BizYakPhysioSeries;
import com.ruoyi.web.modules.industryservice.domain.BizYakReproductionRecord;
import com.ruoyi.web.modules.industryservice.domain.dto.YakAssetBundleDto;
import com.ruoyi.web.modules.industryservice.mapper.BizPastureMapper;
import com.ruoyi.web.modules.industryservice.mapper.BizFarmEnclosureMapper;
import com.ruoyi.web.modules.industryservice.mapper.BizFarmingBatchMapper;
import com.ruoyi.web.modules.industryservice.mapper.BizYakAssetMapper;
import com.ruoyi.web.modules.industryservice.mapper.BizYakFeedingRecordMapper;
import com.ruoyi.web.modules.industryservice.support.YakAssetStatusMapper;
import com.ruoyi.web.modules.industryservice.mapper.BizYakGrowthRecordMapper;
import com.ruoyi.web.modules.industryservice.mapper.BizYakPhysioSeriesMapper;
import com.ruoyi.web.modules.industryservice.mapper.BizYakReproductionRecordMapper;
import com.ruoyi.web.modules.industryservice.support.FarmingSyncSupport;
import com.ruoyi.web.modules.industryservice.support.YakAssetRules;
import com.ruoyi.web.modules.industryservice.support.YakAssetValidation;

/**
 * 单头牦牛资产同步事务服务。
 * <p>
 * 接收 {@link YakAssetBundleDto}（含主表 {@link BizYakAsset} 及可选子表列表），
 * 按 {@code external_id}（第三方 cattleId）优先、其次 {@code yak_no} 进行 upsert。
 * 每头牦牛独立事务（REQUIRES_NEW），单头失败不影响其他头。
 * </p>
 *
 * <h3>主表合并策略</h3>
 * <ul>
 *   <li>先查 external_id，再查 yak_no</li>
 *   <li>存在则 update，不存在则 insert</li>
 *   <li>自动解析 pasture_id：farmId → biz_pasture.external_id，或牧场名称精确匹配</li>
 * </ul>
 *
 * <h3>子表覆盖策略</h3>
 * <p>
 * bundle 中某子表列表为 {@code null} 表示<strong>本次不同步</strong>该子表（保留本地数据）；
 * 非 null 时先 delete 再 batchInsert（全量覆盖该子表）。
 * 当前入栏建档 OpenAPI 仅填充主表字段，子表列表默认为 null。
 * </p>
 */
@Service
public class YakAssetBundleSyncTxService
{
    @Autowired
    private BizYakAssetMapper bizYakAssetMapper;

    @Autowired
    private BizPastureMapper bizPastureMapper;

    @Autowired
    private BizFarmEnclosureMapper bizFarmEnclosureMapper;

    @Autowired
    private BizFarmingBatchMapper bizFarmingBatchMapper;

    @Autowired
    private BizYakPhysioSeriesMapper physioSeriesMapper;

    @Autowired
    private BizYakGrowthRecordMapper growthRecordMapper;

    @Autowired
    private BizYakReproductionRecordMapper reproductionRecordMapper;

    @Autowired
    private BizYakFeedingRecordMapper feedingRecordMapper;

    /**
     * 持久化一头牦牛的同步数据包。
     *
     * @param bundle   含主表及可选子表
     * @param syncTime 本次同步批次时间，写入 last_sync_time
     * @return {@code true}=新增，{@code false}=更新
     */
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public boolean persistBundle(YakAssetBundleDto bundle, Date syncTime)
    {
        if (bundle == null || bundle.getAsset() == null)
        {
            throw new ServiceException("同步数据包无效");
        }
        BizYakAsset incoming = bundle.getAsset();
        YakAssetValidation.validateYakNoForSync(incoming.getYakNo());
        String yakNo = incoming.getYakNo().trim();
        incoming.setYakNo(yakNo);
        if (incoming.getAssetStatus() == null)
        {
            incoming.setAssetStatus(YakAssetRules.ASSET_STATUS_MIN);
        }
        else
        {
            incoming.setAssetStatus(YakAssetStatusMapper.normalizeLegacyNumericStatus(incoming.getAssetStatus()));
            YakAssetValidation.validateAssetStatus(incoming.getAssetStatus());
        }
        resolvePasture(incoming, bundle);
        resolveEnclosure(incoming);
        resolveBatch(incoming);
        // 月龄不入栏接口直传：有出生日期则按同步时刻计算整月龄写入 age_months
        if (incoming.getBirthDate() != null)
        {
            incoming.setAgeMonths(YakAssetValidation.resolveAgeMonths(incoming.getBirthDate(), syncTime));
        }
        incoming.setLastSyncTime(syncTime);
        incoming.setDelFlag(YakAssetRules.DEL_FLAG_NORMAL);

        BizYakAsset existing = resolveExisting(incoming);
        Long yakAssetId;
        boolean inserted;
        if (existing == null)
        {
            bizYakAssetMapper.insertBizYakAsset(incoming);
            yakAssetId = incoming.getId();
            inserted = true;
        }
        else
        {
            incoming.setId(existing.getId());
            bizYakAssetMapper.updateBizYakAsset(incoming);
            yakAssetId = existing.getId();
            inserted = false;
        }
        replaceChildRows(yakAssetId, bundle);
        return inserted;
    }

    /**
     * 解析本地已存在档案：优先 external_id（cattleId），其次 yak_no。
     */
    private BizYakAsset resolveExisting(BizYakAsset incoming)
    {
        if (incoming.getExternalId() != null)
        {
            BizYakAsset byExternal = bizYakAssetMapper.selectBizYakAssetByExternalId(incoming.getExternalId());
            if (byExternal != null)
            {
                return byExternal;
            }
        }
        return bizYakAssetMapper.selectBizYakAssetByYakNo(incoming.getYakNo());
    }

    /**
     * 关联养殖场：优先 thirdPartyPastureCode（farmId），其次 pastureName 精确匹配。
     */
    private void resolvePasture(BizYakAsset incoming, YakAssetBundleDto bundle)
    {
        BizPasture pasture = null;
        if (bundle != null && StringUtils.isNotEmpty(bundle.getThirdPartyPastureCode()))
        {
            try
            {
                Long farmId = Long.parseLong(bundle.getThirdPartyPastureCode().trim());
                pasture = bizPastureMapper.selectBizPastureByExternalId(farmId);
            }
            catch (NumberFormatException ignored)
            {
                // 非数字编码时回退名称匹配
            }
        }
        if (pasture == null && StringUtils.isNotEmpty(incoming.getPastureName()))
        {
            pasture = bizPastureMapper.selectBizPastureByExactName(incoming.getPastureName().trim());
        }
        if (pasture != null)
        {
            incoming.setPastureId(pasture.getId());
            incoming.setPastureName(pasture.getPastureName());
        }
        else if (StringUtils.isEmpty(incoming.getPastureName()))
        {
            incoming.setPastureName("未关联");
        }
    }

    private void resolveEnclosure(BizYakAsset incoming)
    {
        // enclosure_external_id → biz_farm_enclosure.id，供本地关联；环境监测仍用 external_id
        Long enclosureId = FarmingSyncSupport.resolveEnclosureId(
                bizFarmEnclosureMapper, incoming.getEnclosureExternalId());
        incoming.setEnclosureId(enclosureId);
    }

    private void resolveBatch(BizYakAsset incoming)
    {
        if (incoming.getBatchExternalId() == null)
        {
            incoming.setBatchId(null);
            incoming.setBatchNo(null);
            return;
        }
        // batch_no 仅通过已同步的 biz_farming_batch 解析，OpenAPI 不直传 batchNo 文本
        BizFarmingBatch batch = bizFarmingBatchMapper.selectBizFarmingBatchByExternalId(
                incoming.getBatchExternalId());
        if (batch != null)
        {
            incoming.setBatchId(batch.getId());
            incoming.setBatchNo(batch.getBatchNo());
        }
        else
        {
            incoming.setBatchId(null);
            incoming.setBatchNo(null);
        }
    }

    /**
     * 子表「按需覆盖」：列表为 null 跳过；非 null 则 delete + batchInsert。
     */
    private void replaceChildRows(Long yakAssetId, YakAssetBundleDto bundle)
    {
        if (bundle.getPhysioSeries() != null)
        {
            physioSeriesMapper.deleteByYakAssetId(yakAssetId);
        }
        if (bundle.getGrowthRecords() != null)
        {
            growthRecordMapper.deleteByYakAssetId(yakAssetId);
        }
        if (bundle.getReproductionRecords() != null)
        {
            reproductionRecordMapper.deleteByYakAssetId(yakAssetId);
        }
        if (bundle.getFeedingRecords() != null)
        {
            feedingRecordMapper.deleteByYakAssetId(yakAssetId);
        }

        if (!CollectionUtils.isEmpty(bundle.getPhysioSeries()))
        {
            for (BizYakPhysioSeries row : bundle.getPhysioSeries())
            {
                row.setYakAssetId(yakAssetId);
            }
            physioSeriesMapper.batchInsert(bundle.getPhysioSeries());
        }
        if (!CollectionUtils.isEmpty(bundle.getGrowthRecords()))
        {
            for (BizYakGrowthRecord row : bundle.getGrowthRecords())
            {
                row.setYakAssetId(yakAssetId);
                if (row.getDataKind() == null)
                {
                    row.setDataKind(YakAssetRules.DATA_KIND_ACTUAL);
                }
            }
            growthRecordMapper.batchInsert(bundle.getGrowthRecords());
        }
        if (!CollectionUtils.isEmpty(bundle.getReproductionRecords()))
        {
            for (BizYakReproductionRecord row : bundle.getReproductionRecords())
            {
                row.setYakAssetId(yakAssetId);
                if (row.getDystociaFlag() == null)
                {
                    row.setDystociaFlag("0");
                }
            }
            reproductionRecordMapper.batchInsert(bundle.getReproductionRecords());
        }
        if (!CollectionUtils.isEmpty(bundle.getFeedingRecords()))
        {
            for (BizYakFeedingRecord row : bundle.getFeedingRecords())
            {
                row.setYakAssetId(yakAssetId);
            }
            feedingRecordMapper.batchInsert(bundle.getFeedingRecords());
        }
    }
}
