/*
 *  Copyright 2019-2020 Zheng Jie
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.youchain.basicdata.service.impl;


import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import com.youchain.basicdata.domain.*;
import com.youchain.basicdata.repository.*;
import com.youchain.basicdata.service.*;
import com.youchain.basicdata.service.dto.AreaDto;
import com.youchain.basicdata.service.dto.AreaQueryCriteria;
import com.youchain.basicdata.service.mapstruct.AreaMapper;
import com.youchain.basicdata.service.mapstruct.PointMapper;
import com.youchain.businessdata.domain.Asn;
import com.youchain.businessdata.domain.AsnDetail;
import com.youchain.businessdata.domain.PickDetail;
import com.youchain.businessdata.domain.PickTicket;
import com.youchain.businessdata.service.*;
import com.youchain.config.FileProperties;
import com.youchain.config.thread.ThreadPoolExecutorUtil;
import com.youchain.exception.BadRequestException;
import com.youchain.modules.system.domain.Dept;
import com.youchain.modules.system.domain.DictDetail;
import com.youchain.modules.system.repository.DictDetailRepository;
import com.youchain.modules.system.repository.DictRepository;
import com.youchain.utils.*;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;

/**
 * @author HJL
 * @website https://eladmin.vip
 * @description 服务实现
 * @date 2023-08-14
 **/
@Service
@RequiredArgsConstructor
public class ImportDataServiceImpl implements ImportDataService {
    private final FileProperties properties;
    private final BigItemRepository bigItemRepository;
    private final AreaRepository areaRepository;
    private final ItemRepository itemRepository;
    private final PointRepository pointRepository;
    private final PointService pointService;
    private final BomAccountRepository bomAccountRepository;
    private final ItemService itemService;
    private final AsnDetailService asnDetailService;
    private final AsnService asnService;
    private final PickDetailService pickDetailService;
    private final PickTicketService pickTicketService;
    private final InventoryService inventoryService;
    private final BigItemService bigItemService;
    private final BomAccountService bomAccountService;
    private final BomAccountLogService bomAccountLogService;

    @Override
    public void importBomAccount(int row, Map<String, Object> readAll) {
        String bigItemCode = readAll.get("完成品品番") == null ? null : readAll.get("完成品品番").toString();
        String station_type = readAll.get("工位") == null ? null : readAll.get("工位").toString();
        String itemCode = readAll.get("部品品番") == null ? null : readAll.get("部品品番").toString();
        String ac = readAll.get("AC") == null ? null : readAll.get("AC").toString();
        String contents = readAll.get("加工内容") == null ? null : readAll.get("加工内容").toString();
        String single = readAll.get("单用") == null ? null : readAll.get("单用").toString();
        String r_area_name = readAll.get("入库库区") == null ? null : readAll.get("入库库区").toString();
        String c_area_name = readAll.get("出库库区") == null ? null : readAll.get("出库库区").toString();
        String z_point_code = readAll.get("制造库位") == null ? null : readAll.get("制造库位").toString();
//        String c_point_code =readAll.get("暂存库位")==null?null:readAll.get("暂存库位").toString();
        String out_type = readAll.get("出库类型") == null ? null : readAll.get("出库类型").toString();
        String supplier = readAll.get("供应商") == null ? null : readAll.get("供应商").toString();
        String bp_type = readAll.get("部品种类") == null ? null : readAll.get("部品种类").toString();

        BigItem bigItem = null;
        if (bigItemCode.length() > 0) {
            bigItem = bigItemRepository.findByCode(bigItemCode);
            if (bigItem == null) {
                throw new BadRequestException(HttpStatus.NOT_FOUND, row + "行" + bigItemCode + "完成品品番无效");
            }
        } else {
            throw new BadRequestException(HttpStatus.NOT_FOUND, row + "行" + "请输入完成品品番");
        }
        Item item = null;
        if (itemCode.length() > 0) {
            item = itemRepository.findByCode(itemCode);
            if (item == null) {
                throw new BadRequestException(HttpStatus.NOT_FOUND, row + "行" + itemCode + "部品品番无效");
            }
        } else {
            throw new BadRequestException(HttpStatus.NOT_FOUND, row + "行" + "请输入部品品番");
        }
        Area r_area = null;
        if (r_area_name.length() > 0) {
            r_area = areaRepository.getByName(r_area_name);
            if (r_area == null) {
                throw new BadRequestException(HttpStatus.NOT_FOUND, row + "行" + r_area_name + "入库库区无效");
            }
        } else {
            throw new BadRequestException(HttpStatus.NOT_FOUND, row + "行" + "请输入入库库区");
        }
        Area c_area = null;
        if (c_area_name.length() > 0) {
            c_area = areaRepository.getByName(c_area_name);
            if (c_area == null) {
                throw new BadRequestException(HttpStatus.NOT_FOUND, row + "行" + c_area_name + "出库库区无效");
            }
        } else {
            throw new BadRequestException(HttpStatus.NOT_FOUND, row + "行" + "请输入出库库区");
        }
//        Point c_point = null;
//        if (c_point_code!=null&&!c_point_code.equals("")) {
//            c_point = pointRepository.findByCode(c_point_code);
//            if (c_point == null) {
//                c_point = pointService.createPoint(c_point_code, "ZCKW", r_area,c_point);
//            }
//        }
        Point z_point = null;
        if (z_point_code != null && !z_point_code.equals("")) {
            z_point = pointRepository.findByCode(z_point_code);
            if (z_point == null) {
//               z_point = pointService.createPoint(z_point_code, "ZZKW", r_area,c_point);
                z_point = pointService.createPoint(z_point_code, "ZZKW", r_area);
            }

        } else {
            throw new BadRequestException(HttpStatus.NOT_FOUND, row + "行" + "请输入制造库位");
        }
        Boolean isNew = Boolean.FALSE;
        BomAccount bomAccount = bomAccountRepository.findByOnly(bigItem.getId(), item.getId(), r_area.getId(), z_point.getId());
        if (bomAccount == null) {
            bomAccount = new BomAccount();
            bomAccount.setBigItem(bigItem);
            bomAccount.setItem(item);
            bomAccount.setRArea(r_area);
            bomAccount.setDept(r_area.getDept());
            bomAccount.setZPoint(z_point);
            bomAccount.setBp_type(bp_type);
            isNew = Boolean.TRUE;
        }
        bomAccount.setStationType(station_type);
        bomAccount.setCArea(c_area);
        bomAccount.setAc(ac);
        bomAccount.setContents(contents);
        bomAccount.setEnabled(true);
        bomAccount.setSingles(Integer.parseInt(single));
        bomAccount.setOutType(out_type);
        bomAccount.setSupplier(supplier);
        if (isNew) {
            bomAccountService.create(bomAccount);
            bomAccountLogService.copyBomAccount(bomAccount.getId(), "import_add");
        } else {
            bomAccountService.update(bomAccount);
            bomAccountLogService.copyBomAccount(bomAccount.getId(), "import_update");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String importItem(MultipartFile multipartFile) {
        FileUtil.checkSize(properties.getMaxSize(), multipartFile.getSize());
        String suffix = FileUtil.getExtensionName(multipartFile.getOriginalFilename());
        String type = FileUtil.getFileType(suffix);
        File file = FileUtil.upload(multipartFile, properties.getPath().getPath() + type + File.separator);
        Dept dept = UserUtils.getDept();
        ExcelReader reader = ExcelUtil.getReader(file);
        List<Map<String, Object>> readAll = reader.readAll();
        Set<String> itemCodes = new HashSet<>();//物料集合
        for (Map<String, Object> record : readAll) {
            String itemCode = record.get("料号").toString().trim();
            if (!StringUtils.isEmpty(itemCode)) {
                itemCodes.add(itemCode);
            }
        }


        //获取已存在的物料
        Map<String, Item> existingPoint = itemService.findByCodes(itemCodes);


        List<Item> itemsToInsert = new ArrayList<>();//新增物料集合
        List<Item> itemsToUpdate = new ArrayList<>();//修改物料集合
        for (Map<String, Object> record : readAll) {
            String itemCode = record.get("料号").toString().trim();
            //判断是否已存在物料
            if (existingPoint.containsKey(itemCode)) {
                Item item = existingPoint.get(itemCode);
                //更新物料
                itemsToUpdate.add(updateItems(item, dept, record));
            } else {
                //新增物料
                itemsToInsert.add(createItem(dept, record));
            }
        }

        //批量新增物料
        if (!itemsToInsert.isEmpty()) {
            itemRepository.saveAll(itemsToInsert);
        }

        //批量更新物料
        if (!itemsToUpdate.isEmpty()) {
            itemRepository.saveAll(itemsToUpdate);
        }

        return ("导入成功：" + " 新增（" + itemsToInsert.size() + ")修改（" + itemsToUpdate.size() + ")");
    }

    private Item updateItems(Item item, Dept dept, Map<String, Object> record) {
        item.setName(Optional.ofNullable(record.get("物料描述")).map(Object::toString).map(String::trim).orElse(""));
        item.setPackageType(Optional.ofNullable(record.get("包装类型")).map(Object::toString).map(String::trim).orElse(""));
        item.setSpecQuantity(Optional.ofNullable(record.get("规格数量")).map(Object::toString).map(Double::parseDouble).orElse(0D));
        item.setSpecWeight(Optional.ofNullable(record.get("规格重量")).map(Object::toString).map(Double::parseDouble).orElse(0D));
        item.setGrossWeight(Optional.ofNullable(record.get("毛重")).map(Object::toString).map(Double::parseDouble).orElse(0D));
        item.setLength(Optional.ofNullable(record.get("长")).map(Object::toString).map(Double::parseDouble).orElse(0D));
        item.setWidth(Optional.ofNullable(record.get("宽")).map(Object::toString).map(Double::parseDouble).orElse(0D));
        item.setHeight(Optional.ofNullable(record.get("高")).map(Object::toString).map(Double::parseDouble).orElse(0D));
        item.setVolume(Optional.ofNullable(record.get("体积")).map(Object::toString).map(Double::parseDouble).orElse(0D));
        item.setUnit(Optional.ofNullable(record.get("单位")).map(Object::toString).map(String::trim).orElse(""));
        item.setType(Optional.ofNullable(record.get("类型")).map(Object::toString).map(String::trim).orElse(""));
        item.setValueGrade(Optional.ofNullable(record.get("物料价值等级")).map(Object::toString).map(String::trim).orElse(""));
        item.setValidPeriod(Optional.ofNullable(record.get("保质期天数")).map(Object::toString).map(Integer::parseInt).orElse(0));
        item.setAlertDays(Optional.ofNullable(record.get("预警天数")).map(Object::toString).map(Integer::parseInt).orElse(0));
        item.setIsBatch(Optional.ofNullable(record.get("是否批次")).map(Object::toString).map(String::trim).map("是"::equals).orElse(false));
        item.setIsSerial(Optional.ofNullable(record.get("是否序列号")).map(Object::toString).map(String::trim).map("是"::equals).orElse(false));
        item.setIsValidPeriod(Optional.ofNullable(record.get("是否有效期")).map(Object::toString).map(String::trim).map("是"::equals).orElse(false));
        item.setIsHazardous(Optional.ofNullable(record.get("是否危化品")).map(Object::toString).map(String::trim).map("是"::equals).orElse(false));
        item.setIsInvAvailable(Optional.ofNullable(record.get("是否有库存")).map(Object::toString).map(String::trim).map("是"::equals).orElse(false));
        item.setIsSapMaterial(Optional.ofNullable(record.get("是否SAP料号")).map(Object::toString).map(String::trim).map("是"::equals).orElse(false));
        item.setHeatValue(Optional.ofNullable(record.get("热度值")).map(Object::toString).map(Integer::parseInt).orElse(0));
        item.setDescription(Optional.ofNullable(record.get("备注")).map(Object::toString).map(String::trim).orElse(""));
        return item;
    }

    private Item createItem(Dept dept, Map<String, Object> record) {
        Item item = new Item();
        item.setCode(Optional.ofNullable(record.get("料号")).map(Object::toString).map(String::trim).orElse(""));
        item.setName(Optional.ofNullable(record.get("物料描述")).map(Object::toString).map(String::trim).orElse(""));
        item.setPackageType(Optional.ofNullable(record.get("包装类型")).map(Object::toString).map(String::trim).orElse(""));
        item.setSpecQuantity(Optional.ofNullable(record.get("规格数量")).map(Object::toString).map(Double::parseDouble).orElse(0D));
        item.setSpecWeight(Optional.ofNullable(record.get("规格重量")).map(Object::toString).map(Double::parseDouble).orElse(0D));
        item.setGrossWeight(Optional.ofNullable(record.get("毛重")).map(Object::toString).map(Double::parseDouble).orElse(0D));
        item.setLength(Optional.ofNullable(record.get("长")).map(Object::toString).map(Double::parseDouble).orElse(0D));
        item.setWidth(Optional.ofNullable(record.get("宽")).map(Object::toString).map(Double::parseDouble).orElse(0D));
        item.setHeight(Optional.ofNullable(record.get("高")).map(Object::toString).map(Double::parseDouble).orElse(0D));
        item.setVolume(Optional.ofNullable(record.get("体积")).map(Object::toString).map(Double::parseDouble).orElse(0D));
        item.setUnit(Optional.ofNullable(record.get("单位")).map(Object::toString).map(String::trim).orElse(""));
        item.setType(Optional.ofNullable(record.get("类型")).map(Object::toString).map(String::trim).orElse(""));
        item.setValueGrade(Optional.ofNullable(record.get("物料价值等级")).map(Object::toString).map(String::trim).orElse(""));
        item.setValidPeriod(Optional.ofNullable(record.get("保质期天数")).map(Object::toString).map(Integer::parseInt).orElse(0));
        item.setAlertDays(Optional.ofNullable(record.get("预警天数")).map(Object::toString).map(Integer::parseInt).orElse(0));
        item.setIsBatch(Optional.ofNullable(record.get("是否批次")).map(Object::toString).map(String::trim).map("是"::equals).orElse(false));
        item.setIsSerial(Optional.ofNullable(record.get("是否序列号")).map(Object::toString).map(String::trim).map("是"::equals).orElse(false));
        item.setIsValidPeriod(Optional.ofNullable(record.get("是否有效期")).map(Object::toString).map(String::trim).map("是"::equals).orElse(false));
        item.setIsHazardous(Optional.ofNullable(record.get("是否危化品")).map(Object::toString).map(String::trim).map("是"::equals).orElse(false));
        item.setIsInvAvailable(Optional.ofNullable(record.get("是否有库存")).map(Object::toString).map(String::trim).map("是"::equals).orElse(false));
        item.setIsSapMaterial(Optional.ofNullable(record.get("是否SAP料号")).map(Object::toString).map(String::trim).map("是"::equals).orElse(false));
        item.setHeatValue(Optional.ofNullable(record.get("热度值")).map(Object::toString).map(Integer::parseInt).orElse(0));
        item.setDescription(Optional.ofNullable(record.get("备注")).map(Object::toString).map(String::trim).orElse(""));
        item.setDept(dept);
        item.setEnabled(true);
        return item;
    }


    @Override
    public String importBigItem(Map<String, Object> readAll) {
        String re = "";
        String code = readAll.get("完成品品番") == null ? null : readAll.get("完成品品番").toString().trim();
        String name = readAll.get("完成品型式名") == null ? null : readAll.get("完成品型式名").toString().trim();
        String models = readAll.get("机种") == null ? null : readAll.get("机种").toString().trim();
        String country = readAll.get("国别") == null ? null : readAll.get("国别").toString().trim();
        String outboundType = readAll.get("出库类型") == null ? null : readAll.get("出库类型").toString().trim();
        if (code.length() > 0) {
            BigItem bigItem = bigItemRepository.findByCode(code);
            if (bigItem == null) {
                re = "a";
                bigItem = new BigItem();
                bigItem.setCode(code);
                bigItem.setDeptId(UserUtils.getDept().getId());
            } else {
                //新增物料
                //itemsToCreate.add(createItem(dept, record));
            }
            bigItem.setModels(models);
            bigItem.setName(name);
            bigItem.setCountry(country);
            bigItem.setOutboundType(outboundType);
            bigItem.setEnabled(true);
            if (re.equals("a")) {
                bigItemService.create(bigItem);
            } else if (re.equals("b")) {
                bigItemService.update(bigItem);
            }
        }
        return re;
    }

    @Override
    public String importAsnDetail(Map<String, Object> readAll, Asn asn) {
        String re = "";
        String code = readAll.get("品番") == null ? null : readAll.get("品番").toString();
        String qty = readAll.get("数量") == null ? null : readAll.get("数量").toString();
        String zzkw = readAll.get("制造库位") == null ? null : readAll.get("制造库位").toString();
        if (code.length() > 0) {
            Item item = itemRepository.findByCode(code);
            if (item == null) {
                return "部品品番无效";
            }
            Point point = pointService.getPoint(zzkw, null, null, null);
            if (point == null) {
                return "制造库位无效";
            }
            List<BomAccount> boms = bomAccountRepository.queryBomUnique(asn.getArea().getId(), item.getId(), point.getId());
            if (boms.size() <= 0) {
                return "BOM工位清单不存在";
            }
            AsnDetail asnDetail = new AsnDetail();
            asnDetail.setAsn(asn);
            asnDetail.setDept(UserUtils.getDept());
            asnDetail.setStatus(BizStatus.OPEN);
            asnDetail.setItem(item);
            asnDetail.setPoint(point);
            asnDetail.setOrderQty(Double.parseDouble(qty));
            asnDetailService.create(asnDetail);
            asn.setOrderQuantity(asn.getOrderQuantity() + asnDetail.getOrderQty());
            asnService.update(asn);
        }
        return re;
    }

    @Override
    public String importPickDetail(Map<String, Object> readAll, PickTicket pickTicket) {
        String re = "";
        String code = "" + readAll.get("品番");
        String qty = "" + readAll.get("数量");
        String zzkw = "" + readAll.get("制造库位");
        String remark = "" + readAll.get("备注");
        if (code.length() > 0) {
            Item item = itemRepository.findByCode(code);
            if (item == null) {
                return "部品品番无效";
            }
            Point point = pointService.getPoint(zzkw, null, null, null);
            Long zzkwId = null;
            if (point == null) {
                if (pickTicket.getArea().getBexb()) {
                    return "制造库位无效";
                }
            } else {
                zzkwId = point.getId();
            }
//            List<BomAccount> boms= bomAccountRepository.queryBomUnique(pickTicket.getArea().getId(),item.getId(), point.getId());
//            if(boms.size()<=0){
//                return "BOM工位清单不存在";
//            }
            Double xbQty = inventoryService.getInvQty(item.getId(), pickTicket.getArea().getId(), zzkwId);
            if (xbQty.intValue() < Double.parseDouble(qty)) {
                return "库存不足";
            }
            PickDetail pickDetail = new PickDetail();
            pickDetail.setPickTicket(pickTicket);
            pickDetail.setDept(UserUtils.getDept());
            pickDetail.setStatus(BizStatus.OPEN);
            pickDetail.setItem(item);
            pickDetail.setPoint(point);
            pickDetail.setRemark(remark);
            pickDetail.setArea(pickTicket.getArea());
            pickDetail.setOrderQty(Double.parseDouble(qty));
            pickDetailService.create(pickDetail);
            pickTicket.setOrderQuantity(pickTicket.getOrderQuantity() + pickDetail.getOrderQty());
            pickTicketService.update(pickTicket);

        }
        return re;
    }
}
