package com.kcim.service.impl;

import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.result.ExcelVerifyHandlerResult;
import cn.afterturn.easypoi.handler.inter.IExcelVerifyHandler;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.kcim.common.exception.CostException;
import com.kcim.common.util.PageUtils;
import com.kcim.common.util.Result;
import com.kcim.common.util.UserContext;
import com.kcim.common.constants.NumberConstant;
import com.kcim.common.util.excel.entity.PatientItemImportEntity;
import com.kcim.common.util.excel.entity.ProductTemplateEntity;
import com.kcim.common.util.excel.handler.ItemTypeHandler;
import com.kcim.dao.mapper.ProductMapper;
import com.kcim.dao.model.*;
import com.kcim.dao.model.dto.ProductDTO;
import com.kcim.dao.model.dto.ProductEditDTO;
import com.kcim.dao.repository.AccountingProductRepository;
import com.kcim.vo.CommonVO;
import com.kcim.vo.DictDataVo;
import com.kcim.vo.ProductVO;
import com.kcim.service.ProductService;
import com.kcim.common.util.BeanUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
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 java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;

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

@Slf4j
@Service("productService")
@AllArgsConstructor
public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> implements ProductService {

    private HospitalServiceImpl hospitalService;

    AccountingProductRepository accountingProductRepository;

    /**
     * 分页查询
     *
     * @param current
     * @param pageSize
     * @param name
     * @return
     */
    @Override
    public PageUtils selectList(Integer current, Integer pageSize, String name) {
        Page<Product> productPage = new Page<>(current, pageSize);
        LambdaQueryWrapper<Product> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Product::getHospId, UserContext.getHospId());
        if(!StringUtils.isEmpty(name)){
            queryWrapper.like(Product::getProductName, name);
        }
        queryWrapper.orderByDesc(Product::getCreateTime);
        Page<Product> pages = this.page(productPage, queryWrapper);
        List<Product> records = pages.getRecords();
        if(CollectionUtils.isEmpty(records)){
            return new PageUtils(new ArrayList<>(),NumberConstant.ZERO,pageSize,current);
        }
        List<ProductVO> list = BeanUtil.convertList(records, ProductVO.class);
        return new PageUtils(list, Math.toIntExact(pages.getTotal()),pageSize,current);

    }

    /**
     * 保存成本项目
     *
     * @param productDTO
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void saveProduct(ProductDTO productDTO) {
        // 校验code
        this.checkProductCode(productDTO.getProductCode(), UserContext.getHospId());
        Product product = BeanUtil.convertObj(productDTO, Product.class);
        product.setCreateTime(System.currentTimeMillis());
        product.setHospId(UserContext.getHospId());
        this.save(product);
    }

    private void checkProductCode(String code, Long hospId) {
        List<Product> list = this.list(
                new LambdaQueryWrapper<Product>()
                        .eq(Product::getProductCode, code)
                        .eq(Product::getHospId, hospId)
        );
        if (CollUtil.isNotEmpty(list)) {
            throw new CostException(500, "成本代码已存在");
        }
    }


    /**
     * 编辑某个成本项目
     *
     * @param productEditDTO
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void editProduct(ProductEditDTO productEditDTO) {
        Product byId = this.getById(productEditDTO.getId());
        if (Objects.isNull(byId)) {
            throw new CostException(500, "选中的会计科目不存在");
        }
        this.removeById(productEditDTO.getId());
        this.checkProductCode(productEditDTO.getProductCode(), UserContext.getHospId());
        Product product = byId.setId(null).setHospId(UserContext.getHospId())
                        .setProductCode(productEditDTO.getProductCode())
                        .setProductName(productEditDTO.getProductName())
                        .setCreateTime(System.currentTimeMillis());
        this.save(product);
    }

    /**
     * 修改或新增会计科目对照列表
     *
     * @return
     */
    @Override
    public List<CommonVO> getProducts() {
        List<Product> list = this.list(
                new LambdaQueryWrapper<Product>().select(Product::getId, Product::getProductCode, Product::getProductName)
                        .eq(Product::getHospId, UserContext.getHospId())
        );
        if (list.isEmpty()) {
            return Collections.emptyList();
        }

        List<AccountingProduct> accountingProducts = accountingProductRepository.getList();
        if(!CollectionUtils.isEmpty(accountingProducts)){
            //过滤出已对照过的会计收入项目
            List<Long> collect = accountingProducts.stream().map(AccountingProduct::getProductId).collect(Collectors.toList());
            List<Product> removeList = new ArrayList<>();
            for (Product product : list) {
                if(collect.contains(product.getId())){
                    removeList.add(product);
                }
            }
            if(!CollectionUtils.isEmpty(removeList)){
                list.removeAll(removeList);
            }
        }

        return list.stream().map(i -> {
            CommonVO commonVO = new CommonVO();
            commonVO.setId(i.getId());
            commonVO.setName(i.getProductName() + "[" + i.getProductCode() + "]");
            return commonVO;
        }).collect(Collectors.toList());
    }

    /**
     * 批量导入收入成本信息
     *
     * @param list
     * @param hospId
     * @return
     */
    @Override
    public Result importProduct(List<List<Object>> list, Long hospId) {
        for (int i = list.size() - 1; i >= 0; i--) {
            if (i == NumberConstant.ZERO || i == NumberConstant.ONE || i == NumberConstant.TWO || i == NumberConstant.THREE) {
                list.remove(list.get(i));
            }
        }
        log.info("读取的数据为：{}", list);
        List<Product> productList = new ArrayList<>();
        List<String> errRowNums = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {
            List<Object> data = list.get(i);
            log.info("得到用户输入的数据为：{}", data);
            Product product = new Product();
            product.setHospId(hospId);
            product.setCreateTime(System.currentTimeMillis());
            int size = data.size();
            if (size != 5) {
                // 补充读取的null问题
                if (size == 4) {
                    data.add(StrUtil.EMPTY);
                }
                for (int j = 0; j < 3; j++) {
                    if (Objects.isNull(data.get(j))) {
                        data.set(j, StrUtil.EMPTY);
                    }
                }
            }
            for (int j = 0; j < 3; j++) {
                String str = String.valueOf(data.get(j));
                log.info("得到的字符串{}", str);
                if (StrUtil.isBlank(str)) {
                    errRowNums.add("" + (i + 3));
                }

                if (j == 0) {
                    //  Excel里面输入医院名称  根据医院名称解析
                    Hospital hospital = hospitalService.getByName(str);
                    product.setHospId(hospital.getId());
                } else if (j == 1) {
                    product.setProductName(str);
                } else {
                    product.setProductCode(str);
                }
            }
            productList.add(product);
        }
        if (CollUtil.isNotEmpty(errRowNums)) {
            String collect = errRowNums.stream().collect(Collectors.joining(StrUtil.COMMA));
            throw new CostException(500, "第" + collect + "行数据异常");
        }
        // 校验输入的Department是否存在  输入的科室里面筛选出已经存在的科室信息
        List<Product> realProducts = new ArrayList<>();
        productList.forEach(i -> {
            Product one = getOne(
                    new QueryWrapper<Product>().lambda()
                            .eq(Product::getProductCode, i.getProductCode())
                            .eq(Product::getHospId, i.getHospId())
            );
            if (Objects.nonNull(one)) {
                realProducts.add(one);
            }
        });
        productList = productList.stream().filter(i -> !realProducts.stream().map(Product::getProductCode).collect(Collectors.toList()).contains(i.getProductCode())).collect(Collectors.toList());
        this.saveBatch(productList);
        if (CollectionUtils.isEmpty(realProducts)){
            return Result.build(200,"数据导入成功",null);
        }else {
            return Result.build(200, "有" + realProducts.size() + "条数据已存在，未被导入", null);
        }
    }

    /**
     * 批量删除收入成本数据
     *
     * @param idList 成本的Id集合
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    public void deleteByIds(List<Integer> idList) {
        this.removeByIds(idList);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    public Result importProduct(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<ProductTemplateEntity> handler = val ->{
                if(StringUtils.isEmpty(val.getProductCode())){
                    return new ExcelVerifyHandlerResult(false,"成本项目编号不能为空");
                }
                return new ExcelVerifyHandlerResult(true);
            };
            params.setVerifyHandler(handler);
            // 标题占用多少行
            params.setTitleRows(1);
            // 头部属性占用多少行
            params.setHeadRows(1);

            List<ProductTemplateEntity> importExcel  = ExcelImportUtil.importExcel(stream, ProductTemplateEntity.class,params);
            if(!CollectionUtils.isEmpty(importExcel)){
                List<Product> saveList = new ArrayList<>();
                Product product = new Product();
                product.setHospId(UserContext.getHospId());
                product.setCreateTime(new Date().getTime());
                for (ProductTemplateEntity entity : importExcel) {
                    Product obj = BeanUtil.convertObj(product, Product.class);
                    obj.setProductCode(entity.getProductCode());
                    obj.setProductName(entity.getProductName());
                    saveList.add(obj);
                }
                if(!CollectionUtils.isEmpty(saveList)){
                    check();
                    this.saveBatch(saveList,50);
                }

            }

        }catch (Exception e){
            throw new RuntimeException(e);
        }
        return Result.ok();
    }

    private void check() {
        LambdaQueryWrapper<Product> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Product::getHospId,UserContext.getHospId());
        List<Product> list = this.list(queryWrapper);
        if(!CollectionUtils.isEmpty(list)){
            List<Long> collect = list.stream().map(Product::getId).collect(Collectors.toList());
            this.removeByIds(collect);
        }
    }

}