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

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.TreeMap;
import com.ruoyi.common.utils.StringUtils;
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;

/**
 * 牦牛个体生理 OpenAPI 数据解析与曲线合并工具。
 * <p>
 * 将第三方 DTO 转为前端曲线使用的 {@link BizYakPhysioSeries}，并统一「取最新一条」规则。
 * </p>
 *
 * <h3>温度字段说明</h3>
 * <p>
 * 耳标接口同时返回 {@code actualTemperature}（原始）与 {@code temperature}（转化后）。
 * 产品展示与曲线均使用<strong>转化后温度</strong> {@code temperature}。
 * </p>
 */
public final class YakAssetPhysioSupport
{
    private YakAssetPhysioSupport()
    {
    }

    /**
     * 转化后体温 ℃，对应 OpenEarTagDto.temperature。
     */
    public static BigDecimal convertedTemperature(OpenEarTagDto dto)
    {
        return dto == null ? null : FarmingSyncSupport.parseDecimal(dto.getTemperature());
    }

    /** 解析步数字符串为整数，非法格式返回 null */
    public static Integer parseSteps(String steps)
    {
        if (StringUtils.isEmpty(steps))
        {
            return null;
        }
        try
        {
            return (int) Math.round(Double.parseDouble(steps.trim()));
        }
        catch (NumberFormatException ex)
        {
            return null;
        }
    }

    /** 耳标监测上报时间 reportTime */
    public static Date parseReportTime(OpenEarTagDto dto)
    {
        return dto == null ? null : FarmingSyncSupport.parseThirdPartyTime(dto.getReportTime(), null);
    }

    /** 环境监测采集时间 monitoringTime */
    public static Date parseMonitoringTime(OpenEnvMonitoringDto dto)
    {
        return dto == null ? null : FarmingSyncSupport.parseThirdPartyTime(dto.getMonitoringTime(), null);
    }

    /**
     * 在分页结果中取 reportTime 最大的一条，作为「实时」耳标数据。
     */
    public static OpenEarTagDto findLatestEarTag(List<OpenEarTagDto> rows)
    {
        if (rows == null || rows.isEmpty())
        {
            return null;
        }
        return rows.stream()
                .filter(row -> row != null && parseReportTime(row) != null)
                .max(Comparator.comparing(YakAssetPhysioSupport::parseReportTime))
                .orElse(null);
    }

    /**
     * 在分页结果中取 monitoringTime 最大的一条，作为圈舍「实时」环境温度。
     */
    public static OpenEnvMonitoringDto findLatestEnv(List<OpenEnvMonitoringDto> rows)
    {
        if (rows == null || rows.isEmpty())
        {
            return null;
        }
        return rows.stream()
                .filter(row -> row != null && parseMonitoringTime(row) != null)
                .max(Comparator.comparing(YakAssetPhysioSupport::parseMonitoringTime))
                .orElse(null);
    }

    /**
     * 合并耳标与环境监测时序为统一曲线点，按 collectTime 升序。
     * <p>
     * 同一时间戳上可能仅有体温/步数或仅有环境温度；前端 ECharts 以 null 断点展示。
     * </p>
     */
    public static List<BizYakPhysioSeries> mergeChartSeries(List<OpenEarTagDto> earTags,
            List<OpenEnvMonitoringDto> envRows)
    {
        TreeMap<Date, BizYakPhysioSeries> merged = new TreeMap<>();
        if (earTags != null)
        {
            for (OpenEarTagDto row : earTags)
            {
                Date collectTime = parseReportTime(row);
                if (collectTime == null)
                {
                    continue;
                }
                BizYakPhysioSeries point = merged.computeIfAbsent(collectTime, YakAssetPhysioSupport::newPoint);
                point.setBodyTemp(convertedTemperature(row));
                point.setSteps(parseSteps(row.getSteps()));
            }
        }
        if (envRows != null)
        {
            for (OpenEnvMonitoringDto row : envRows)
            {
                Date collectTime = parseMonitoringTime(row);
                if (collectTime == null)
                {
                    continue;
                }
                BizYakPhysioSeries point = merged.computeIfAbsent(collectTime, YakAssetPhysioSupport::newPoint);
                point.setEnvTemp(FarmingSyncSupport.toDecimal(row.getTemperature()));
            }
        }
        return new ArrayList<>(merged.values());
    }

    private static BizYakPhysioSeries newPoint(Date collectTime)
    {
        BizYakPhysioSeries point = new BizYakPhysioSeries();
        point.setCollectTime(collectTime);
        return point;
    }
}
