package com.casic.missiles.modular.system.controller;

import com.baomidou.mybatisplus.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.casic.missiles.modular.system.constant.ModularDictConst;
import com.casic.missiles.modular.system.dto.DeviceDto;
import com.casic.missiles.modular.system.dto.DeviceSelectDto;
import com.casic.missiles.modular.system.enums.DeviceExportEnum;
import com.casic.missiles.modular.system.model.DeviceModels;
import com.casic.missiles.modular.system.service.IDeviceModelsService;
import com.casic.missiles.modular.system.service.IDeviceTypeService;
import com.casic.missiles.config.DeviceServerProperties;
import com.casic.missiles.core.base.controller.ExportController;
import com.casic.missiles.core.base.response.ErrorResponseData;
import com.casic.missiles.core.base.response.ResponseData;
import com.casic.missiles.core.base.response.SuccessResponseData;
import com.casic.missiles.core.common.annotion.BussinessLog;
import com.casic.missiles.core.common.annotion.Permission;
import com.casic.missiles.core.common.constant.factory.PageFactory;
import com.casic.missiles.core.common.service.ICommonPermissionService;
import com.casic.missiles.core.datascope.DataScope;
import com.casic.missiles.core.exception.GunsException;
import com.casic.missiles.core.exception.GunsExceptionEnum;
import com.casic.missiles.core.log.LogObjectHolder;
import com.casic.missiles.core.util.ToolUtil;
import com.casic.missiles.modular.system.constant.DeviceConst;
import com.casic.missiles.modular.system.dict.DeviceDict;
import com.casic.missiles.modular.system.dto.DeviceCodeSelectDto;
import com.casic.missiles.modular.system.model.Device;
import com.casic.missiles.modular.system.model.DeviceType;
import com.casic.missiles.modular.system.service.IDeviceService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.hswebframework.expands.office.excel.ExcelIO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.casic.missiles.modular.system.constant.DeviceConst.DEVICE_ADD_LOG_KEY;
import static com.casic.missiles.modular.system.constant.DeviceConst.DEVICE_QUERY_DEVICE_TYPE;

/**
 * 设备控制器
 *
 * @author dev
 * @Date 2019-05-23 18:07:55
 */
@Controller
@RequestMapping("/device")
@Api(value = "设备管理", description = "基础设备相关管理")
public class DeviceController extends ExportController {
    private static final Logger logger = LoggerFactory.getLogger(DeviceController.class);
    @Autowired
    private ICommonPermissionService permissionService;
    @Autowired
    private IDeviceService deviceService;
    @Autowired
    private DeviceServerProperties deviceServerProperties;

    @Autowired
    private IDeviceTypeService deviceTypeService;
    @Autowired
    private IDeviceModelsService deviceModelsService;

    @ApiOperation("获取设备列表")
    @RequestMapping(value = "/list")
    @ResponseBody
    public Object list(String keywords, String deviceType, String deptid, String beginTime, String endTime) {
        Page<DeviceDto> page = new PageFactory<DeviceDto>().defaultPage();
        //查询数据权限 使用默认DEPTID 字段
        DataScope dataScope = permissionService.getCurrUserDataScope();
        List<DeviceDto> list = deviceService.selectDataScopePage(dataScope, page, deviceType, deptid, beginTime, endTime, keywords);
        list.forEach(deviceDto -> {
            deviceDto.setBfztName(permissionService.getDictNameByCode(ModularDictConst.BFZT, deviceDto.getBfzt()));
            deviceDto.setOnlineStateName(permissionService.getDictNameByCode(ModularDictConst.ONLINESTATUS, deviceDto.getOnlineState()));
        });
        page.setRecords(list);
        return new SuccessResponseData(super.packForBT(page));
    }

    @ApiOperation("设备状态获取列表")
    @RequestMapping(value = "/listByConfig")
    @ResponseBody
    public ResponseData listByConfig(String deviceType, String configStatus) {

        DataScope dataScope = permissionService.getCurrUserDataScope();
            List<DeviceCodeSelectDto> list = deviceService.selectDevicesByConfig(dataScope, deviceType, configStatus);
        if (ToolUtil.isNotEmpty(list)) {
            list.forEach(deviceCodeSelectDto -> {
                deviceCodeSelectDto.setDeptName(permissionService.getDeptName(deviceCodeSelectDto.getDeptId()));
            });
        }
        return new SuccessResponseData(list);
    }


    @ApiOperation("获取设备类型列表")
    @GetMapping(value = "/type")
    @ResponseBody
    public Object type() {
        //设备类型列表查询
        List<DeviceType> list = deviceTypeService.selectList(null);
        List<DeviceSelectDto> selectDtos = new ArrayList<>();
        if (ToolUtil.isNotEmpty(list)) {
            list.forEach(deviceType -> {
                selectDtos.add(new DeviceSelectDto(deviceType.getTypeName(), deviceType.getId()));
            });
        }
        return ResponseData.success(selectDtos);
    }

    @ApiOperation("根据设备类型获取设备型号列表")
    @GetMapping(value = "/model")
    @ResponseBody
    public Object model(String deviceType) {
        //设备类型列表查询
        EntityWrapper<DeviceModels> query = new EntityWrapper<>();
        if (ToolUtil.isNotEmpty(deviceType))
            query.eq(DEVICE_QUERY_DEVICE_TYPE, deviceType);

        List<DeviceModels> list = deviceModelsService.selectList(query);
        List<DeviceSelectDto> selectDtos = new ArrayList<>();
        if (ToolUtil.isNotEmpty(list)) {
            list.forEach(deviceModels -> {
                selectDtos.add(new DeviceSelectDto(deviceModels.getModelName(), deviceModels.getId(), deviceModels.getDeviceType()));
            });
        }
        return ResponseData.success(selectDtos);
    }

    @ApiOperation("批量导入设备")
    @RequestMapping(value = "/batchImport", method = RequestMethod.POST)
    @Permission
    @ResponseBody
    public Object batchImport(@RequestParam("file") MultipartFile file) {
        List<Device> results = new ArrayList<>();
        //设置表头与字段映射,可通过反射获取
        Map<String, String> mapper = new HashMap<>();
        mapper.put("设备编号", "devcode");//判断唯一
        mapper.put("设备名称", "deviceName");
        mapper.put("设备类型", "deviceTypeName");//需要转换
        mapper.put("设备型号", "modelName");//需要转换
        mapper.put("闸井编号", "wellCode");//需要转换
        mapper.put("数据集中器编号", "concenCode");//需要转换
        mapper.put("设备安装时间", "installDateFmt");
        try {
            try (InputStream in = file.getInputStream()) {
                ExcelIO.read(in, mapper, Device.class, (row) -> {
                    //仅读取第一个sheet
                    if (row.getSheet() == 0) {
                        if (row.getResult() != null) {
                            Device device = row.getResult();
                            //过滤设备编号及设备名称都为空的数据 (判定为空行不导入该行)
                            if (!ToolUtil.isAllEmpty(device.getDevcode(), device.getDeviceName())) {
                                device.setValid(DeviceConst.YES);
                                device.setOnlineState(DeviceConst.YES);
                                results.add(device);
                            }
                        }
                    } else {
                        //其他sheet停止读取
                        logger.info("当前sheet" + row.getSheet() + ",停止读取");
                        row.shutdown();
                    }
                });

                List<String> list = deviceService.addDeviceBatch(results);

                if (!ToolUtil.isEmpty(list)) {
                    //获取第校验报错信息
                    return new ErrorResponseData(list.get(0));
                }

            }
        } catch (Exception e) {
            return catchMybatisPlusException(e, "导入设备失败");
        }

        return ResponseData.success();
    }

    @ApiOperation("设备列表导出")
    @RequestMapping(value = "/batchExport")
    @Permission
    @ResponseBody
    public void batchExport(HttpServletResponse response, String keywords, String deviceType, String deptid, String beginTime, String endTime) throws IOException {

        Page<DeviceDto> page = new PageFactory<DeviceDto>().defaultPage();
        page.setCurrent(1);
        page.setSearchCount(false);
        page.setSize(Integer.MAX_VALUE);
        DataScope dataScope = permissionService.getCurrUserDataScope();
        List<DeviceDto> list = deviceService.selectDataScopePage(dataScope, page, deviceType, deptid, beginTime, endTime, keywords);
        list.forEach(deviceDto -> {
            deviceDto.setBfztName(permissionService.getDictNameByCode(ModularDictConst.BFZT, deviceDto.getBfzt()));
            deviceDto.setOnlineStateName(permissionService.getDictNameByCode(ModularDictConst.ONLINESTATUS, deviceDto.getOnlineState()));
        });
        super.exportExcel(DeviceExportEnum.DEVICE_EXPORT, list, response);

    }

    /**
     * 新增
     */
    @RequestMapping(value = "/add")
    @Permission
    @BussinessLog(value = "添加设备", key = DEVICE_ADD_LOG_KEY, dict = DeviceDict.class)
    @ResponseBody
    public Object add(@Valid Device device, BindingResult result) {
        if (result.hasErrors()) {
            return ResponseData.error(result.getFieldErrors().get(0).getDefaultMessage());
        }

        try {
            deviceService.insert(device);
        } catch (Exception e) {
            GunsException gunsException = new GunsException(GunsExceptionEnum.REQUEST_NULL);
            String errorMsg = "设备添加失败";
            if (e instanceof DuplicateKeyException) {
                errorMsg = "设备编号重复";
            } else if (e instanceof GunsException) {
                GunsException gunException = (GunsException) e;
                errorMsg = gunException.getMessage();
            }
            logger.error("设备添加失败", e);
            gunsException.setMessage(errorMsg);
            throw gunsException;
        }

        return ResponseData.success();
    }

    private ResponseData catchMybatisPlusException(Exception e, String errorMsg) {
        if (e instanceof MybatisPlusException) {
            MybatisPlusException mybatisPlusException = (MybatisPlusException) e;
            String message = mybatisPlusException.getCause().getCause().getCause().getMessage();
            if (message.contains("Duplicate entry '")) {
                return new ErrorResponseData("设备编号重复:" + message.replaceAll("Duplicate entry '", "").replaceAll("' for key 'DEVCODE'", ""));
            }
        }
        logger.error(errorMsg, e);
        return new ErrorResponseData(errorMsg);
    }

    /**
     * 删除
     */
    @PostMapping(value = "/delete")
    @ResponseBody
    @Permission
    @BussinessLog(value = "删除设备信息")
    public Object delete(@RequestParam List<Long> ids) {
        deviceService.deleteByIds(ids);
        return ResponseData.success();
    }


    /**
     * 修改
     */
    @PostMapping(value = "/update")
    @ResponseBody
    @Permission
    @BussinessLog(value = "修改设备信息", key = DEVICE_ADD_LOG_KEY, dict = DeviceDict.class)
    public Object update(Device device) {
        if (ToolUtil.isEmpty(device.getId())) {
            throw new GunsException(GunsExceptionEnum.REQUEST_NULL);
        }
        Device oldDevice = this.deviceService.selectById(device.getId());
        LogObjectHolder.me().set(oldDevice);

        deviceService.updateById(device);
        return ResponseData.success();
    }


}
