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

import com.neusoft.smart.pos.dto.printer.redis.PrinterBean;
import com.neusoft.smart.pos.dto.printer.request.PostPrinterRequest;
import com.neusoft.smart.pos.dto.printer.request.PrinterQueryRequest;
import com.neusoft.smart.pos.dto.printer.request.PutPrinterRequest;
import com.neusoft.smart.pos.dto.printer.response.PostPrinterQueryResponse;
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.printer.constants.PrintConstants;
import com.neusoft.smart.pos.printer.constants.PrinterErrorCode;
import com.neusoft.smart.pos.printer.persistent.domain.*;
import com.neusoft.smart.pos.printer.persistent.ext.domain.PrinterDataQuery;
import com.neusoft.smart.pos.printer.repository.*;
import com.neusoft.smart.pos.printer.tasks.PrinterCreateOrUpdateTasks;
import com.neusoft.smart.pos.utils.RequestHeaderUtil;
import lombok.val;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundValueOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class PrinterServiceOther {
    
    @Autowired
    private PrinterInfoRepository printerInfoRepository;
    
    @Autowired
    private PrinterGoodsRefInfoRepository printerGoodsRefInfoRepository;
    
    @Autowired
    private PrinterRuleRefRepository printerRuleRefRepository;
    
    @Autowired
    private PrinterRuleAttributeRepository printerRuleAttributeRepository;
    
    @Autowired
    private PrinterTemplateRefRepository printerTemplateRefRepository;
    
    @Autowired
    private TaskExecutor taskExecutor;
    
    @Autowired
    private RedisTemplate redisTemplate;
    
    /**
     * @param postPrinterRequest
     */
    @Transactional
    public void create(PostPrinterRequest postPrinterRequest) {
        //保存打印机对象
        val printerInfo = new PrinterInfo();
        BeanUtils.copyProperties(postPrinterRequest, printerInfo);
//        printerInfo.setCreatedBy(RequestHeaderUtil.getUserId().toString());
        printerInfoRepository.create(printerInfo);
        //如果是中转设备,保存连接打印机
        if (PrintConstants.TRANSFER.getCode().equals(printerInfo.getDeviceType())) {
            if (null != postPrinterRequest.getLinkedPrinterIds()) {
                postPrinterRequest.getLinkedPrinterIds().forEach(linkedPrinterId -> {
                    PrinterInfo child = new PrinterInfo();
                    child.setParentId(printerInfo.getId());
                    child.setId(linkedPrinterId);
                    printerInfoRepository.updateSelective(child);
                });
            }
        }
        
        //保存打印机规则
        postPrinterRequest.getPrinterRules().forEach(rule -> {
            val printerRuleRef = new PrinterRuleRef();
            printerRuleRef.setPrinterId(printerInfo.getId());
            printerRuleRef.setRuleId(rule.getRuleId());
            printerRuleRef.setSortNo(rule.getSortNo());
            printerRuleRefRepository.create(printerRuleRef);
            rule.getRuleAttributes().forEach(attr -> {
                val printerRuleAttribute = new PrinterRuleAttribute();
                printerRuleAttribute.setPrinterRuleId(printerRuleRef.getId());
                printerRuleAttribute.setRuleId(rule.getRuleId());
                printerRuleAttribute.setAttributeId(attr.getAttributeId());
                printerRuleAttribute.setAttributeValue(attr.getAttributeValue());
                printerRuleAttributeRepository.create(printerRuleAttribute);
            });
        });
        //保存打印机模板
        postPrinterRequest.getPrinterTemplateIds().forEach(templateId -> {
            val printerTemplateRef = new PrinterTemplateRef();
            printerTemplateRef.setPrinterId(printerInfo.getId());
            printerTemplateRef.setTemplateId(templateId);
            printerTemplateRefRepository.create(printerTemplateRef);
        });
        //保存打印机和菜单或者菜单分类的关系
        if (null != postPrinterRequest.getPrinterGoodsRefs() && !postPrinterRequest.getPrinterGoodsRefs().isEmpty()) {
            val printerGoodsRefInfos = BeanUtil.parseList(postPrinterRequest.getPrinterGoodsRefs(), PrinterGoodsRefInfo.class);
            printerGoodsRefInfos.forEach(info -> {
                info.setPrinterId(printerInfo.getId());
                info.setOrgId(printerInfo.getOrgId());
                info.setShopId(printerInfo.getShopId());
            });
            printerGoodsRefInfoRepository.createBatch(printerGoodsRefInfos);
        }
        //调用处理缓存的服务
        val printerCreateOrUpdateTasks = new PrinterCreateOrUpdateTasks();
        printerCreateOrUpdateTasks.setPrinterId(printerInfo.getId());
        taskExecutor.getExecutorService().submit(printerCreateOrUpdateTasks);
    }
    
    /**
     * 更新
     *
     * @param putPrinterRequest
     */
    @Transactional
    public void update(PutPrinterRequest putPrinterRequest) {
        val printerInfo = printerInfoRepository.queryPrinterByPrinterId(putPrinterRequest.getId());
        if (null == printerInfo) {
            throw new BusinessCommonException(PrinterErrorCode.INVALIDATE_SN_ERROR);
        }
        BeanUtils.copyProperties(putPrinterRequest, printerInfo);
        printerInfoRepository.update(printerInfo);
        //如果是中转设备，处理下连接打印机
        if (PrintConstants.TRANSFER.getCode().equals(printerInfo.getDeviceType())) {
            val children = printerInfoRepository.queryPrinterByParentId(printerInfo.getId());
            children.forEach(oldChild -> {
                oldChild.setParentId(0l);
                printerInfoRepository.update(oldChild);
            });
            putPrinterRequest.getLinkedPrinterIds().forEach(newChildId -> {
                val child = printerInfoRepository.queryPrinterByPrinterId(newChildId);
                child.setParentId(printerInfo.getId());
                printerInfoRepository.update(child);
            });
        } else {
            //处理一下对应规则
            //记录一下就规则关系id,为了下边删除规则属性所用
            val ruleRefs = printerRuleRefRepository.queryPrinterRulesByPrinterId(printerInfo.getId());
            val oldRefIds = ruleRefs.parallelStream().map(PrinterRuleRef::getId).collect(Collectors.toList());
            //把旧的规则关系删了
            printerRuleRefRepository.deleteByPrinterId(printerInfo.getId());
            //把旧的规则属性值删了
            printerRuleAttributeRepository.deleteByRefIds(oldRefIds);
            //下边重新创建规则和对应属性值
            putPrinterRequest.getPrinterRules().forEach(rule -> {
                val printerRuleRef = new PrinterRuleRef();
                printerRuleRef.setPrinterId(printerInfo.getId());
                printerRuleRef.setRuleId(rule.getRuleId());
                printerRuleRef.setSortNo(rule.getSortNo());
                printerRuleRefRepository.create(printerRuleRef);
                rule.getRuleAttributes().forEach(attr -> {
                    val printerRuleAttribute = new PrinterRuleAttribute();
                    printerRuleAttribute.setRuleId(rule.getRuleId());
                    printerRuleAttribute.setPrinterRuleId(printerRuleRef.getId());
                    printerRuleAttribute.setAttributeId(attr.getAttributeId());
                    printerRuleAttribute.setAttributeValue(attr.getAttributeValue());
                    printerRuleAttributeRepository.create(printerRuleAttribute);
                });
            });
            //再处理一下菜单或者菜单分类对应关系
            //先删除就关系
            printerGoodsRefInfoRepository.deleteByPrinterId(printerInfo.getId());
            if (null != putPrinterRequest.getPrinterGoodsRefs() && !putPrinterRequest.getPrinterGoodsRefs().isEmpty()) {
                val printerGoodsRefInfos = BeanUtil.parseList(putPrinterRequest.getPrinterGoodsRefs(), PrinterGoodsRefInfo.class);
                printerGoodsRefInfos.forEach(info -> {
                    info.setPrinterId(printerInfo.getId());
                    info.setShopId(printerInfo.getShopId());
                    info.setOrgId(printerInfo.getOrgId());
                });
                printerGoodsRefInfoRepository.createBatch(printerGoodsRefInfos);
            }
            //处理下模板
            printerTemplateRefRepository.deleteByPrinterId(printerInfo.getId());
            putPrinterRequest.getPrinterTemplateIds().forEach(templateId -> {
                val printerTemplateRef = new PrinterTemplateRef();
                printerTemplateRef.setTemplateId(templateId);
                printerTemplateRef.setPrinterId(printerInfo.getId());
                printerTemplateRefRepository.create(printerTemplateRef);
            });
        }
        //调用处理缓存的服务
        val printerCreateOrUpdateTasks = new PrinterCreateOrUpdateTasks();
        printerCreateOrUpdateTasks.setPrinterId(printerInfo.getId());
        taskExecutor.getExecutorService().submit(printerCreateOrUpdateTasks);
    }
    
    
    /**
     * 修改打印机状态
     *
     * @param printerId
     * @param status
     */
    @Transactional
    public void changeStatus(Long printerId, String status) {
        val printerInfo = printerInfoRepository.queryPrinterByPrinterId(printerId);
        if (null == printerInfo) {
            throw new BusinessCommonException(PrinterErrorCode.INVALIDATE_SN_ERROR);
        }
        printerInfo.setPrinterStatus(status);
        printerInfoRepository.update(printerInfo);
        String sn = "@@";
        
        if (PrintConstants.TRANSFER.getCode().equals(printerInfo.getDeviceType())) {
            sn = printerInfo.getPrinterSn();
            val children = printerInfoRepository.queryPrinterByParentId(printerInfo.getId());
            children.forEach(child -> {
                child.setPrinterStatus(status);
                printerInfoRepository.update(child);
                BoundValueOperations<String, PrinterBean> boundValueOperations = redisTemplate.boundValueOps("printer_" + child.getId() + "_@@");
                PrinterBean printerBean = boundValueOperations.get();
                printerBean.setPrinterStatus(status);
                boundValueOperations.set(printerBean);
            });
        }
        BoundValueOperations<String, PrinterBean> boundValueOperations = redisTemplate.boundValueOps("printer_" + printerId + "_" + sn);
        PrinterBean printerBean = boundValueOperations.get();
        printerBean.setPrinterStatus(status);
        boundValueOperations.set(printerBean);
    }
    
    /**
     * 通过门店id和登录用户的集团id查询所有打印机和中转设备
     *
     * @param shopId
     * @return
     */
    public List<PostPrinterQueryResponse> getList(Integer shopId) {
        val printers = printerInfoRepository.queryAll(RequestHeaderUtil.getOrgId(), shopId);
        val responseMap = new HashMap<Long, PostPrinterQueryResponse>();
        printers.forEach(printer -> {
            if (PrintConstants.TRANSFER.getCode().equals(printer.getDeviceType()) || printer.getParentId().equals(0L)) {
                val postPrinterQueryResponse = BeanUtil.parse(printer, PostPrinterQueryResponse.class);
                responseMap.put(postPrinterQueryResponse.getId(), postPrinterQueryResponse);
            } else {
                if (!responseMap.containsKey(printer.getId())) {
                    val parentPrinter = responseMap.get(printer.getParentId());
                    parentPrinter.getLinkedPrinters().add(BeanUtil.parse(printer, PostPrinterQueryResponse.class));
                }
            }
        });
        return new ArrayList<>(responseMap.values());
    }
    
    
    public List<PostPrinterQueryResponse> queryPrinterList(PrinterQueryRequest printerDataQueryRequest) {
        List<PrinterInfo> result = printerInfoRepository.queryPrinterList(BeanUtil.parse(printerDataQueryRequest, PrinterDataQuery.class));
        List<PostPrinterQueryResponse> responseList = BeanUtil.parseList(result, PostPrinterQueryResponse.class);
        responseList.forEach(printer -> {
            if (PrintConstants.TRANSFER.getCode().equals(printer.getDeviceType())) {
                List<PrinterInfo> children = printerInfoRepository.queryPrinterByParentId(printer.getId());
                printer.setLinkedPrinters(BeanUtil.parseList(children, PostPrinterQueryResponse.class));
            }
        });
        return responseList;
    }
    
    public Integer queryPinterCount(PrinterQueryRequest printerDataQueryRequest) {
        return printerInfoRepository.queryPinterCount(BeanUtil.parse(printerDataQueryRequest, PrinterDataQuery.class));
    }
    
    
    public PostPrinterQueryResponse get(Long id) {
        PrinterInfo result = printerInfoRepository.queryPrinterByPrinterId(id);
        PostPrinterQueryResponse postPrinterQueryResponse = BeanUtil.parse(result, PostPrinterQueryResponse.class);
        List<PrinterInfo> children = printerInfoRepository.queryPrinterByParentId(id);
        if (!children.isEmpty()) {
            postPrinterQueryResponse.setLinkedPrinters(BeanUtil.parseList(children, PostPrinterQueryResponse.class));
        }
        return postPrinterQueryResponse;
    }
}
