package com.hfkj.service.meal.impl;

import com.hfkj.common.QRCodeGenerator;
import com.hfkj.common.exception.BaseException;
import com.hfkj.common.exception.ErrorCode;
import com.hfkj.common.exception.ErrorHelp;
import com.hfkj.common.exception.SysCode;
import com.hfkj.common.utils.DateUtil;
import com.hfkj.common.utils.GenerateUtil;
import com.hfkj.common.utils.IDGenerator;
import com.hfkj.config.CommonSysConst;
import com.hfkj.config.SpPrinterConfig;
import com.hfkj.config.SpPrinterTemplate;
import com.hfkj.dao.BsMealTableMapper;
import com.hfkj.entity.*;
import com.hfkj.model.MerBasisModel;
import com.hfkj.service.BsDeviceService;
import com.hfkj.service.BsMerService;
import com.hfkj.service.BsStoreService;
import com.hfkj.service.meal.BsMealShopCartService;
import com.hfkj.service.meal.BsMealTableOrderProductService;
import com.hfkj.service.meal.BsMealTableOrderService;
import com.hfkj.service.meal.BsMealTableService;
import com.hfkj.sysenum.*;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;

/**
 * @className: BsMealTableServiceImpl
 * @author: HuRui
 * @date: 2023/11/29
 **/
@Service("mealTableService")
public class BsMealTableServiceImpl implements BsMealTableService {

    @Resource
    private BsMealTableMapper mealTableMapper;

    @Resource
    private BsStoreService storeService;

    @Resource
    private BsMerService merService;

    @Resource
    private BsMealTableOrderService mealTableOrderService;

    @Resource
    private BsMealTableOrderProductService mealTableOrderProductService;

    @Resource
    private BsMealShopCartService mealShopCartService;

    @Resource
    private BsDeviceService deviceService;

    @Resource
    private RedisTemplate redisTemplate;

    @Override
    public void editData(BsMealTable data) {
        if (data.getId() == null) {
            data.setCreateTime(new Date());
            data.setUpdateTime(new Date());
            mealTableMapper.insert(data);
        } else {
            data.setUpdateTime(new Date());
            mealTableMapper.updateByPrimaryKey(data);
        }
    }

    @Override
    public void generateTable(Long storeId, Integer generateNum) {
        String lockKey = "GENERATE_TABLE_"+storeId;
        try {
            Boolean lock = redisTemplate.opsForValue().setIfAbsent(lockKey, null);
            if(lock) {
                // 加锁成功

                // 查询门店
                BsStore store = storeService.getStoreById(storeId);
                if (store == null) {
                    throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未知的门店");
                }
                // 查询商户
                BsMer mer = merService.getMer(store.getMerId());
                if (mer == null) {
                    throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未知的商户");
                }
                Integer tableNumber = mealTableMapper.getMaxTableNum(store.getId());
                if (tableNumber == null) {
                    tableNumber = 0;
                }

                for (int i = 0; i < generateNum; i++) {
                    tableNumber = tableNumber + 1;
                    BsMealTable mealTable = new BsMealTable();
                    mealTable.setMerId(mer.getId());
                    mealTable.setMerNo(mer.getMerNo());
                    mealTable.setMerName(mer.getMerName());
                    mealTable.setMerAbbreviate(mer.getMerAbbreviate());
                    mealTable.setStoreId(store.getId());
                    mealTable.setStoreName(store.getName());
                    // 桌码唯一编号 13位时间戳 + 1位线程生成数
                    mealTable.setSerialNumber(System.currentTimeMillis()+IDGenerator.nextId(1));
                    mealTable.setTableNumber(tableNumber);
                    mealTable.setTableName(mealTable.getTableNumber() + "号桌");
                    mealTable.setStatus(MealTableStatusEnum.status1.getNumber());

                    // 生成二维码
                    String file = "/mealTableQrCode/" + storeId + "/" + mealTable.getSerialNumber() + ".png";
                    mealTable.setQrCodeContent(CommonSysConst.getSysConfig().getDomainName()+"/wxqrcode/meal?sn="+mealTable.getSerialNumber());
                    QRCodeGenerator.generateQRCodeImage(
                            mealTable.getQrCodeContent(),
                            350,
                            350,
                            CommonSysConst.getSysConfig().getFilesystem() + file
                    );
                    mealTable.setQrCodeImgUrl(CommonSysConst.getSysConfig().getDomainName() + "/filesystem" + file);
                    editData(mealTable);
                }
                redisTemplate.delete(lockKey);

            } else {
                throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "请勿频繁生成，正在生成中...");
            }
        } catch (BaseException baseException) {
            redisTemplate.delete(lockKey);
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, baseException.getErrorMsg());

        } catch (Exception e) {
            redisTemplate.delete(lockKey);
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "生成失败！未知错误");
        }
    }

    @Override
    public void delTable(String serialNumber) {
        // 查询桌台
        BsMealTable mealTable = getTableBySerialNumber(serialNumber);
        if (mealTable == null) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未知的桌台");
        }
        if (!mealTable.getStatus().equals(MealTableStatusEnum.status1.getNumber())) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "桌台正在使用中...");
        }
        mealTable.setStatus(MealTableStatusEnum.status0.getNumber());
        editData(mealTable);
    }

    @Override
    public BsMealTable getTableBySerialNumber(String serialNumber) {
        BsMealTableExample example = new BsMealTableExample();
        example.createCriteria().andSerialNumberEqualTo(serialNumber)
                .andStatusNotEqualTo(MealTableStatusEnum.status0.getNumber());
        List<BsMealTable> list = mealTableMapper.selectByExample(example);
        if (!list.isEmpty()) {
            return list.get(0);
        }
        return null;
    }

    @Override
    public List<BsMealTable> getTableList(Map<String, Object> param) {
        BsMealTableExample example = new BsMealTableExample();
        BsMealTableExample.Criteria criteria = example.createCriteria()
                .andStatusNotEqualTo(MealTableStatusEnum.status0.getNumber());

        if (MapUtils.getLong(param, "storeId") != null) {
            criteria.andStoreIdEqualTo(MapUtils.getLong(param, "storeId"));
        }

        if (StringUtils.isNotBlank(MapUtils.getString(param, "tableName"))) {
            criteria.andTableNameLike("%"+MapUtils.getString(param, "tableName")+"%");
        }

        if (MapUtils.getInteger(param, "status") != null) {
            criteria.andStatusEqualTo(MapUtils.getInteger(param, "status"));
        }

        example.setOrderByClause("table_number");
        return mealTableMapper.selectByExample(example);
    }

    @Override
    @Transactional(propagation= Propagation.REQUIRES_NEW)
    public void startTable(String serialNumber, Integer peopleNum) {
        // 查询桌台
        BsMealTable mealTable = getTableBySerialNumber(serialNumber);
        if (mealTable == null) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未找到桌台");
        }
        if (!mealTable.getStatus().equals(MealTableStatusEnum.status1.getNumber())) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "当前桌台状态不处于：未开台");
        }
        mealTable.setStatus(MealTableStatusEnum.status2.getNumber());
        editData(mealTable);

        BsMealTableOrder order = new BsMealTableOrder();
        order.setMerId(mealTable.getMerId());
        order.setMerNo(mealTable.getMerNo());
        order.setMerName(mealTable.getMerName());
        order.setMerAbbreviate(mealTable.getMerAbbreviate());
        order.setStoreId(mealTable.getStoreId());
        order.setStoreName(mealTable.getStoreName());
        order.setSerialNumber(mealTable.getSerialNumber());
        order.setTableNumber(mealTable.getTableNumber());
        order.setTableName(mealTable.getTableName());
        order.setPeopleNum(peopleNum);
        order.setOrderNo(DateUtil.format(new Date(), DateUtil.YMDHMS) + IDGenerator.nextId(10));
        order.setOrderAmount(new BigDecimal("0"));
        order.setStatus(MealTableOrderStatusEnum.status1.getNumber());
        order.setPayStatus(MealTableOrderPayStatusEnum.status1.getNumber());
        mealTableOrderService.editData(order);
    }

    @Override
    @Transactional(propagation= Propagation.REQUIRES_NEW)
    public void endTable(String serialNumber) {
        // 查询桌台
        BsMealTable mealTable = getTableBySerialNumber(serialNumber);
        if (mealTable == null) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未找到桌台");
        }
        if (!mealTable.getStatus().equals(MealTableStatusEnum.status2.getNumber())) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "当前桌台状态不处于：已开台");
        }
        mealTable.setStatus(MealTableStatusEnum.status1.getNumber());
        editData(mealTable);

        // 查询桌台订单
        BsMealTableOrder tableOrder = mealTableOrderService.getCurrentTableOrder(serialNumber);
        if (tableOrder != null) {
            tableOrder.setStatus(MealTableOrderStatusEnum.status2.getNumber());
            tableOrder.setPayStatus(MealTableOrderPayStatusEnum.status3.getNumber());
            tableOrder.setPayTime(new Date());
            mealTableOrderService.editData(tableOrder);

            // 清空购物车
            mealShopCartService.clearData(tableOrder.getSerialNumber());

            // 订单产品
            Map<String,Object> orderProductMap = new HashMap<>();
            orderProductMap.put("orderNo", tableOrder.getOrderNo());
            List<BsMealTableOrderProduct> productList = mealTableOrderProductService.getOrderProductList(orderProductMap);

            // 打印小票
            Map<String,Object> deviceParam = new HashMap<>();
            deviceParam.put("storeId", tableOrder.getStoreId());
            deviceParam.put("deviceType", DeviceTypeEnum.type3.getNumber());
            List<BsDevice> deviceList = deviceService.getDeviceList(deviceParam);
            for (BsDevice device : deviceList) {
                SpPrinterConfig sp = new SpPrinterConfig();
                try {
                    sp.print(device.getDeviceNo(), SpPrinterTemplate.mealOrderBill(tableOrder, productList), 1);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}
