package com.sundot.airport.common.service.portrait;

import com.sundot.airport.common.domain.portrait.IndicatorCalculateParams;
import com.sundot.airport.common.domain.portrait.BaseModuleIndicatorResult;
import com.sundot.airport.common.enums.portrait.IndicatorType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;

/**
 * 抽象模块指标服务基类
 * 提供通用的指标计算逻辑，各模块可以继承此类实现自己的特定逻辑
 *
 * @param <T> 模块指标结果类型
 */
public abstract class AbstractModuleIndicatorService<T extends BaseModuleIndicatorResult> implements ModuleIndicatorService {

    private static final Logger log = LoggerFactory.getLogger(AbstractModuleIndicatorService.class);

    /**
     * 创建模块特定的结果对象
     *
     * @return 模块结果对象
     */
    protected abstract T createResult();

    /**
     * 获取当前模块支持的指标类型
     *
     * @return 指标类型列表
     */
    protected abstract Set<IndicatorType> getSupportedIndicatorTypes();

    /**
     * 获取所有可用的指标
     *
     * @return 指标集合
     */
    protected abstract Set<? extends Indicator<?>> getIndicators();

    @Override
    public Object calculateIndicators(IndicatorCalculateParams params) {
        T result = createResult();
        result.setModuleName(getModuleName());

        // 获取需要计算的指标类型列表
        List<IndicatorType> indicatorTypes = getIndicatorTypesToCalculate(params);

        // 获取当前模块名称
        String currentModule = getModuleName();

        // 检查是否指定了模块，如果指定了模块但不包含当前模块，则直接返回空结果
        if (params.getModules() != null && !params.getModules().isEmpty()
                && !params.getModules().contains(currentModule)) {
            return null;
        }

        // 获取支持的指标类型
        Set<IndicatorType> supportedTypes = getSupportedIndicatorTypes();

        for (IndicatorType indicatorType : indicatorTypes) {
            // 处理属于当前模块且被支持的指标类型
            if (currentModule.equals(indicatorType.getModule()) && supportedTypes.contains(indicatorType)) {
                // 查找对应的指标实现
                Indicator<?> indicator = findIndicator(indicatorType);
                if (indicator != null) {
                    try {
                        indicator.calculate(params);
                        // 注意：这里需要子类自己处理如何将指标值设置到结果对象中
                        setIndicatorResult(indicator, result);
                    } catch (Exception e) {
                        log.error("指标计算出错: 指标名称={}, 模块={}, 错误信息={}",
                                indicator.getName(), getModuleName(), e.getMessage(), e);
                        result.setError(indicator.getName(), e.getMessage());
                    }
                }
            }
        }

        return result;
    }

    /**
     * 根据指标类型查找对应的指标实现
     *
     * @param type 指标类型
     * @return 指标实现
     */
    private Indicator<?> findIndicator(IndicatorType type) {
        Set<? extends Indicator<?>> indicators = getIndicators();
        if (indicators != null) {
            for (Indicator<?> indicator : indicators) {
                if (type.getCode().equals(indicator.getName())) {
                    return indicator;
                }
            }
        }
        return null;
    }

    /**
     * 将指标值设置到结果对象中
     *
     * @param indicator 指标
     * @param result    结果对象
     */
    protected abstract void setIndicatorResult(Indicator<?> indicator, T result);

    /**
     * 根据参数确定需要计算的指标类型列表
     *
     * @param params 指标计算参数
     * @return 需要计算的指标类型列表
     */
    private List<IndicatorType> getIndicatorTypesToCalculate(IndicatorCalculateParams params) {
        // 如果参数中指定了指标，则只计算指定模块的指标
        if (params.getIndicatorTypes() != null && !params.getIndicatorTypes().isEmpty()) {
            List<IndicatorType> indicatorTypes = new ArrayList<>();
            for (String typeCode : params.getIndicatorTypes()) {
                IndicatorType type = IndicatorType.fromCode(typeCode);
                if (type != null) {
                    indicatorTypes.add(type);
                }
            }
            return indicatorTypes;
        } else {
            // 否则计算所有指标
            return Arrays.asList(IndicatorType.values());
        }
    }
}