package cn.fastfun.service.impl;

import cn.fastfun.controller.param.*;
import cn.fastfun.service.AppDeviceLogService;
import cn.fastfun.service.AppDeviceService;
import cn.fastfun.service.UtilService;
import cn.fastfun.service.entity.AppDevice;
import cn.fastfun.service.entity.AppDeviceLog;
import cn.fastfun.service.entity.AppImeiHistory;
import cn.fastfun.util.ObjectUtil;
import com.bridge.dto.ApiDTO;
import com.bridge.dto.ApiPageDTO;
import com.bridge.dto.QueryParam;
import com.bridge.dto.QueryParamExp;
import com.bridge.exception.ApiRuntimeException;
import com.bridge.service.JpaService;
import com.bridge.service.impl.JpaServiceImp;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.models.auth.In;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.BooleanUtils;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.annotation.Resource;
import javax.persistence.Query;
import javax.transaction.Transactional;
import java.math.BigInteger;
//import java.sql.Timestamp;
import java.sql.Timestamp;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;

@Slf4j
@Service
public class AppDeviceLogServiceImpl extends JpaServiceImp<AppDeviceLog, String> implements AppDeviceLogService {

    @Resource
    AppDeviceService appDeviceService;

    @Resource
    AppDeviceLogService appDeviceLogService;

    @Resource
    UtilService utilService;

    @Resource
    JdbcTemplate jdbcTemplate;

    //业务类
    @Resource(name = "appImeiHistoryService")
    JpaService<AppImeiHistory, String> appImeiHistoryService;

    @Override
    @Transactional
    public void putInStorage(LibraryInFormParam param) {
        List<AppDevice> deviceList = appDeviceService.findAll(QueryParamExp.in("sn", param.getSn().toArray(new String[]{})));
        param.setSn(new ArrayList<>());
        deviceList.forEach(p -> param.getSn().add(p.getSn()));
        if (!CollectionUtils.isEmpty(param.getSn())) {
            // 查询当前操作id的最大值
            StringBuffer sql = new StringBuffer();
            sql.append("SELECT COALESCE(MAX(operate_id),0) as max_opid from app_device_log where operate_id is not null");
            log.info("SQL: {}", sql.toString());
            ApiPageDTO page = appDeviceLogService.getListBySQL(sql.toString(), new HashMap<>(), new QueryParam());
            List<Map<String, Object>> data = (List<Map<String, Object>>) page.getData();
            BigInteger operateID = (BigInteger) data.get(0).get("max_opid");
            operateID = operateID.add(BigInteger.valueOf(1));
            Date time = new Date();
            BigInteger finalOperateID = operateID;

            param.getSn().forEach(p -> {
                String batchNum;
                AppDevice appDevice = appDeviceService.getOne(QueryParamExp.eq("sn", p));
                if (null == appDevice) throw new ApiRuntimeException("设备信息不存在!");
                batchNum = appDevice.getBatchNum();
                if (appDevice.getStatus() < 1) {
                    appDevice.setStatus(1); // 已入库
                    Map<String, Boolean> checkRes = appDeviceLogService.selfCheck(p);
                    appDevice.setCheckStatus(BooleanUtils.toInteger(checkRes.get("checkResult"))); //自检
                    appDevice.setCheckStatusDataConnect(BooleanUtils.toInteger(checkRes.get("checkDataConnectResult"))); //自检
                    appDevice.setCheckStatusLocation(BooleanUtils.toInteger(checkRes.get("checkLocationResult"))); //自检
                    appDevice.setCheckStatusLock(BooleanUtils.toInteger(checkRes.get("checkLockResult"))); //自检
                    appDevice.setCheckStatusFault(BooleanUtils.toInteger(checkRes.get("checkFaultResult"))); //自检
                    appDevice.setCheckStatusVoltage(BooleanUtils.toInteger(checkRes.get("checkVoltageResult"))); //自检
                    //TODO 发送解锁指令
                    appDevice.setInstorageTime(time);
                    appDeviceService.save(appDevice);

                    AppDeviceLog appDeviceLog = new AppDeviceLog(p, appDevice.getImei()).toInStorage(time, batchNum, finalOperateID);
                    appDeviceLog.setOperator(utilService.getUserName());
                    save(appDeviceLog); // 记录入库日志
                } else if (deviceList.size() == 1) {  //如果只有1个,认为是单个入库,检测是否重复入库;批次入库只跳过
                    throw new ApiRuntimeException(p + "设备已入库,不能重复入库!");
                }
            });
        } else {
            throw new ApiRuntimeException("设备未录入!");
        }
    }

    @Override
    @Transactional
    public Map<String, Boolean> selfCheck(String sn) {
        Map<String, Boolean> res = new HashMap<>();
        Boolean checkResult = true;
        Boolean checkDataConnectResult = true;
        Boolean checkLocationResult = true;
        Boolean checkLockResult = true;
        Boolean checkFaultResult = true;
        Boolean checkVoltageResult = true;

        Map<String, Object> bmsData = new HashMap<>();
        Map<String, Object> gpsData = new HashMap<>();
        try {
            bmsData = jdbcTemplate.queryForMap("select devcode,error_code, locked_state, status_time, cell_voltages from ff_battery_status where devcode='" + sn + "'");
        } catch (EmptyResultDataAccessException e) {
            bmsData.put("devcode", null);
        }
        try {
            gpsData = jdbcTemplate.queryForMap("select devcode from ff_location where devcode='" + sn + "'");
        } catch (EmptyResultDataAccessException e) {
            gpsData.put("devcode", null);
        }
        if (StringUtils.isEmpty(bmsData.get("devcode"))) {
            checkLockResult = false;
            checkFaultResult = false;
            checkVoltageResult = false;
            checkDataConnectResult = false;
        } else {
            if (StringUtils.isEmpty(bmsData.get("locked_state"))) {
                checkFaultResult = true;
            } else {
                //锁定 0=解锁,1=锁定
                if (bmsData.get("locked_state").equals(0)) {
                    checkFaultResult = true;
                }
            }
            if (StringUtils.isEmpty(bmsData.get("error_code"))) {
                checkFaultResult = true;
            } else {
                if (bmsData.get("error_code").equals(0)) {
                    checkFaultResult = true;
                }
            }
            List<Double> voltage = ObjectUtil.StringToArrayList((String) bmsData.get("cell_voltages"), ",");
            if (!StringUtils.isEmpty(bmsData.get("cell_voltages")) && (Collections.max(voltage) > 4.5 || Collections.min(voltage) < 2.5)) {
                checkVoltageResult = false;
            }

            Calendar cal = Calendar.getInstance();
            cal.setTime(new Date());
            Long time1 = cal.getTimeInMillis();
            cal.setTime((Date) bmsData.get("status_time"));
            Long time2 = cal.getTimeInMillis();
            if (!StringUtils.isEmpty(bmsData.get("status_time")) && (time1 - time2) / 1000.0 / 3600 > 6) {
                checkDataConnectResult = false;
            }
            new Timestamp(System.currentTimeMillis());
        }
        if (!StringUtils.isEmpty(gpsData.get("devcode"))) {
            checkLocationResult = false;
        }

        checkResult = checkDataConnectResult && checkLocationResult && checkLockResult && checkFaultResult && checkVoltageResult;
        res.put("checkResult", checkResult);
        res.put("checkDataConnectResult", checkDataConnectResult);
        res.put("checkLocationResult", checkLocationResult);
        res.put("checkLockResult", checkLockResult);
        res.put("checkFaultResult", checkFaultResult);
        res.put("checkVoltageResult", checkVoltageResult);
        return res;
    }

    @Override
    @Transactional
    public void transfer(TransferFormParam param) {
        if (CollectionUtils.isEmpty(param.getSn()) && !CollectionUtils.isEmpty(param.getBatchNum())) {
            List<AppDevice> deviceList = appDeviceService.findAll(QueryParamExp.in("operateID", param.getBatchNum().toArray(new Integer[]{})));
            param.setSn(new ArrayList<>());
            deviceList.forEach(p -> param.getSn().add(p.getSn()));
        }

        if (!CollectionUtils.isEmpty(param.getSn())) {
            // 查询当前操作id的最大值
            StringBuffer sql = new StringBuffer();
            sql.append("SELECT COALESCE(MAX(operate_id),0) as max_opid from app_device_log where operate_id is not null");
            log.info("SQL: {}", sql.toString());
            ApiPageDTO page = appDeviceLogService.getListBySQL(sql.toString(), new HashMap<>(), new QueryParam());
            List<Map<String, Object>> data = (List<Map<String, Object>>) page.getData();
            BigInteger operateID = (BigInteger) data.get(0).get("max_opid");
            operateID = operateID.add(BigInteger.valueOf(1));
            Date time = new Date();

            BigInteger finalOperateID = operateID;
            //批量调拨时,若有不符合调拨条件的电池,则停止本次批量调拨

            param.getSn().forEach(p -> {
                AppDevice appDevice = appDeviceService.getOne(QueryParamExp.eq("sn", p));
                if (null == appDevice) {
                    throw new ApiRuntimeException(p + "设备信息不存在!");
                }
                // @TODO: 自建不通过
//                if (1 != appDevice.getStatus() && 2 != appDevice.getStatus()) {
//                    throw new ApiRuntimeException(p + "不是入库状态,不能调拨!");
//                }
//                if (1 != appDevice.getCheckStatus()) {
//                    throw new ApiRuntimeException(p + "自检未通过,不能调拨!");
//                }
            });
            param.getSn().forEach(p -> {
                String batchNum;
                AppDevice appDevice = appDeviceService.getOne(QueryParamExp.eq("sn", p));
                batchNum = appDevice.getBatchNum();
                // 将可调拨的电池进行调拨
                if (1 == appDevice.getStatus()) {

                    appDevice.setStatus(2); // 已划拨
                    appDevice.setTransferTime(time);
                    appDevice.setOwnerId(param.getCustomId()); // 设置归属
                    appDevice.setCustomer(param.getCustomId()); // 设置归属
                    appDevice.setTfDescribe(param.getDescribe());
                    appDevice.setTfUsed(param.getUsed());
                    appDeviceService.save(appDevice);

                    AppDeviceLog appDeviceLog = new AppDeviceLog(p, appDevice.getImei()).toTransfer(param, time, batchNum, finalOperateID);
                    appDeviceLog.setOperator(utilService.getUserName());
                    appDeviceLog.setOutCustomId(param.getCustomId());
                    save(appDeviceLog); // 记录划拨日志
                } else {
                    throw new ApiRuntimeException(p + "不是入库状态或自检未通过,不能调拨!");
                }
            });
        }
    }

    @Override
    @Transactional
    public void transferBack(TransferFormParam param) {
        AppDevice appDevice = appDeviceService.getOne(QueryParamExp.eq("sn", param.getSn().get(0)));
        // 查询当前操作id的最大值
        StringBuffer sql = new StringBuffer();
        sql.append("SELECT COALESCE(MAX(operate_id),0) as max_opid from app_device_log where operate_id is not null");
        log.info("SQL: {}", sql.toString());
        ApiPageDTO page = appDeviceLogService.getListBySQL(sql.toString(), new HashMap<>(), new QueryParam());
        List<Map<String, Object>> data = (List<Map<String, Object>>) page.getData();
        BigInteger operateID = (BigInteger) data.get(0).get("max_opid");
        operateID = operateID.add(BigInteger.valueOf(1));
        Date time = new Date();

        BigInteger finalOperateID = operateID;
        String batchNum;
        if (null == appDevice) throw new ApiRuntimeException("设备信息不存在!");
        if (3 != appDevice.getStatus()) throw new ApiRuntimeException("设备不是出库状态!");
        batchNum = appDevice.getBatchNum();
        appDevice.setInstorageTime(time);
        appDevice.setStatus(1); // 已入库
        appDevice.setTransferBackTime(time);
        appDeviceService.save(appDevice);

        AppDeviceLog appDeviceLog = new AppDeviceLog(appDevice.getSn(), appDevice.getImei()).transferBack(param, time, batchNum, finalOperateID);
        appDeviceLog.setOperator(utilService.getUserName());
        save(appDeviceLog); // 记录调回日志
    }

    @Override
    @Transactional
    public void outStorage(LibraryOutFormParam param) {
        if (CollectionUtils.isEmpty(param.getSn()) && !CollectionUtils.isEmpty(param.getBatchNum())) {
            List<AppDevice> deviceList = appDeviceService.findAll(QueryParamExp.in("operateID", param.getBatchNum().toArray(new Integer[]{})));
            param.setSn(new ArrayList<>());
            deviceList.forEach(p -> param.getSn().add(p.getSn()));
        }

        if (!CollectionUtils.isEmpty(param.getSn())) {
            // 查询当前操作id的最大值
            StringBuffer sql = new StringBuffer();
            sql.append("SELECT COALESCE(MAX(operate_id),0) as max_opid from app_device_log where operate_id is not null");
            log.info("SQL: {}", sql.toString());
            ApiPageDTO page = appDeviceLogService.getListBySQL(sql.toString(), new HashMap<>(), new QueryParam());
            List<Map<String, Object>> data = (List<Map<String, Object>>) page.getData();
            BigInteger operateID = (BigInteger) data.get(0).get("max_opid");
            operateID = operateID.add(BigInteger.valueOf(1));
            Date time = new Date();

            //批量出库时,若有不符合出库条件的电池,则停止本次批量出库
            param.getSn().forEach(p -> {
                AppDevice appDevice = appDeviceService.getOne(QueryParamExp.eq("sn", p));
                if (null == appDevice) {
                    throw new ApiRuntimeException(p + "设备信息不存在!");
                }
                if (2 != appDevice.getStatus() && 3 != appDevice.getStatus()) {
                    throw new ApiRuntimeException(p + "不是调拨状态,不能出库!");
                }
            });
            BigInteger finalOperateID = operateID;
            param.getSn().forEach(p -> {
                String batchNum;
                AppDevice appDevice = appDeviceService.getOne(QueryParamExp.eq("sn", p));

                // 将可出库的电池出库
                if (2 == appDevice.getStatus()) {

                    batchNum = appDevice.getBatchNum();
                    appDevice.setOutstorageTime(time);
                    appDevice.setStatus(3); // 已出库
                    appDeviceService.save(appDevice);
                    AppDeviceLog appDeviceLog = new AppDeviceLog(p, appDevice.getImei()).outStorage(param, time, batchNum, finalOperateID);
                    appDeviceLog.setOperator(utilService.getUserName());
                    save(appDeviceLog); // 记录出库日志
                } else {
                    throw new ApiRuntimeException(p + "不是调拨状态,不能出库!");
                }
            });
        }
    }

    @Override
    @Transactional
    public void handle(HandelFormParam param) {
        // 查询当前操作id的最大值
        StringBuffer sql = new StringBuffer();
        sql.append("SELECT COALESCE(MAX(operate_id),0) as max_opid from app_device_log where operate_id is not null");
        log.info("SQL: {}", sql.toString());
        ApiPageDTO page = appDeviceLogService.getListBySQL(sql.toString(), new HashMap<>(), new QueryParam());
        List<Map<String, Object>> data = (List<Map<String, Object>>) page.getData();
        BigInteger operateID = (BigInteger) data.get(0).get("max_opid");
        operateID = operateID.add(BigInteger.valueOf(1));
        Date time = new Date();

        BigInteger finalOperateID = operateID;
        param.getSn().forEach(p -> {
            String batchNum;
            AppDevice appDevice = appDeviceService.getOne(QueryParamExp.eq("sn", p));
            if (null == appDevice) throw new ApiRuntimeException("设备信息不存在!");
            if (1 != appDevice.getStatus()) throw new ApiRuntimeException("设备不是入库状态!");
            if (StringUtils.isEmpty(appDevice.getTransferTime())) throw new ApiRuntimeException("设备未被调拨过!");
            batchNum = appDevice.getBatchNum();
            appDevice.setHandleTime(time);
            appDevice.setStatus(4); // 处置
            appDeviceService.save(appDevice);
            //TODO 发送上锁指令
            AppDeviceLog appDeviceLog = new AppDeviceLog(p, appDevice.getImei()).toHandle(param, time, batchNum, finalOperateID);
            appDeviceLog.setOperator(utilService.getUserName());
            save(appDeviceLog); // 记录处置日志
        });
    }

    /**
     * 获取客户列表
     *
     * @return java.util.List<java.util.Map < java.lang.String, java.lang.Object>>
     */
    @Override
    public List<Map<String, Object>> getCustomList() {
        StringBuilder sql = new StringBuilder();
        sql.append("SELECT id,organ_code,title from app_custom where organ_code is not null");
        log.info("SQL: {}", sql.toString());
        List<Map<String, Object>> mapList = this.getListBySQL(sql.toString(), new HashMap<>());
        return mapList;
    }
}