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

import java.util.Collections;
import java.util.Date;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.web.modules.industryservice.domain.BizYakAsset;
import com.ruoyi.web.modules.industryservice.domain.BizYakPhysioSeries;
import com.ruoyi.web.modules.industryservice.domain.dto.OpenEarTagDto;
import com.ruoyi.web.modules.industryservice.domain.dto.OpenEnvMonitoringDto;
import com.ruoyi.web.modules.industryservice.support.FarmingSyncSupport;
import com.ruoyi.web.modules.industryservice.support.ThirdPartyFarmingProperties;
import com.ruoyi.web.modules.industryservice.support.ThirdPartyIotEarTagClient;
import com.ruoyi.web.modules.industryservice.support.ThirdPartyIotEnvMonitoringClient;
import com.ruoyi.web.modules.industryservice.support.YakAssetPhysioSupport;

/**
 * 牦牛档案详情「个体生理」实时数据服务。
 * <p>
 * 不依赖本地 IoT 同步表，打开详情或拉取曲线时直接请求第三方开放接口：
 * </p>
 * <ul>
 *   <li>耳标：{@code GET /open-api/v1/iot/ear-tags}，参数 {@code earTagNumber}（必传），可选 {@code startTime}/{@code endTime}</li>
 *   <li>环境：{@code GET /open-api/v1/iot/env-monitoring}，参数 {@code farmId}、{@code enclosureId}，可选时间窗口</li>
 * </ul>
 *
 * <h3>字段来源</h3>
 * <ul>
 *   <li>实时体温 ← 耳标 {@code temperature}（转化后温度，非 actualTemperature）</li>
 *   <li>实时运动量 ← 耳标 {@code steps}</li>
 *   <li>上报时间 ← 耳标 {@code reportTime} 最大的一条</li>
 *   <li>环境温度 ← 环境监测 {@code temperature}，{@code monitoringTime} 最大的一条</li>
 * </ul>
 *
 * <p>第三方未启用或调用失败时降级为空值，不阻断详情页加载。</p>
 */
@Service
public class YakAssetPhysioLiveService
{
    private static final Logger log = LoggerFactory.getLogger(YakAssetPhysioLiveService.class);

    @Autowired
    private ThirdPartyIotEarTagClient earTagClient;

    @Autowired
    private ThirdPartyIotEnvMonitoringClient envMonitoringClient;

    @Autowired
    private ThirdPartyFarmingProperties properties;

    /**
     * 填充详情区实时生理指标，直接写回 {@link BizYakAsset} 对应字段供前端展示。
     * <p>不传时间窗口，在返回结果中取上报时间最新的一条。</p>
     */
    public void enrichRealtimePhysio(BizYakAsset asset)
    {
        if (asset == null)
        {
            return;
        }
        String earTagNumber = StringUtils.isNotEmpty(asset.getEarTagNumber()) ? asset.getEarTagNumber().trim() : null;
        if (earTagNumber != null)
        {
            OpenEarTagDto latest = YakAssetPhysioSupport.findLatestEarTag(
                    safeFetchEarTags(earTagNumber, null, null));
            if (latest != null)
            {
                asset.setRealtimeTemp(YakAssetPhysioSupport.convertedTemperature(latest));
                asset.setRealtimeSteps(YakAssetPhysioSupport.parseSteps(latest.getSteps()));
                asset.setPhysioCollectTime(YakAssetPhysioSupport.parseReportTime(latest));
            }
        }
        if (asset.getFarmExternalId() != null && asset.getEnclosureExternalId() != null)
        {
            OpenEnvMonitoringDto latestEnv = YakAssetPhysioSupport.findLatestEnv(safeFetchEnv(
                    asset.getFarmExternalId(), asset.getEnclosureExternalId(), null, null));
            if (latestEnv != null)
            {
                asset.setEnvTemp(FarmingSyncSupport.toDecimal(latestEnv.getTemperature()));
            }
        }
    }

    /**
     * 近 N 天生理曲线：耳标温度/步数与环境温度按采集时间合并为 {@link BizYakPhysioSeries} 序列。
     *
     * @param asset 须含 earTagNumber；环境曲线另须 farmExternalId、enclosureExternalId
     * @param days  统计天数，监测开始时间 = 当前时间 − days
     */
    public List<BizYakPhysioSeries> fetchPhysioChart(BizYakAsset asset, int days)
    {
        if (asset == null || days <= 0)
        {
            return Collections.emptyList();
        }
        Date endTime = new Date();
        Date startTime = new Date(endTime.getTime() - days * 24L * 60 * 60 * 1000L);
        List<OpenEarTagDto> earTags = Collections.emptyList();
        String earTagNumber = StringUtils.isNotEmpty(asset.getEarTagNumber()) ? asset.getEarTagNumber().trim() : null;
        if (earTagNumber != null)
        {
            earTags = safeFetchEarTags(earTagNumber, startTime, endTime);
        }
        List<OpenEnvMonitoringDto> envRows = Collections.emptyList();
        if (asset.getFarmExternalId() != null && asset.getEnclosureExternalId() != null)
        {
            envRows = safeFetchEnv(asset.getFarmExternalId(), asset.getEnclosureExternalId(), startTime, endTime);
        }
        return YakAssetPhysioSupport.mergeChartSeries(earTags, envRows);
    }

    /**
     * 安全调用耳标接口：未启用或异常时返回空列表。
     */
    private List<OpenEarTagDto> safeFetchEarTags(String earTagNumber, Date startTime, Date endTime)
    {
        if (!properties.isEnabled() || StringUtils.isEmpty(earTagNumber))
        {
            return Collections.emptyList();
        }
        try
        {
            return earTagClient.fetchByEarTag(earTagNumber, startTime, endTime);
        }
        catch (Exception ex)
        {
            log.warn("读取耳标生理数据失败 earTagNumber={}: {}", earTagNumber, ex.getMessage());
            return Collections.emptyList();
        }
    }

    /**
     * 安全调用环境监测接口：未启用或异常时返回空列表。
     */
    private List<OpenEnvMonitoringDto> safeFetchEnv(Long farmId, Long enclosureId, Date startTime, Date endTime)
    {
        if (!properties.isEnabled() || farmId == null || enclosureId == null)
        {
            return Collections.emptyList();
        }
        try
        {
            return envMonitoringClient.fetchByFarmEnclosure(farmId, enclosureId, startTime, endTime);
        }
        catch (Exception ex)
        {
            log.warn("读取环境监测数据失败 farmId={} enclosureId={}: {}", farmId, enclosureId, ex.getMessage());
            return Collections.emptyList();
        }
    }
}
