package com.xzzn.ems.service.impl;

import com.xzzn.common.exception.ServiceException;
import com.xzzn.common.utils.StringUtils;
import com.xzzn.ems.domain.EmsPointConfig;
import com.xzzn.ems.domain.EmsPointCalcConfig;
import com.xzzn.ems.service.IEmsPointConfigService;
import com.xzzn.ems.service.IEmsPointCalcConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Service
public class EmsPointCalcConfigServiceImpl implements IEmsPointCalcConfigService {
    private static final Pattern CALC_EXPRESSION_PATTERN = Pattern.compile("^[0-9A-Za-z_+\\-*/().,?:<>=!&|\\s]+$");
    private static final String CALC_POINT_TYPE = "calc";

    @Autowired
    private IEmsPointConfigService pointConfigService;

    @Override
    public List<EmsPointCalcConfig> selectPointCalcConfigList(EmsPointCalcConfig pointCalcConfig) {
        EmsPointConfig query = toPointConfigQuery(pointCalcConfig);
        List<EmsPointConfig> configList = pointConfigService.selectPointConfigList(query);
        if (configList == null || configList.isEmpty()) {
            return new ArrayList<>();
        }
        return configList.stream().map(this::toCalcConfig).collect(Collectors.toList());
    }

    @Override
    public EmsPointCalcConfig selectPointCalcConfigById(Long id) {
        EmsPointConfig config = pointConfigService.selectPointConfigById(id);
        if (config == null || !CALC_POINT_TYPE.equalsIgnoreCase(config.getPointType())) {
            return null;
        }
        return toCalcConfig(config);
    }

    @Override
    public int insertPointCalcConfig(EmsPointCalcConfig pointCalcConfig, String operName) {
        if (pointCalcConfig == null || StringUtils.isBlank(pointCalcConfig.getSiteId())) {
            throw new ServiceException("站点ID不能为空");
        }
        if (StringUtils.isBlank(pointCalcConfig.getPointId())) {
            throw new ServiceException("点位ID不能为空");
        }
        validateCalcExpression(pointCalcConfig.getCalcExpression());
        return pointConfigService.insertPointConfig(toPointConfig(pointCalcConfig), operName);
    }

    @Override
    public int updatePointCalcConfig(EmsPointCalcConfig pointCalcConfig, String operName) {
        if (pointCalcConfig == null || StringUtils.isBlank(pointCalcConfig.getSiteId())) {
            throw new ServiceException("站点ID不能为空");
        }
        if (StringUtils.isBlank(pointCalcConfig.getPointId())) {
            throw new ServiceException("点位ID不能为空");
        }
        validateCalcExpression(pointCalcConfig.getCalcExpression());
        return pointConfigService.updatePointConfig(toPointConfig(pointCalcConfig), operName);
    }

    @Override
    public int deletePointCalcConfigByIds(Long[] ids) {
        return pointConfigService.deletePointConfigByIds(ids);
    }

    @Override
    public int deleteBySiteId(String siteId) {
        if (StringUtils.isBlank(siteId)) {
            return 0;
        }
        EmsPointConfig query = new EmsPointConfig();
        query.setSiteId(siteId);
        query.setPointType(CALC_POINT_TYPE);
        List<EmsPointConfig> configList = pointConfigService.selectPointConfigList(query);
        if (configList == null || configList.isEmpty()) {
            return 0;
        }
        Long[] ids = configList.stream().map(EmsPointConfig::getId).toArray(Long[]::new);
        return pointConfigService.deletePointConfigByIds(ids);
    }

    private void validateCalcExpression(String expression) {
        if (StringUtils.isBlank(expression)) {
            throw new ServiceException("计算表达式不能为空");
        }
        if (!CALC_EXPRESSION_PATTERN.matcher(expression).matches()) {
            throw new ServiceException("计算表达式仅支持数字、字母、下划线、空格、运算符和函数语法");
        }
    }

    private EmsPointConfig toPointConfig(EmsPointCalcConfig calcConfig) {
        EmsPointConfig pointConfig = new EmsPointConfig();
        pointConfig.setId(calcConfig.getId());
        pointConfig.setPointId(calcConfig.getPointId());
        pointConfig.setSiteId(calcConfig.getSiteId());
        pointConfig.setPointType(CALC_POINT_TYPE);
        pointConfig.setDeviceCategory(calcConfig.getDeviceCategory());
        pointConfig.setDeviceId("");
        pointConfig.setRegisterAddress("");
        pointConfig.setPointName(calcConfig.getPointName());
        pointConfig.setDataKey(calcConfig.getDataKey());
        pointConfig.setPointDesc(calcConfig.getPointDesc());
        pointConfig.setDataUnit(calcConfig.getDataUnit());
        pointConfig.setCalcExpression(calcConfig.getCalcExpression());
        pointConfig.setRemark(calcConfig.getRemark());
        return pointConfig;
    }

    private EmsPointConfig toPointConfigQuery(EmsPointCalcConfig calcConfig) {
        EmsPointConfig query = new EmsPointConfig();
        query.setSiteId(calcConfig == null ? null : calcConfig.getSiteId());
        query.setDeviceCategory(calcConfig == null ? null : calcConfig.getDeviceCategory());
        query.setDataKey(calcConfig == null ? null : calcConfig.getDataKey());
        query.setPointDesc(calcConfig == null ? null : calcConfig.getPointDesc());
        query.setPointType(CALC_POINT_TYPE);
        return query;
    }

    private EmsPointCalcConfig toCalcConfig(EmsPointConfig pointConfig) {
        EmsPointCalcConfig calcConfig = new EmsPointCalcConfig();
        calcConfig.setId(pointConfig.getId());
        calcConfig.setPointId(pointConfig.getPointId());
        calcConfig.setSiteId(pointConfig.getSiteId());
        calcConfig.setDeviceCategory(pointConfig.getDeviceCategory());
        calcConfig.setPointName(pointConfig.getPointName());
        calcConfig.setDataKey(pointConfig.getDataKey());
        calcConfig.setPointDesc(pointConfig.getPointDesc());
        calcConfig.setDataUnit(pointConfig.getDataUnit());
        calcConfig.setCalcExpression(pointConfig.getCalcExpression());
        calcConfig.setRemark(pointConfig.getRemark());
        calcConfig.setCreateBy(pointConfig.getCreateBy());
        calcConfig.setCreateTime(pointConfig.getCreateTime());
        calcConfig.setUpdateBy(pointConfig.getUpdateBy());
        calcConfig.setUpdateTime(pointConfig.getUpdateTime());
        return calcConfig;
    }
}
