package com.huatek.busi.service.impl.dataoutput.impls;

import java.io.BufferedWriter;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import com.huatek.busi.common.SiteConstants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import com.google.common.base.Joiner;
import com.google.common.collect.Maps;
import com.huatek.busi.common.util.DateUtil;
import com.huatek.busi.service.cac.CacEtlFactoryService;
import com.huatek.busi.service.dataoutput.DataOutputExecutor;
import com.huatek.busi.service.pointtable.PointTableEtlFactoryService;
import com.huatek.busi.service.transformer.TransformerRunStatusService;
import com.huatek.busi.vo.dataoutput.OutputEquipmentVo;
import com.huatek.torch.frame.exception.OwlException;

/**
 * 数据输出接口抽象实现
 * 
 * @author anker_cheng
 * @date 2019/10/14
 */
public abstract class AbstractDataOutputExecutor implements DataOutputExecutor {
    static final String PART_START = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";

    static String PART_ONE =
        "<output><body><equipinfo><id>%s</id><name>%s</name><subid>%s</subid><subname>%s</subname></equipinfo><day>%s</day>";

    static String PART_END = "</body></output>";

    static final Joiner JOINER = Joiner.on("").skipNulls();

    @Autowired
    protected CacEtlFactoryService<?> cacEtlFactoryService;
    @Autowired
    protected TransformerRunStatusService transformerRunStatusService;
    @Autowired
    protected PointTableEtlFactoryService pointTableEtlFactoryService;

    @Override
    public void execute(Path path, OutputEquipmentVo vo, LocalDate day) throws Exception {
        Map<String, Object> params;
        // 20230614 测温设备撸出子树下所有的传感器的最新一条数据（按sensor_code去重）
        if (SiteConstants.SiteTreeEnum.CW_HL_EQM.getValue().equals(vo.getMainEquipmentType())) {
            params = getParamsForCw(vo, day);
            params.put("outTask", "hasValue");
        } else {
            params = getParams(vo, day);
        }
        List<Map<String, Object>> dataList = queryDataList(params);

        OutputStream opt = Files.newOutputStream(path);
        try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(opt, StandardCharsets.UTF_8))) {
            writer.append(PART_START);
            writer.append(String.format(PART_ONE, vo.getMainTreeId(), vo.getMainTreeName(), getVal(vo.getSubTreeId()),
                getVal(vo.getSubTreeName()), day.toString()));
            if (!CollectionUtils.isEmpty(dataList)) {
                List<String> keys = getKeys();
                for (Map<String, Object> item : dataList) {
                    writer.append("<item>");
                    for (String key : keys) {
                        writer.append(String.format("<attr name=\"%s\" value=\"%s\"/>", key, getVal(item.get(key))));
                    }
                    writer.append("</item>");
                }
            }
            writer.append(PART_END);
        }
    }
    
    /**
     * 数据输出只取最新一条数据
     * @param vo
     * @param day
     * @return
     */
    protected Map<String, Object> getParams(OutputEquipmentVo vo, LocalDate day) {
        String date1=day.plusDays(-1).toString();
        String date = day.toString();
        Map<String, Object> params = Maps.newLinkedHashMap();
        params.put("mainTreeId", vo.getMainTreeId());
        params.put("subTreeId", vo.getSubTreeId());
        params.put("timeStamp", date1);
        params.put("timeStampEnd", date);
        params.put("page", "1");
        params.put("limit", "500");
        return params;
    }
    protected Map<String, Object> getParamsXML(OutputEquipmentVo vo, LocalDate day) {
        String date1=day.plusDays(-1).toString();
        String date = day.toString();
        Map<String, Object> params = Maps.newLinkedHashMap();
        params.put("mainTreeId", vo.getMainTreeId());
        params.put("subTreeId", vo.getSubTreeId());
        params.put("timeStamp", date1);
        params.put("timeStampEnd", date);
        params.put("page", "1");
        params.put("limit", "500");
        return params;
    }
    /**
     * 数据输出只取最新一条数据
     * @param vo
     * @param day
     * @return
     */
    protected Map<String, Object> getParamsForCw(OutputEquipmentVo vo, LocalDate day) {
//        String date = day.toString();
        Map<String, Object> params = Maps.newLinkedHashMap();
        params.put("mainTreeId", vo.getMainTreeId());
        params.put("subTreeId", vo.getSubTreeId());
//        params.put("timeStamp", date);
//        params.put("timeStampEnd", date);
        params.put("page", "1");
        params.put("limit", "9999");
        return params;
    }

    protected List<String> getKeys() {
        return Collections.emptyList();
    }

    @SuppressWarnings("unchecked")
    protected List<Map<String, Object>> queryDataList(Map<String, Object> params) {
        Map<String, Object> result = null;
        if (!StringUtils.isEmpty(params.get("cacMonitorTypeCode"))) {
            result = cacEtlFactoryService.findCACPageData(params);
        } else if (!StringUtils.isEmpty(params.get("pointTableMonitorTypeCode"))) {
            result = pointTableEtlFactoryService.findPointTablePageData(params);
        } else if (!StringUtils.isEmpty(params.get("transformerRunStatus"))) {
            result = transformerRunStatusService.findTransformerRunStatusPage(params);
        } else {
            throw new OwlException("参数错误！");
        }
        return (List<Map<String, Object>>)result.get("data");
    }

    private static String getVal(Object val) {
        if (val == null) {
            return "";
        }
        if (val instanceof LocalDate) {
            return DateUtil.format((LocalDate)val);
        }
        if (val instanceof LocalDateTime) {
            return DateUtil.format((LocalDateTime)val);
        }
        return val.toString();
    }
}
