package cn.com.victorysoft.business.calc.service;

import cn.com.victorysoft.business.calc.param.RealtimeRange;
import cn.com.victorysoft.business.indicator.entity.Pump;
import cn.com.victorysoft.business.indicator.entity.PumpDevice;
import cn.com.victorysoft.business.indicator.service.PumpDeviceService;
import cn.com.victorysoft.business.util.DateUtils;
import cn.com.victorysoft.business.util.StringUtils;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * 实时数据服务
 */
@Slf4j
@Service
public class RealtimeService {

    @Value("${realtime.remote.url}")
    private String realtimeRemoteUrl;
    @Value("${realtime.remote.username}")
    private String realtimeRemoteUsername;
    @Value("${realtime.remote.password}")
    private String realtimeRemotePassword;

    @Resource
    private PumpDeviceService pumpDeviceService;

    @Resource
    private RestTemplate restTemplate;

    /**
     * 全部注水泵数据
     */
    public void syncPumpDeviceList() {
        List<Pump> pumps = pumpDeviceService.selectPump(null);
        for (Pump pump : pumps) {
            this.syncPumpDevice(pump);
        }
    }

    /**
     * 注水泵数据
     */
    @Transactional
    public void syncPumpDevice(Pump pump) {
        // 检查是否存在
        Date recordDate = DateUtils.truncate(new Date(), Calendar.DATE);
        PumpDevice device = new PumpDevice();
        device.setStationName(pump.getStationName());
        device.setPumpId(pump.getId());
        device.setRecordDate(recordDate);
        device.setUnitcode(pump.getAreaCode());
        device.setPumpType(pump.getPumpType());
        PumpDevice pumpDevice = pumpDeviceService.selectPumpDevice(device);
        if (pumpDevice != null) return;

        String url = realtimeRemoteUrl + "getDqBeng.json";
        ResponseEntity<String> result = null;
        boolean success = false;
        try{
            result = restTemplate.postForEntity(url, buildDevicePostBody(pump.getId()), String.class);
            success = result.getStatusCodeValue() == 200;
        }catch (Exception e) {
            log.error("注水泵实时数据获取异常", e);
        }
        if (result == null || !success) return;
        log.info("注水泵实时数据接口返回结果：{}", result);
        JSONArray data = JSONArray.fromObject(result.getBody());
        if (data == null || data.size() == 0) return;

        JSONObject jsonObject = data.getJSONObject(0);
        if (StringUtils.isEmpty(device.getPumpType())) {
            device.setPumpType(getString(jsonObject, "SBBM"));
        }
        // 运行时间
        device.setRunTime(null);
        // 运行状态
        device.setRunStatus(getInteger(jsonObject, "YXZT"));
        // 进口压力
        device.setPressureIn(getDouble(jsonObject, "JKYL"));
        // 出口压力
        device.setPressureOut(getDouble(jsonObject, "CKYL"));
        // 平衡压力
        device.setPressureBalance(getDouble(jsonObject, "LLJ_YL"));
        // 排量h
        device.setVolumeHour(getDouble(jsonObject, "LLJ_SSLL"));
        // 排量D
        if (device.getVolumeHour() != null) {
            device.setVolumeDay(device.getVolumeHour() * 24);
        }
        // 计算有效功率 = 【1000*排量（m³/h）*（出口压力-进口压力）Mpa*100】/3600*102
        if (device.getVolumeHour() != null && device.getPressureOut() != null && device.getPressureIn() != null) {
            device.setEffectivePower((1000 * device.getVolumeHour() * (device.getPressureOut() - device.getPressureIn()) * 100) / 3600 * 102);
        }
        // 电压
        device.setVoltage(getDouble(jsonObject, "DC_UA"));
        // 电流
        device.setElectricCurrent(getDouble(jsonObject, "DC_IA"));
        // 功率因数
        device.setPowerFactor(getDouble(jsonObject, "DC_GLYS"));
        // 效率
        if (pump.getEfficiency() != null) {
            device.setEfficiency(pump.getEfficiency().doubleValue());
        }
        // 输入功率 = 1.732*电流*电压*功率因数
        if (device.getVoltage() != null && device.getElectricCurrent() != null && device.getPowerFactor() != null) {
            device.setPowerIn(1.732 * device.getElectricCurrent() * device.getVoltage() * device.getPowerFactor());
        }
        // 输出功率 = 输入功率*效率
        if (device.getPowerIn() != null && device.getEfficiency() != null) {
            device.setPowerOut(device.getPowerIn() * device.getEfficiency());
        }
        // TODO 分水器压力，从PCS表SSC_FZ_SS获取，但是没有输出接口，先使用出口压力-0.3
        if (device.getPressureOut() != null) {
            device.setPressureSplit(device.getPressureOut() - 0.3);
        }
        pumpDeviceService.insert(device);
    }

    private BigDecimal subtract(BigDecimal d1, BigDecimal d0, double max, BigDecimal defaultValue) {
        if (d1 != null && d0 != null) {
            BigDecimal d = d1.subtract(d0);
            if (d.doubleValue() >= 0 && d.doubleValue() < max) {
                return d;
            }
        }
        return defaultValue;
    }

    private JSONObject buildDevicePostBody(String deviceCode) {
        JSONObject jsonParam = new JSONObject();
        JSONObject head = new JSONObject();
        head.put("username", realtimeRemoteUsername);
        head.put("password", realtimeRemotePassword);
        head.put("sbbm.s", deviceCode);
        jsonParam.put("head", head);
        jsonParam.put("body", new ArrayList<>(0));
        return jsonParam;
    }

    private JSONObject buildPostBody(RealtimeRange param) {
        JSONObject jsonParam = new JSONObject();
        JSONObject head = new JSONObject();
        head.put("username", realtimeRemoteUsername);
        head.put("password", realtimeRemotePassword);
        String dateStr = DateUtils.formatDate(param.getDate());
        head.put("startDate.t",  dateStr+ " " + param.getTime() + ":00");
        head.put("endDate.t", dateStr + " " + param.getTime() + ":00");
        jsonParam.put("head", head);
        jsonParam.put("body", new ArrayList<>(0));
        return jsonParam;
    }

    @SneakyThrows
    private JSONObject buildPostWellBody(String wellname, RealtimeRange param) {
        JSONObject jsonParam = new JSONObject();
        JSONObject head = new JSONObject();
        head.put("username", realtimeRemoteUsername);
        head.put("password", realtimeRemotePassword);
        String dateStr = DateUtils.formatDate(param.getDate());
        String startDateStr = dateStr+ " " + param.getTime() + ":00";
        head.put("startDate.t", startDateStr);
        Date startDate = DateUtils.parseDate(startDateStr, "yyyy-MM-dd HH:mm:ss");
        // 取10分钟的数据，防止丢点
        Date endDate = DateUtils.addMinutes(startDate, 10);
        head.put("endDate.t", DateUtils.format(endDate, "yyyy-MM-dd HH:mm:ss"));
        head.put("jh.s", wellname);
        jsonParam.put("head", head);
        jsonParam.put("body", new ArrayList<>(0));
        return jsonParam;
    }
    
    private String getString(JSONObject jsonObject, String key) {
        if (jsonObject.containsKey(key)) {
            return jsonObject.getString( key);
        }
        return null;
    }
    private Double getDouble(JSONObject jsonObject, String key) {
        if (jsonObject.containsKey(key)) {
            return jsonObject.getDouble(key);
        }
        return null;
    }
    private Integer getInteger(JSONObject jsonObject, String key) {
        if (jsonObject.containsKey(key)) {
            return jsonObject.getInt(key);
        }
        return null;
    }
    private Date getDate(JSONObject jsonObject, String key) {
        if (jsonObject.containsKey(key)) {
            try {
                String dateStr = getString(jsonObject, key);
                if (dateStr != null) {
                    return DateUtils.parseDate(dateStr, "yyyy-MM-dd HH:mm:ss");
                }
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

}
