package com.kcim.service.impl;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.result.ExcelVerifyHandlerResult;
import cn.afterturn.easypoi.handler.inter.IExcelVerifyHandler;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.kcim.common.constants.NumberConstant;
import com.kcim.common.exception.CostException;
import com.kcim.common.util.BeanUtil;
import com.kcim.common.util.PageUtils;
import com.kcim.common.util.UserContext;
import com.kcim.common.util.excel.ExcelStyleUtil;
import com.kcim.common.util.excel.entity.OrderImportEntity;
import com.kcim.common.util.excel.handler.OrderTypeHandler;
import com.kcim.dao.model.Order;
import com.kcim.dao.model.OrderItemMap;
import com.kcim.dao.repository.ItemRepository;
import com.kcim.dao.repository.OrderItemMapRepository;
import com.kcim.dao.repository.OrderRepository;
import com.kcim.service.*;
import com.kcim.vo.DictDataVo;
import com.kcim.web.request.OrderItemRequest;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;

import static com.kcim.common.constants.Constant.ORDER_TYPE;

/**
 * @program: CostAccount
 * @description: 医嘱项目接口实现类
 * @author: Wang.YS
 * @create: 2023-11-15 15:29
 **/
@Service("OrderService")
@Slf4j
@AllArgsConstructor
public class OrderServiceImpl implements OrderService {
    OrderRepository repository;

    OrderItemMapRepository orderItemMapRepository;

    CenterService centerService;

    ItemRepository itemRepository;

    DrugService drugService;

    MaterialService materialService;

    ItemService itemService;

    /**
     * 获取医嘱列表
     * @param orderType 医嘱类型
     * @param orderName 医嘱名称
     * @return 医嘱列表
     */
    @Override
    public Object getOrderList(String orderType, String orderName) {
        List<Order> list = repository.getList(orderType,orderName);
        if(CollectionUtils.isEmpty(list)){
            return new ArrayList<>();
        }

        DictDataVo dict = centerService.getDict(ORDER_TYPE);
        List<DictDataVo> dataVoList = dict.getDataVoList();
        Map<String,String> dataMap = dataVoList.stream().collect(Collectors.toMap(DictDataVo::getCode, DictDataVo::getName, (a, b) -> b));
        list.forEach(order -> order.setTypeName(dataMap.get(order.getType())));

        return list;
    }

    /**
     * 新增医嘱
     * @param request 入参
     */
    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public void addOrder(Order request) {
        List<Order> byCode = repository.getByCode(request.getCode());
        if(!CollectionUtils.isEmpty(byCode)){
            throw new CostException("当前医嘱项目代码已存在，请修改后再保存");
        }
        request.setHospId(UserContext.getCurrentLoginHospId());
        request.setCreateTime(new Date());
        request.setCreateUser(String.valueOf(UserContext.getCurrentUser().getId()));
        repository.save(request);

    }

    /**
     * 编辑医嘱
     * @param request 入参
     */
    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public void editOrder(Order request) {
        Integer id = request.getId();
        if(id ==null){
            throw new CostException("编辑时主键必填");
        }
        Order order = repository.getById(id);
        Order oneByCode = repository.getOneByCode(request.getCode());
        if(Objects.nonNull(order)){
            if(Objects.isNull(oneByCode)||oneByCode.getId().equals(id)){
                BeanUtil.convertObj(request,order);
                order.setUpdateUser(String.valueOf(UserContext.getCurrentUser().getId()));
                order.setUpdateTime(new Date());
                repository.updateById(order);
            }else {
                throw new CostException("当前收费项目代码已存在，请修改后再保存");
            }
        }
    }

    /**
     * 删除医嘱
     * @param id 主键
     */
    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public void deleteOrder(Integer id) {
        repository.deleteOrder(id);

    }

    /**
     * 获取医嘱类型
     * @return 医嘱类型字典
     */
    @Override
    public Object getOrderType() {
        DictDataVo dict = centerService.getDict(ORDER_TYPE);
        return dict.getDataVoList();
    }

    /**
     * 导出医嘱模版
     * @param response 出参
     * @return 出参
     */
    @SneakyThrows
    @Override
    public Object exportOrder(HttpServletResponse response) {
        try {
            //配置excel 文件信息
            ExportParams params = new ExportParams();

            params.setTitle("1、为了保证成功导入，请勿修改模板格式\n" +
                    "2、医嘱项目类型为下拉选择字段，不可填写选项外的内容");
            DictDataVo orderType = centerService.getDict(ORDER_TYPE);
//            DictDataVo chargeItemType = centerService.getDict(CHARGE_ITEM_TYPE);
            List<DictDataVo> orderTypeDataVoList = orderType.getDataVoList();
//            List<DictDataVo> chargeItemTypeDataVoList = chargeItemType.getDataVoList();
            //设置导出样式
            params.setStyle(ExcelStyleUtil.class);
            params.setDictHandler(new OrderTypeHandler(orderTypeDataVoList));
//            params.setDictHandler(new OrderTypeHandler(chargeItemTypeDataVoList));
            //设置sheetName
            params.setSheetName("医嘱项目");
//            FileOutputStream outputStream = new FileOutputStream("E:\\医嘱项目成本导入模版.xlsx");
            Workbook workbook = ExcelExportUtil.exportExcel(params, OrderImportEntity.class,new ArrayList<>());
            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/vnd.ms-excel");
            String fileName ="医嘱项目成本导入模版";
            response.setHeader("Content-Disposition",  URLEncoder.encode(fileName, "UTF-8"));
            workbook.write(response.getOutputStream());

            workbook.close();
            log.info("导出文件：{}",fileName);
        } catch (FileNotFoundException e) {
            throw new CostException(e.getMessage());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return response.getOutputStream();
    }

    /**
     * 导入医嘱
     * @param file excel 文 件
     */
    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public void importOrder(MultipartFile file) {
        try {
            if (ObjectUtils.isEmpty(file) || file.getSize() == 0){
                throw new CostException("未获取到导入的excel文件内容");
            }
            log.info("接收到文件：{}",file.getOriginalFilename());
            // 参数1：文件流
            InputStream stream = file.getInputStream();
            // 参数2：导入类型
            ImportParams params = new ImportParams();
            //校验Excel 去掉空行
            params.setNeedVerify(true);
            IExcelVerifyHandler<OrderImportEntity> handler = val ->{
                if(StringUtils.isEmpty(val.getCode())){
                    return new ExcelVerifyHandlerResult(false,"医嘱项目代码不能为空");
                }
                if(StringUtils.isEmpty(val.getName())){
                    return new ExcelVerifyHandlerResult(false,"医嘱项目名称不能为空");
                }
                return new ExcelVerifyHandlerResult(true);
            };
            params.setVerifyHandler(handler);
            // 标题占用多少行
            params.setTitleRows(1);
            // 头部属性占用多少行
            params.setHeadRows(1);
            DictDataVo dict = centerService.getDict(ORDER_TYPE);

            List<DictDataVo> dataVoList = dict.getDataVoList();
            //设置导出样式
            params.setDictHandler(new OrderTypeHandler(dataVoList));
            List<OrderImportEntity> orderImportEntities  = ExcelImportUtil.importExcel(stream, OrderImportEntity.class,params);
            if(!CollectionUtils.isEmpty(orderImportEntities)){
                List<Order> saveList = new ArrayList<>();
                Order order =new Order();
                order.setHospId(UserContext.getHospId());
                order.setCreateTime(new Date());
                order.setCreateUser(String.valueOf(UserContext.getCurrentUser().getId()));
                List<OrderItemMap> saveOrderItemList = new ArrayList<>();

                OrderItemMap orderItemMap = new OrderItemMap();
                orderItemMap.setHospId(UserContext.getHospId());
                orderItemMap.setCreateTime(new Date());
                orderItemMap.setCreateUser(String.valueOf(UserContext.getCurrentUser().getId()));
                Map<String, List<OrderImportEntity>> collect = orderImportEntities.stream().collect(Collectors.groupingBy(OrderImportEntity::getCode));
                for (String orderCode : collect.keySet()) {
                    List<OrderImportEntity> entities = collect.get(orderCode);
                    Order obj = BeanUtil.convertObj(order, Order.class);
                    obj.setCode(entities.get(0).getCode());
                    obj.setName(entities.get(0).getName());
                    obj.setType(entities.get(0).getType());
                    for (OrderImportEntity entity : entities) {
                        OrderItemMap itemMap = BeanUtil.convertObj(orderItemMap, OrderItemMap.class);
                        itemMap.setOrderCode(obj.getCode());
                        itemMap.setItemCode(entity.getItemCode());
                        itemMap.setNum(entity.getNum());
                        itemMap.setUnit(entity.getUnit());
                        itemMap.setItemName(entity.getItemName());
                        itemMap.setItemType(entity.getItemType());
                        saveOrderItemList.add(itemMap);
                    }
                    saveList.add(obj);
                }
                if(!CollectionUtils.isEmpty(saveList)){
                    check();
                    repository.saveBatch(saveList,50);
                    if(!CollectionUtils.isEmpty(saveOrderItemList)){
                        checkItemMap();
                        orderItemMapRepository.saveBatch(saveOrderItemList,50);
                    }
                }
            }
        } catch (Exception e) {
            throw new CostException(e.getMessage());
        }
    }

    /**
     * 按分页获取医嘱列表
     * @param current 当前页
     * @param pageSize 页容量
     * @param orderCode 医嘱代码
     * @param itemName 项目名称
     * @return 列表
     */
    @Override
    public Object getOrderItemList(Integer current, Integer pageSize, String orderCode, String itemName) {
        Page<OrderItemMap> page = orderItemMapRepository.getPage(current, pageSize, orderCode, itemName);
        List<OrderItemMap> records = page.getRecords();
        if(CollectionUtils.isEmpty(records)){
            return new PageUtils(new ArrayList<>(), NumberConstant.ZERO,pageSize,current);
        }
        for (OrderItemMap record : records) {
            //"药品_1","材料_2","项目_3"
            String itemType = record.getItemType();
            switch (itemType) {
                case "1":
                    record.setItemTypeName("药品");
                    break;
                case "2":
                    record.setItemTypeName("材料");
                    break;
                case "3":
                    record.setItemTypeName("项目");
                    break;
                default:
                    record.setItemTypeName("未知");
                    break;
            }
        }
        return new PageUtils(records, Math.toIntExact(page.getTotal()),pageSize,current);

    }

    /**
     * 添加医嘱项目
     * @param request 入参
     */
    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public void addOrderItem(OrderItemRequest request) {
        String orderCode = request.getOrderCode();
        List<OrderItemMap> items = request.getItems();
        if(CollectionUtils.isEmpty(items)){
            throw new CostException("未传入任何需要保存的数据，无需保存");
        }
//        orderItemMapRepository.removeByOrderCode(orderCode);
        for (OrderItemMap item : items) {
            item.setOrderCode(orderCode);
            item.setCreateTime(new Date());
            item.setCreateUser(String.valueOf(UserContext.getCurrentUser().getId()));
            item.setHospId(UserContext.getHospId());
            item.setNum(BigDecimal.ONE);
            item.setItemType(item.getItemType());
        }
        orderItemMapRepository.saveBatch(items);

    }

    /**
     * 编辑医嘱项目列表
     * @param request 入参
     */
    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public void editOrderItem(OrderItemMap request) {
        Integer id = request.getId();
        if(id ==null){
            throw new CostException("编辑时主键必填");

        }
        OrderItemMap orderItemMap = orderItemMapRepository.getById(id);
        if(Objects.nonNull(orderItemMap)){
            BeanUtil.convertObj(request,orderItemMap);
            orderItemMap.setUpdateUser(String.valueOf(UserContext.getCurrentUser().getId()));
            orderItemMap.setUpdateTime(new Date());
            orderItemMapRepository.updateById(orderItemMap);
        }
    }

    /**
     * 单个删除
     * @param id 主键
     */
    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public void deleteOrderItem(Integer id) {
        orderItemMapRepository.removeByIds(Collections.singleton(id));
    }

    /**
     * 批量删除医嘱项目
     * @param ids 主键列表
     */
    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public void batchDeleteOrderItem(List<Integer> ids) {
        orderItemMapRepository.removeByIds(ids);

    }

    /**
     * 获取项目字典
     * @param type 类型
     * @param orderCode 医嘱代码
     * @param name 项目名称
     * @return 字典列表
     */
    @Override
    public Object getItemDict(Integer type, String orderCode, String name) {
        List<OrderItemMap> orderItemMaps = new ArrayList<>();
        if(type.equals(NumberConstant.ONE)){
            //药品
            orderItemMaps = drugService.getItemDict(name);
        } else if (type.equals(NumberConstant.TWO)) {
            //材料
            orderItemMaps = materialService.getItemDict(name);
        } else if (type.equals(NumberConstant.THREE)) {
            //收费项目
            orderItemMaps = itemService.getItemDict(name);
        }else {
            orderItemMaps = itemService.getItemDict(name);
        }
        //获取已对照的项目
        List<OrderItemMap> byOrderCode = orderItemMapRepository.getByOrderCode(orderCode);
        if(!CollectionUtils.isEmpty(byOrderCode)){
            List<String> list = byOrderCode.stream().map(OrderItemMap::getItemCode).collect(Collectors.toList());

            List<OrderItemMap> removeList = orderItemMaps.stream().filter(orderItemMap -> list.contains(orderItemMap.getItemCode())).collect(Collectors.toList());
            if(!CollectionUtils.isEmpty(removeList)){
                orderItemMaps.removeAll(removeList);
            }

        }
        return orderItemMaps;
    }

    private void check() {
        List<Order> list = repository.getList();
        if(!CollectionUtils.isEmpty(list)){
            repository.removeList(list);
        }
    }

    private void checkItemMap() {
        List<OrderItemMap> list = orderItemMapRepository.getList();
        if(!CollectionUtils.isEmpty(list)){
            orderItemMapRepository.removeList(list);
        }
    }
}
