package com.ycwl.basic.service.printer.impl;

import com.ycwl.basic.biz.OrderBiz;
import com.ycwl.basic.constant.NumberConstant;
import com.ycwl.basic.enums.OrderStateEnum;
import com.ycwl.basic.exception.BaseException;
import com.ycwl.basic.mapper.MemberMapper;
import com.ycwl.basic.mapper.OrderMapper;
import com.ycwl.basic.mapper.PrintTaskMapper;
import com.ycwl.basic.mapper.PrinterMapper;
import com.ycwl.basic.mapper.SourceMapper;
import com.ycwl.basic.model.mobile.order.PriceObj;
import com.ycwl.basic.model.pc.member.resp.MemberRespVO;
import com.ycwl.basic.model.pc.order.entity.OrderEntity;
import com.ycwl.basic.model.pc.order.entity.OrderItemEntity;
import com.ycwl.basic.model.pc.price.entity.PriceConfigEntity;
import com.ycwl.basic.model.pc.printer.entity.PrintTaskEntity;
import com.ycwl.basic.model.pc.printer.entity.PrinterEntity;
import com.ycwl.basic.model.pc.printer.resp.MemberPrintResp;
import com.ycwl.basic.model.pc.printer.resp.PrinterResp;
import com.ycwl.basic.model.pc.source.resp.SourceRespVO;
import com.ycwl.basic.model.printer.req.FromSourceReq;
import com.ycwl.basic.model.printer.req.PrinterSyncReq;
import com.ycwl.basic.model.printer.req.WorkerAuthReqVo;
import com.ycwl.basic.model.printer.resp.PrintTaskResp;
import com.ycwl.basic.model.wx.WXPayOrderReqVO;
import com.ycwl.basic.repository.PriceRepository;
import com.ycwl.basic.service.mobile.WxPayService;
import com.ycwl.basic.service.printer.PrinterService;
import com.ycwl.basic.utils.ApiResponse;
import com.ycwl.basic.utils.SnowFlakeUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

@Slf4j
@Service
public class PrinterServiceImpl implements PrinterService {
    @Autowired
    private PrinterMapper printerMapper;
    @Autowired
    private PriceRepository priceRepository;
    @Autowired
    private SourceMapper sourceMapper;
    @Autowired
    private MemberMapper memberMapper;
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    @Lazy
    private OrderBiz orderBiz;
    @Autowired
    private WxPayService wxPayService;
    @Autowired
    private PrintTaskMapper printTaskMapper;

    @Override
    public List<PrinterResp> listByScenicId(Long scenicId) {
        return printerMapper.listByScenicId(scenicId);
    }

    @Override
    public ApiResponse<List<PrinterEntity>> list(PrinterEntity condition) {
        return ApiResponse.success(printerMapper.list(condition));
    }

    @Override
    public ApiResponse<PrinterEntity> get(Integer id) {
        return ApiResponse.success(printerMapper.getById(id));
    }

    @Override
    public ApiResponse<Integer> add(PrinterEntity entity) {
        return ApiResponse.success(printerMapper.add(entity));
    }

    @Override
    public ApiResponse<Integer> update(PrinterEntity entity) {
        return ApiResponse.success(printerMapper.update(entity));
    }

    @Override
    public ApiResponse<Integer> delete(Integer id) {
        return ApiResponse.success(printerMapper.deleteById(id));
    }

    private PrinterEntity getPrinter(WorkerAuthReqVo req) {
        String accessKey = req.getAccessKey();
        if (accessKey == null) {
            return null;
        }
        PrinterEntity printer = printerMapper.findByAccessKey(accessKey);
        if (printer == null) {
            return null;
        }
        if (printer.getStatus() != 1) {
            return null;
        }
        return printer;
    }

    @Override
    public List<PrintTaskResp> sync(PrinterSyncReq req) {
        PrinterEntity printer = getPrinter(req);
        if (printer == null) {
            return Collections.emptyList();
        }
        List<String> printers = req.getPrinters();
        String printersStr = StringUtils.join(printers, ",");
        if (!StringUtils.equals(printersStr, printer.getPrinters())) {
            printer.setPrinters(printersStr);
            printerMapper.update(printer);
        }
        PrintTaskResp task = printerMapper.findTaskByPrinterId(printer.getId());
        if (task == null) {
            return Collections.emptyList();
        }
        return Collections.singletonList(task);
    }

    @Override
    public void taskSuccess(Integer taskId, WorkerAuthReqVo req) {
        PrintTaskEntity task = printerMapper.getTaskById(taskId);
        if (task == null) {
            return;
        }
        PrinterEntity printer = getPrinter(req);
        if (printer == null) {
            return;
        }
        if (printer.getId().equals(task.getPrinterId())) {
            printerMapper.updateTaskStatus(taskId, 1);
        }
    }

    @Override
    public void taskFail(Integer taskId, WorkerAuthReqVo req) {
        PrintTaskEntity task = printerMapper.getTaskById(taskId);
        if (task == null) {
            return;
        }
        PrinterEntity printer = getPrinter(req);
        if (printer == null) {
            return;
        }
        if (printer.getId().equals(task.getPrinterId())) {
            printerMapper.updateTaskStatus(taskId, 2);
        }
    }

    @Override
    public List<MemberPrintResp> getUserPhotoList(Long userId, Long scenicId) {
        List<MemberPrintResp> list = printerMapper.listRelation(userId, scenicId);
        if (list.isEmpty()) {
            // 额外逻辑
        }
        return list;
    }

    @Override
    public List<MemberPrintResp> getUserPhotoListByOrderId(Long orderId) {
        return printerMapper.listRelationByOrderId(orderId);
    }

    @Override
    public boolean deleteUserPhoto(Long memberId, Long scenicId, Long relationId) {
        int record = printerMapper.deleteUserPhoto(memberId, scenicId, relationId);
        return record > 0;
    }

    @Override
    public boolean addUserPhoto(Long memberId, Long scenicId, String url) {
        printerMapper.addUserPhoto(memberId, scenicId, url);
        return true;
    }

    @Override
    public MemberPrintResp getUserPhoto(Long userId, Long scenicId, Long id) {
        return printerMapper.getUserPhoto(userId, scenicId, id);
    }

    @Override
    public int setPhotoCropped(Long memberId, Long scenicId, Long id, String url) {
        return printerMapper.setPhotoCropped(memberId, scenicId, id, url);
    }

    @Override
    public int setPhotoQuantity(Long memberId, Long scenicId, Long id, Integer quantity) {
        return printerMapper.setPhotoQuantity(memberId, scenicId, id, quantity);
    }

    @Override
    public PriceObj queryPrice(Long memberId, Long scenicId) {
        List<MemberPrintResp> userPhotoList = getUserPhotoList(memberId, scenicId);
        // 判断几张
        PriceConfigEntity priceConfig = priceRepository.getPriceConfigByScenicTypeGoods(scenicId, 3, null);
        PriceObj obj = new PriceObj();
        long count = userPhotoList.stream().filter(item -> Objects.nonNull(item.getQuantity())).mapToInt(MemberPrintResp::getQuantity).sum();
        obj.setPrice(priceConfig.getPrice().multiply(BigDecimal.valueOf(count)));
        obj.setSlashPrice(priceConfig.getSlashPrice().multiply(BigDecimal.valueOf(count)));
        obj.setGoodsType(3);
        obj.setFree(false);
        obj.setScenicId(scenicId);
        return obj;
    }

    @Override
    public boolean addUserPhotoFromSource(Long memberId, Long scenicId, FromSourceReq req) {
        req.getIds().forEach(id -> {
            SourceRespVO byId = sourceMapper.getById(id);
            if (byId == null) {
                return;
            }
            printerMapper.addUserPhoto(memberId, scenicId, byId.getUrl());
        });
        return false;
    }

    @Override
    public Map<String, Object> createOrder(Long memberId, Long scenicId, Integer printerId) {
        if (printerId == null) {
            List<PrinterResp> printerList = printerMapper.listByScenicId(scenicId);
            if (printerList.size() != 1) {
                throw new BaseException("请选择打印机");
            } else {
                printerId = printerList.getFirst().getId();
            }
        } else {
            PrinterEntity printer = printerMapper.getById(printerId);
            if (printer == null) {
                throw new BaseException("打印机不存在");
            }
            if (printer.getStatus() != 1) {
                throw new BaseException("打印机已停用");
            }
            if (!printer.getScenicId().equals(scenicId)) {
                throw new BaseException("打印机不属于该景区");
            }
        }
        PriceConfigEntity priceConfig = priceRepository.getPriceConfigByScenicTypeGoods(scenicId, 3, null);
        if (priceConfig == null) {
            throw new BaseException("该套餐暂未开放购买");
        }
        log.info("创建打印订单，价格配置：{}", priceConfig);
        OrderEntity order = new OrderEntity();
        Long orderId = SnowFlakeUtil.getLongId();
        order.setId(orderId);
        order.setMemberId(memberId);
        MemberRespVO member = memberMapper.getById(memberId);
        order.setOpenId(member.getOpenId());
        order.setScenicId(scenicId);
        order.setType(priceConfig.getType());
        batchSetUserPhotoListToPrinter(memberId, scenicId, printerId);
        List<MemberPrintResp> userPhotoList = getUserPhotoList(memberId, scenicId);
        List<OrderItemEntity> orderItems = userPhotoList.stream().map(goods -> {
            OrderItemEntity orderItem = new OrderItemEntity();
            orderItem.setOrderId(orderId);
            // member_print
            orderItem.setGoodsId(Long.valueOf(goods.getId()));
            orderItem.setGoodsType(3);
            return orderItem;
        }).collect(Collectors.toList());
        long count = userPhotoList.stream().filter(item -> Objects.nonNull(item.getQuantity())).mapToInt(MemberPrintResp::getQuantity).sum();
        order.setPrice(priceConfig.getPrice().multiply(BigDecimal.valueOf(count)));
        order.setSlashPrice(priceConfig.getSlashPrice().multiply(BigDecimal.valueOf(count)));
        order.setPayPrice(priceConfig.getPrice().multiply(BigDecimal.valueOf(count)));
//        order.setFaceId();
        if (order.getPayPrice().equals(BigDecimal.ZERO)) {
            order.setStatus(OrderStateEnum.PAID.getState());
            order.setPayAt(new Date());
        } else {
            order.setStatus(OrderStateEnum.UNPAID.getState());
        }
        orderMapper.add(order);
        int addOrderItems = orderMapper.addOrderItems(orderItems);
        if (addOrderItems == NumberConstant.ZERO) {
            log.error("订单明细添加失败");
            throw new BaseException("订单添加失败");
        }
        Map<String, Object> data = new HashMap<>();
        if (order.getPayPrice().equals(BigDecimal.ZERO)) {
            orderBiz.paidOrder(order.getId());
            data.put("needPay", false);
        } else {
            WXPayOrderReqVO wxPayOrderReqVO = new WXPayOrderReqVO();
            wxPayOrderReqVO.setOpenId(order.getOpenId())
                    .setMemberId(order.getMemberId())
                    .setOrderSn(order.getId())
                    .setTotalPrice(order.getPayPrice().setScale(2, RoundingMode.HALF_UP).multiply(new BigDecimal(100)).intValueExact())
                    .setGoodsName("照片打印")
                    .setDescription("照片打印");
            try {
                data = wxPayService.createOrder(order.getScenicId(), wxPayOrderReqVO);
            } catch (Exception e) {
                throw new BaseException(e);
            }
            data.put("orderId", orderId);
        }
        return data;
    }

    @Override
    public void batchSetUserPhotoListToPrinter(Long memberId, Long scenicId, Integer printerId) {
        printerMapper.updateUserPhotoListToPrinter(memberId, scenicId, printerId);
    }

    @Override
    public void setUserIsBuyItem(Long memberId, Long id, Long orderId) {
        printerMapper.setUserIsBuyItem(memberId, id, orderId);
        // 创建打印任务
        List<MemberPrintResp> userPhotoListByOrderId = getUserPhotoListByOrderId(orderId);
        userPhotoListByOrderId.forEach(item -> {
            PrinterEntity printer = printerMapper.getById(item.getPrinterId());
            PrintTaskEntity task = new PrintTaskEntity();
            task.setPrinterId(printer.getId());
            task.setStatus(0);
            task.setUrl(item.getCropUrl());
            task.setHeight(printer.getPreferH());
            task.setWidth(printer.getPreferW());
            task.setCreateTime(new Date());
            task.setUpdateTime(new Date());
            printTaskMapper.insertTask(task);
        });
    }
}