package com.neusoft.smart.pos.device.service;

import com.neusoft.smart.pos.device.constants.DeviceErrorCode;
import com.neusoft.smart.pos.device.persistent.domain.AppProjectConfig;
import com.neusoft.smart.pos.device.persistent.domain.Device;
import com.neusoft.smart.pos.device.persistent.domain.DeviceAuthLicence;
import com.neusoft.smart.pos.device.persistent.domain.DeviceExample;
import com.neusoft.smart.pos.device.persistent.ext.domain.DeviceQuery;
import com.neusoft.smart.pos.device.persistent.repository.AppProjectConfigRepository;
import com.neusoft.smart.pos.device.persistent.repository.DeviceAuthLicenceRepository;
import com.neusoft.smart.pos.device.persistent.repository.DeviceRepository;
import com.neusoft.smart.pos.device.task.DeviceAppendTask;
import com.neusoft.smart.pos.device.task.DeviceModifyTask;
import com.neusoft.smart.pos.device.task.DeviceStatusTask;
import com.neusoft.smart.pos.device.task.DeviceStoreTask;
import com.neusoft.smart.pos.dto.device.request.DeviceQueryRequest;
import com.neusoft.smart.pos.dto.device.request.DeviceRequest;
import com.neusoft.smart.pos.dto.device.response.DeviceResponse;
import com.neusoft.smart.pos.dto.device.response.GetAppProjectConfigResponse;
import com.neusoft.smart.pos.dto.device.response.GetDeviceAuthLicenceResponse;
import com.neusoft.smart.pos.framework.exception.BusinessCommonException;
import com.neusoft.smart.pos.framework.task.TaskExecutor;
import com.neusoft.smart.pos.framework.utils.BeanUtil;
import com.neusoft.smart.pos.framework.utils.ExcelUtils;
import com.neusoft.smart.pos.redis.bean.DeviceInfo;
import com.neusoft.smart.pos.utils.RequestHeaderUtil;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.util.Pair;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Service
@Slf4j
public class DeviceService {
    
    @Autowired
    private DeviceRepository deviceRepository;
    
    @Autowired
    private DeviceAuthLicenceRepository deviceAuthLicenceRepository;
    
    @Autowired
    private AppProjectConfigRepository appProjectConfigRepository;
    
    @Autowired
    private TaskExecutor taskExecutor;
    
    
    @Autowired
    private RedisTemplate redisTemplate;
    
    /**
     * @param deviceRequest
     * @param isAddTask
     * @return
     */
    @Transactional
    public DeviceResponse create(DeviceRequest deviceRequest, Boolean isAddTask) {
        String regEx = "^[0-9]+\\.[0-9]+\\.[0-9]+$";
        // 编译正则表达式
        Pattern pattern = Pattern.compile(regEx);
        Matcher matcher = pattern.matcher(deviceRequest.getCurVersion());
        // 字符串是否与正则表达式相匹配
        if (!matcher.matches()) {
            throw new BusinessCommonException(DeviceErrorCode.VERSION_FORMAT_ERROR);
        }
        if (validateDuplicate(deviceRequest.getMacAddr(), deviceRequest.getSerialNo(), deviceRequest.getAlias(), null, deviceRequest.getOrganizationId())) {
            throw new BusinessCommonException(DeviceErrorCode.DEVICE_DUPLICATE);
        }
        
        Device device = new Device();
        BeanUtils.copyProperties(deviceRequest, device);
        device.setCreatedBy(RequestHeaderUtil.getUserId());
        device.setOrganizationId(RequestHeaderUtil.getOrgId());
        deviceRepository.create(device);
        device = deviceRepository.get(device.getId());
        DeviceResponse response = new DeviceResponse();
        BeanUtils.copyProperties(device, response);
        
        if (isAddTask) {
            DeviceAppendTask deviceAppendTask = new DeviceAppendTask();
            DeviceInfo deviceInfo = new DeviceInfo();
            BeanUtils.copyProperties(device, deviceInfo);
            deviceAppendTask.getDeviceInfo().add(deviceInfo);
            taskExecutor.getExecutorService().submit(deviceAppendTask);
        }
        return response;
    }
    
    
    /**
     * @param deviceRequestList
     * @return
     */
    @Transactional
    public List<DeviceResponse> create(List<DeviceRequest> deviceRequestList) {
        List<DeviceResponse> result = new ArrayList<>();
        DeviceAppendTask deviceAppendTask = new DeviceAppendTask();
        deviceRequestList.forEach(deviceRequest -> {
            try {
                if (StringUtils.isEmpty(deviceRequest.getMacAddr()) ||
                        StringUtils.isEmpty(deviceRequest.getSerialNo()) ||
                        StringUtils.isEmpty(deviceRequest.getCurVersion())) {
                    throw new Exception("序列号、mac地址和版本都不可为空");
                }
                DeviceResponse response = this.create(deviceRequest, false);
                DeviceInfo deviceInfo = new DeviceInfo();
                BeanUtils.copyProperties(response, deviceInfo);
                deviceAppendTask.getDeviceInfo().add(deviceInfo);
            } catch (Exception e) {
                DeviceResponse deviceResponse = new DeviceResponse();
                BeanUtils.copyProperties(deviceRequest, deviceResponse);
                deviceResponse.setNote(e.getMessage());
                result.add(deviceResponse);
            }
        });
        taskExecutor.getExecutorService().submit(deviceAppendTask);
        return result;
    }
    
    private Boolean validateDuplicate(String mac, String SN, String alias, Integer id, Integer orgId) {
        DeviceExample deviceExample = new DeviceExample();
        DeviceExample.Criteria criteria1 = deviceExample.createCriteria().andMacAddrEqualTo(mac).andStatusNotEqualTo(1);
        DeviceExample.Criteria criteria2 = deviceExample.or().andSerialNoEqualTo(SN).andStatusNotEqualTo(1);
        if (null != id) {
            criteria1.andIdNotEqualTo(id);
            criteria2.andIdNotEqualTo(id);
        }
        if (!StringUtils.isEmpty(alias)) {
            DeviceExample.Criteria criteria3 = deviceExample.or().andAliasEqualTo(alias).andStatusNotEqualTo(1).andOrganizationIdEqualTo(orgId);
            if (null != id) {
                criteria3.andIdNotEqualTo(id);
            }
        }
        Integer count = deviceRepository.queryCountByExample(deviceExample);
        return count > 0;
    }
//	/**
//	 * @param deviceRequestList
//	 * @return
//	 */
//	@Transactional
//	public List<DeviceResponse> create(List<DeviceRequest> deviceRequestList) {
//		List<DeviceResponse> result = new ArrayList<>();
//		DeviceAppendTask deviceAppendTask = new DeviceAppendTask();
//		try {
//			Date date = new Date();
//			deviceRequestList.forEach(deviceRequest -> {
//				deviceRequest.setCreatedBy(0);
//				deviceRequest.setCreatedDate(date);
//				deviceRequest.setStatus(0);
//				deviceRequest.setOrganizationId(0);
//				deviceRequest.setLastModifiedBy(0);
//				deviceRequest.setLastModifiedDate(date);
//			});
//			deviceRepository.batchCreate(BeanUtil.parseList(deviceRequestList, Device.class));
//			deviceAppendTask.getDeviceInfo().addAll(BeanUtil.parseList(deviceRequestList, DeviceInfo.class));
//			taskExecutor.getExecutorService().submit(deviceAppendTask);
//		} catch (Exception e) {
//			//失败了 就全部传回去 具体哪个失败了 分辨不出来
////			result.addAll(BeanUtil.parseList(deviceRequestList, DeviceResponse.class));
//			throw new BusinessCommonException(DeviceErrorCode.DEVICE_BATCH_CREATE_ERROR);
//		}
//		return result;
//	}
    
    /**
     * @param deviceRequest
     */
    @Transactional
    public void update(DeviceRequest deviceRequest) {
        Device device = deviceRepository.get(deviceRequest.getId());
        if (null == device) {
            throw new BusinessCommonException(DeviceErrorCode.DEVICE_NOT_FOUND_ERROR);
        }
        if (validateDuplicate(deviceRequest.getMacAddr(), deviceRequest.getSerialNo(), deviceRequest.getAlias(), deviceRequest.getId(), deviceRequest.getOrganizationId())) {
            throw new BusinessCommonException(DeviceErrorCode.DEVICE_DUPLICATE);
        }
        BeanUtils.copyProperties(deviceRequest, device);
//		device.setCreatedBy(null);
//		device.setCreatedDate(null);
        device.setLastModifiedBy(RequestHeaderUtil.getUserId());
        device.setLastModifiedDate(new Date());
        deviceRepository.update(device);
        //更新之后 创建一个修改任务
        //获取一下最新的设备数据
        device = deviceRepository.get(deviceRequest.getId());
        DeviceModifyTask deviceModifyTask = new DeviceModifyTask();
        DeviceInfo deviceInfo = new DeviceInfo();
        BeanUtils.copyProperties(device, deviceInfo);
        deviceModifyTask.setDeviceInfo(deviceInfo);
        taskExecutor.getExecutorService().submit(deviceModifyTask);
    }
    
    @Transactional
    public void updateSelective(DeviceRequest deviceRequest) {
        deviceRepository.update(BeanUtil.parse(deviceRequest, Device.class));
    }
    
    /**
     * @param deviceQueryRequest
     * @return
     */
    public List<DeviceResponse> getList(DeviceQueryRequest deviceQueryRequest) {
        List<Device> poList = deviceRepository.getList(BeanUtil.parse(deviceQueryRequest, DeviceQuery.class));
        return BeanUtil.parseList(poList, DeviceResponse.class);
    }
    
    /**
     * @param deviceQueryRequest
     * @return
     */
    public Integer getCount(DeviceQueryRequest deviceQueryRequest) {
        return deviceRepository.getCount(BeanUtil.parse(deviceQueryRequest, DeviceQuery.class));
    }
    
    /**
     * @param file
     * @return
     * @throws Exception
     */
    public List<DeviceResponse> parseDeviceFromFile(MultipartFile file) {
        List<String[]> data = this.parseFile(file);
        List<DeviceResponse> result = new ArrayList<>();
        
        data.forEach(item -> {
            DeviceResponse deviceResponse = new DeviceResponse();
            deviceResponse.setSerialNo(item[0]);
            deviceResponse.setMacAddr(item[1]);
            deviceResponse.setManufacturer(item[2]);
            deviceResponse.setDeviceType(item[3]);
            deviceResponse.setDeviceModel(item[4]);
            deviceResponse.setCurVersion(item[5]);
            deviceResponse.setRegion(item[6]);
            deviceResponse.setCustomer(item[7]);
            deviceResponse.setDepartment(item[8]);
            deviceResponse.setAlias(item[9]);
            result.add(deviceResponse);
        });
        return result;
    }
    
    /**
     * @param deviceIds
     * @param status
     */
    @Transactional
    public Pair<List<Integer>, List<Integer>> updateStatus(List<Integer> deviceIds, Integer status) {
        //TODO 根据登录用户 查询一下是否是有权限修改的机具 暂时不知道如何获得用户相关数据
        //批量更新
//		Device device = new Device();
//		device.setStatus(status);
//		if(status == 1) {
//			device.setStoreId(0);
//		}
//		DeviceExample deviceExample = new DeviceExample();
//		deviceExample.createCriteria().andIdIn(deviceIds);
//		deviceRepository.batchUpdate(device, deviceExample);
        List<Integer> orgIds = new ArrayList<>();
        List<Integer> storeIds = new ArrayList<>();
        deviceIds.forEach(id -> {
            Device device = deviceRepository.get(id);
            storeIds.add(device.getStoreId());
            orgIds.add(device.getOrganizationId());
            device.setId(id);
            device.setStatus(status);
            if (status == 1) {
                device.setStoreId(null);
            }
            deviceRepository.updateWithNull(device);
        });
        DeviceStatusTask deviceStatusTask = new DeviceStatusTask();
        deviceStatusTask.setDeviceIds(deviceIds);
        deviceStatusTask.setStatus(status);
        taskExecutor.getExecutorService().submit(deviceStatusTask);
        return Pair.of(orgIds, storeIds);
    }
    
    /**
     * 设置门店id
     *
     * @param deviceIds
     * @param storeId
     */
    @Transactional
    public void setStoreId(List<Integer> deviceIds, Integer storeId) {
        DeviceQuery deviceQuery = new DeviceQuery();
        deviceQuery.setStoreIds(Collections.singletonList(storeId));
        deviceQuery.setIsPage(false);
        deviceQuery.setExcludeDeleted(true);
        List<Device> deviceList = deviceRepository.getList(deviceQuery);
        if (!deviceList.isEmpty()) {
            deviceList.forEach(device -> {
                device.setStoreId(null);
                deviceRepository.updateWithNull(device);
            });
        }
        if (null != deviceIds && !deviceIds.isEmpty()) {
            deviceRepository.setStoreId(deviceIds, storeId);
        }
        DeviceStoreTask deviceStoreTask = new DeviceStoreTask();
        deviceStoreTask.setDeviceIds(deviceIds);
        deviceStoreTask.setStoreId(storeId);
        taskExecutor.getExecutorService().submit(deviceStoreTask);
    }
    
    /**
     * @param orgId
     * @param storeId
     */
    public void deleteAllByOrgIdOrStoreId(Integer orgId, Integer storeId) {
        DeviceExample deviceExample = new DeviceExample();
        DeviceExample.Criteria criteria = deviceExample.createCriteria();
        criteria.andOrganizationIdEqualTo(orgId);
        if (null != storeId) {
            criteria.andStoreIdEqualTo(storeId);
        }
        Device device = new Device();
        device.setStatus(1);
        deviceRepository.batchUpdate(device, deviceExample);
    }
    
    /**
     * 数据库到redis
     */
    public void loadData2Redis() {
        redisTemplate.delete("deviceVersionsMap");
        redisTemplate.delete("deviceVersionsMapWithSn");
        DeviceQuery deviceQuery = new DeviceQuery();
        deviceQuery.setIsPage(false);
        List<Device> list = deviceRepository.getList(deviceQuery);
        DeviceAppendTask deviceAppendTask = new DeviceAppendTask();
        list.forEach(aDevice -> {
            DeviceInfo deviceInfo = new DeviceInfo();
            BeanUtils.copyProperties(aDevice, deviceInfo);
            deviceAppendTask.getDeviceInfo().add(deviceInfo);
        });
        taskExecutor.getExecutorService().submit(deviceAppendTask);
    }
    
    /**
     * @param file
     * @return
     * @throws Exception
     */
    private List<String[]> parseFile(MultipartFile file) {
        val list = new ArrayList<String[]>();
        try (//新建WorkBook
             val wb = WorkbookFactory.create(file.getInputStream());) {
            //获取Sheet（工作薄）
            val sheet = wb.getSheetAt(0);
            //开始行数
            int firstRowNum = sheet.getFirstRowNum();
            //结束行数
            int lastRowNum = sheet.getLastRowNum();
            
            if (firstRowNum == lastRowNum) {
                throw new BusinessCommonException(DeviceErrorCode.EMPTY_EXCEL);
            } else {
                val firstRow = sheet.getRow(0);
                val firstCellNum = firstRow.getFirstCellNum();
                val lastCellNum = firstRow.getLastCellNum();
                
                for (int j = firstRowNum + 1; j <= lastRowNum; j++) {
                    //获取一行
                    Row row = sheet.getRow(j);
                    if (row != null && row.getFirstCellNum() != row.getLastCellNum()) {
                        String[] value = new String[lastCellNum];
                        for (int k = firstCellNum; k < lastCellNum; k++) {
                            //获取一个单元格
                            Cell cell = row.getCell(k);
                            if (cell == null) {
                                value[k] = null;
                                continue;
                            }
                            cell.setCellType(Cell.CELL_TYPE_STRING);
                            String content = cell.getStringCellValue();
                            value[k] = content;
                        }
                        list.add(value);
                    }
                }
                
            }
        } catch (IOException | InvalidFormatException e) {
            throw new BusinessCommonException(DeviceErrorCode.PARSE_EXCEL_ERROR);
        }
        return list;
    }
    
    public void export(DeviceQueryRequest deviceQueryRequest, OutputStream os) throws Exception {
        switch (RequestHeaderUtil.getRole()) {
            case "admin":
                deviceQueryRequest.setOrganizationId(RequestHeaderUtil.getOrgId());
                break;
            case "user":
                deviceQueryRequest.setStoreIds(RequestHeaderUtil.getStoreIds());
                break;
            default:
            
        }
        deviceQueryRequest.setIsPage(false);
        List<Device> poList = deviceRepository.getList(BeanUtil.parse(deviceQueryRequest, DeviceQuery.class));
        List<String> fieldNames = Arrays.asList("序列号", "MAC地址", "厂商", "设备", "型号", "版本号", "区域", "客户", "部门", "设备状态", "别名");
        
        List<List<Object>> fieldData = poList.stream().map(device -> {
            List<Object> objectList = new ArrayList<>();
            Integer status = device.getStatus();
            String str = "正常";
            switch (status) {
                case 0:
                    str = "正常";
                    break;
                case 1:
                    str = "删除";
                    break;
                case 2:
                    str = "停用";
                    break;
            }
            objectList.addAll(Arrays.asList(device.getSerialNo(), device.getMacAddr(), device.getManufacturer(), device.getDeviceType(), device.getDeviceModel(), device.getCurVersion(),
                    device.getRegion(), device.getCustomer(), device.getDepartment(), str, device.getAlias()));
            return objectList;
        }).collect(Collectors.toList());
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ExcelUtils.exportExcel(fieldNames, fieldData, outputStream);
        os.write(outputStream.toByteArray());
        os.flush();
        os.close();
    }
    
    /**
     * 人证通设备授权信息查询方法
     * @param serialNo
     * @return
     */
    public GetDeviceAuthLicenceResponse queryDeviceAuthLicence(String serialNo){
        if(StringUtils.isEmpty(serialNo)){
            throw new BusinessCommonException(DeviceErrorCode.DEVICE_SN_EMPTY);
        }
        DeviceAuthLicence deviceAuthLicence = deviceAuthLicenceRepository.queryDeviceAuthLicenceBySn(serialNo);
       if(deviceAuthLicence == null){
           throw new BusinessCommonException(DeviceErrorCode.DEVICE_AUTH_LICENCE_EMPTY);
       }
        GetDeviceAuthLicenceResponse deviceAuthLicenceResponse = new GetDeviceAuthLicenceResponse();
        BeanUtils.copyProperties(deviceAuthLicence,deviceAuthLicenceResponse);
        return deviceAuthLicenceResponse;
    }
    
    /**
     * 应用配置信息信息查询方法
     * @param serialNo
     * @return
     */
    public GetAppProjectConfigResponse queryAppProjectConfig(String serialNo,String appId){
        if(StringUtils.isEmpty(serialNo)){
            throw new BusinessCommonException(DeviceErrorCode.DEVICE_SN_EMPTY);
        }
        if(StringUtils.isEmpty(appId)){
            throw new BusinessCommonException(DeviceErrorCode.APP_ID_EMPTY);
        }
        AppProjectConfig appProjectConfig = appProjectConfigRepository.queryAppProjectConfig(serialNo,appId);
        if(appProjectConfig == null){
            throw new BusinessCommonException(DeviceErrorCode.APP_PROJECT_CONFIG_EMPTY);
        }
        GetAppProjectConfigResponse appProjectConfigResponse = new GetAppProjectConfigResponse();
        BeanUtils.copyProperties(appProjectConfig,appProjectConfigResponse);
        return appProjectConfigResponse;
    }
}
