package org.nl.acs.opc.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.nl.acs.common.base.CommonFinalParam;
import org.nl.acs.opc.LangProcess;
import org.nl.acs.opc.domain.OpcPlc;
import org.nl.acs.opc.service.mapper.OpcPlcMapper;
import org.nl.acs.utils.ReadUtil;
import org.nl.acs.common.base.PageInfo;
import org.nl.acs.common.base.QueryHelpMybatisPlus;
import org.nl.acs.common.base.impl.CommonServiceImpl;
import org.nl.common.exception.BadRequestException;
import org.nl.acs.utils.ConvertUtil;
import org.nl.common.utils.FileUtil;
import org.nl.acs.utils.PageUtil;
import org.nl.acs.opc.domain.Opc;
import org.nl.acs.opc.service.OpcService;
import org.nl.acs.opc.service.dto.OpcDto;
import org.nl.acs.opc.service.dto.OpcQueryParam;
import org.nl.acs.opc.service.mapper.OpcMapper;
import org.nl.common.utils.SecurityUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.data.domain.Pageable;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;

/**
 * @author jiaolm
 * @date 2023-05-09
 */
@Service
@AllArgsConstructor
@Slf4j
// @CacheConfig(cacheNames = OpcService.CACHE_KEY)
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class OpcServiceImpl extends CommonServiceImpl<OpcMapper, Opc> implements OpcService {

    private final OpcMapper opcMapper;
    private final OpcPlcMapper opcPlcMapper;

    private static final String BLURRY = "blurry";

    @Override
    public PageInfo<OpcDto> queryAll(OpcQueryParam query, Pageable pageable) {
        IPage<Opc> queryPage = PageUtil.toMybatisPage(pageable);
        IPage<Opc> page = opcMapper.selectPage(queryPage, QueryHelpMybatisPlus.getPredicate(query));
        return ConvertUtil.convertPage(page, OpcDto.class);
    }

    @Override
    public List<OpcDto> queryAll(OpcQueryParam query) {
        return ConvertUtil.convertList(opcMapper.selectList(QueryHelpMybatisPlus.getPredicate(query)), OpcDto.class);
    }

    @Override
    public Opc getById(String id) {
        return opcMapper.selectById(id);
    }

    @Override

    public OpcDto findById(String id) {
        return ConvertUtil.convert(getById(id), OpcDto.class);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insert(OpcDto dto) {
        String currentUsername = SecurityUtils.getCurrentNickName();
        String now = DateUtil.now();
        dto.setOpc_id(IdUtil.simpleUUID());
        dto.setCreate_by(currentUsername);
        dto.setUpdate_by(currentUsername);
        dto.setUpdate_time(now);
        dto.setCreate_time(now);
        Opc entity = ConvertUtil.convert(dto, Opc.class);
        return opcMapper.insert(entity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateById(OpcDto resources) {
        Opc entity = ConvertUtil.convert(resources, Opc.class);
        int ret = opcMapper.updateById(entity);
        // delCaches(resources.id);
        return ret;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int removeByIds(Set<String> ids) {
        // delCaches(ids);
        return opcMapper.deleteBatchIds(ids);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int removeById(String id) {
        Set<String> set = new HashSet<>(1);
        set.add(id);
        return this.removeByIds(set);
    }

    /*
    private void delCaches(String id) {
        redisUtils.delByKey(CACHE_KEY + "::id:", id);
    }

    private void delCaches(Set<String> ids) {
        for (String id: ids) {
            delCaches(id);
        }
    }*/


    @Override
    public Map<String, Object> queryAll(Map whereJson, Pageable page) {
        IPage<Opc> queryPage = PageUtil.toMybatisPage(page);
        LambdaQueryWrapper<Opc> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Opc::getIs_delete, "0").eq(Opc::getIs_active, CommonFinalParam.ONE);
        if (whereJson.get(BLURRY) != null) {
            wrapper.like(Opc::getOpc_code, whereJson.get("blurry")).or().like(Opc::getOpc_name, whereJson.get("blurry")).or().like(Opc::getOpc_host, whereJson.get("blurry"));
        }
        wrapper.orderByDesc(Opc::getCreate_time);
        IPage<Opc> opcPage = opcMapper.selectPage(queryPage, wrapper);
        final JSONObject json = (JSONObject) JSON.toJSON(ConvertUtil.convertPage(opcPage, OpcDto.class));
        JSONArray newja = new JSONArray();
        JSONArray ja = json.getJSONArray("content");
        for (int i = 0; i < ja.size(); i++) {
            JSONObject jo = (JSONObject) ja.get(i);
            List<OpcPlc> plcList = new LambdaQueryChainWrapper<OpcPlc>(opcPlcMapper)
                    .eq(OpcPlc::getIs_active, CommonFinalParam.ONE)
                    .eq(OpcPlc::getIs_delete, "0")
                    .eq(OpcPlc::getOpc_server_id, jo.getString("opc_id"))
                    .list();
            if (plcList.size() > 0) {
                JSONArray children = new JSONArray();
                for (int j = 0; j < plcList.size(); j++) {
                    JSONObject opc_jo = (JSONObject) JSON.toJSON(plcList.get(j));
                    JSONObject new_jo = new JSONObject();
                    new_jo.put("opc_id", opc_jo.getString("plc_id"));
                    new_jo.put("opc_code", opc_jo.getString("plc_code"));
                    new_jo.put("opc_name", opc_jo.getString("plc_name"));
                    new_jo.put("opc_host", opc_jo.getString("plc_host"));
                    new_jo.put("plc_opc_name", jo.getString("opc_name"));
                    new_jo.put("opc_server_id", jo.getString("opc_id"));
                    //new_jo.put("remark",opc_jo.getString("remark",""));
                    new_jo.put("is_active", opc_jo.getString("is_active"));
                    new_jo.put("is_delete", opc_jo.getString("is_delete"));
                    new_jo.put("create_by", opc_jo.getString("create_by"));
                    new_jo.put("create_time", opc_jo.getString("create_time"));
                    new_jo.put("update_by", opc_jo.getString("update_by"));
                    new_jo.put("update_time", opc_jo.getString("update_time"));
                    new_jo.put("type", "plc");
                    children.add(new_jo);
                }
                jo.put("children", children);
            }
            jo.put("opc_flag", CommonFinalParam.ONE);
            jo.put("type", "server");
            newja.add(jo);
        }
        json.put("content", newja);
        log.info("json:" + json);
        return json;
    }

    @Override
    public List<OpcDto> queryAll(Map whereJson) {
        LambdaQueryWrapper<Opc> wrapper = new LambdaQueryWrapper<>();
        if (whereJson.get(BLURRY) != null) {
            wrapper.like(Opc::getOpc_code, whereJson.get("blurry")).or().like(Opc::getOpc_name, whereJson.get("blurry")).or().like(Opc::getOpc_host, whereJson.get("blurry"));
        }
        return ConvertUtil.convertList(opcMapper.selectList(wrapper), OpcDto.class);
    }


    @Override
    public OpcDto findByCode(String code) {
        Opc opc = new LambdaQueryChainWrapper<>(opcMapper)
                .eq(Opc::getOpc_code, code)
                .one();
        return ConvertUtil.convert(opc, OpcDto.class);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(OpcDto dto) {
        OpcDto entity = this.findById(dto.getOpc_id());
        if (entity == null) {
            throw new BadRequestException(LangProcess.msg("error_sysAuth"));
        }
        String currentUsername = SecurityUtils.getCurrentNickName();
        String now = DateUtil.now();
        dto.setUpdate_time(now);
        dto.setUpdate_by(currentUsername);
        Opc opc = ConvertUtil.convert(dto, Opc.class);
        opcMapper.updateById(opc);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteAll(String[] ids) {
        for (String opc_id : ids) {
            this.removeById(opc_id);
            LambdaQueryWrapper<OpcPlc> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(OpcPlc::getOpc_server_id, opc_id);
            opcPlcMapper.delete(wrapper);
        }
    }

    @Override
    public void download(List<OpcDto> all, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (OpcDto opc : all) {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("OPC编码", opc.getOpc_code());
            map.put("OPC名称", opc.getOpc_name());
            map.put("OPC地址", opc.getOpc_host());
            map.put("用户名", opc.getUser());
            map.put("密码", opc.getPassword());
            map.put("程序ID", opc.getProg_id());
            map.put("注册表ID", opc.getCls_id());
            map.put("domain", opc.getDomain());
            map.put("备注", opc.getRemark());
            map.put("是否启用", opc.getIs_active());
            map.put("是否删除", opc.getIs_delete());
            map.put("创建者", opc.getCreate_by());
            map.put("创建时间", opc.getCreate_time());
            map.put("修改者", opc.getUpdate_by());
            map.put("修改时间", opc.getUpdate_time());
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }

    @Override
    public JSONArray selectList() {
        List<Opc> opcList = new LambdaQueryChainWrapper<>(opcMapper)
                .eq(Opc::getIs_delete, "0")
                .eq(Opc::getIs_active, CommonFinalParam.ONE)
                .list();
        JSONArray result = new JSONArray();
        for (int i = 0; i < opcList.size(); i++) {
            JSONObject obj = (JSONObject) JSON.toJSON(opcList.get(i));
            JSONObject json = new JSONObject();
            json.put("opc_id", obj.getString("opc_id"));
            json.put("opc_code", obj.getString("opc_code"));
            json.put("opc_name", obj.getString("opc_name"));
            result.add(json);
        }
        return result;
    }

    @Override
    public OpcDto queryServerPlc(String opc_id) {
        OpcPlc opcPlc = new LambdaQueryChainWrapper<>(opcPlcMapper)
                .eq(OpcPlc::getOpc_server_id, opc_id)
                .one();
        JSONObject json = (JSONObject) JSON.toJSON(opcPlc);
        System.out.println("json:" + json);
        json.put("opc_code", json.get("plc_code"));
        json.put("opc_id", json.get("plc_id"));
        json.put("opc_name", json.get("plc_name"));
        json.put("opc_host", json.get("plc_host"));
        //json.put("hasChildren","false");
        json.put("type", "PLC");
        //json.put("children",null);
        final OpcDto obj = json.toJavaObject(OpcDto.class);
        return obj;
    }

    @Override
    public HashMap<String, String> getmeteal(Map whereJson) {
        HashMap<String, String> map = new HashMap<>();
        String host = (String) whereJson.get("opc_host");
        String user = (String) whereJson.get("user");
        String password = (String) whereJson.get("password");
        List<Map<String, String>> maps = ReadUtil.showAllOpcServer(host, user, password, "");
        return (HashMap<String, String>) maps.get(0);
    }

    @Override
    public void createPLC(Map map) {
        HashMap<String, String> plc_map = new HashMap<>();
        String now = DateUtil.now();
        plc_map.put("plc_id", IdUtil.simpleUUID());
        plc_map.put("plc_code", (String) map.get("plc_code"));
        plc_map.put("plc_name", (String) map.get("plc_name"));
        plc_map.put("plc_host", (String) map.get("plc_host"));
        plc_map.put("opc_server_id", (String) map.get("opc_server_id"));
        plc_map.put("remark", (String) map.get("remark"));
        plc_map.put("is_active", CommonFinalParam.ONE);
        plc_map.put("is_delete", "0");
        plc_map.put("create_by", SecurityUtils.getCurrentNickName());
        plc_map.put("create_time", now);
        OpcPlc entity = ConvertUtil.convert(plc_map, OpcPlc.class);
        opcPlcMapper.insert(entity);
    }

    @Override
    public void delPLC(Map map) {
        LambdaQueryWrapper<OpcPlc> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(OpcPlc::getPlc_id, map.get("opc_id"));
        opcPlcMapper.delete(wrapper);
    }

    @Override
    public void editPLC(JSONObject json) {
        String now = DateUtil.now();
        json.put("update_time", now);
        json.put("update_by", SecurityUtils.getCurrentNickName());
        OpcPlc opcPlc = JSON.toJavaObject(json, OpcPlc.class);
        opcPlcMapper.updateById(opcPlc);
    }
}
