package com.fjhx.sale.service.documents.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONWriter;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fjhx.area.utils.CustomizeAreaUtil;
import com.fjhx.common.constant.SourceConstant;
import com.fjhx.common.entity.corporation.po.Corporation;
import com.fjhx.common.service.corporation.CorporationService;
import com.fjhx.customer.entity.customer.po.Customer;
import com.fjhx.customer.service.customer.CustomerService;
import com.fjhx.flow.service.flow.FlowExampleService;
import com.fjhx.item.service.product.ProductInfoService;
import com.fjhx.sale.entity.contract.po.Contract;
import com.fjhx.sale.entity.contract.po.ContractProject;
import com.fjhx.sale.entity.contract.vo.ContractVo;
import com.fjhx.sale.entity.documents.dto.DocumentsDto;
import com.fjhx.sale.entity.documents.dto.DocumentsSelectDto;
import com.fjhx.sale.entity.documents.po.Documents;
import com.fjhx.sale.entity.documents.po.DocumentsPdf;
import com.fjhx.sale.entity.documents.po.DocumentsProduct;
import com.fjhx.sale.entity.documents.po.DocumentsTransport;
import com.fjhx.sale.entity.documents.vo.DocumentsVo;
import com.fjhx.sale.entity.pack.po.PackDetail;
import com.fjhx.sale.entity.pack.po.PackDetailGoods;
import com.fjhx.sale.entity.pack.po.PackShipment;
import com.fjhx.sale.mapper.documents.DocumentsMapper;
import com.fjhx.sale.service.contract.ContractProjectService;
import com.fjhx.sale.service.contract.ContractService;
import com.fjhx.sale.service.documents.DocumentsPdfService;
import com.fjhx.sale.service.documents.DocumentsProductService;
import com.fjhx.sale.service.documents.DocumentsService;
import com.fjhx.sale.service.documents.DocumentsTransportService;
import com.fjhx.sale.service.pack.PackDetailGoodsService;
import com.fjhx.sale.service.pack.PackDetailProductService;
import com.fjhx.sale.service.pack.PackDetailService;
import com.fjhx.sale.service.pack.PackShipmentService;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.wrapper.IWrapper;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;


/**
 * <p>
 * 单证表 服务实现类
 * </p>
 *
 * @author
 * @since 2023-04-20
 */
@Service
public class DocumentsServiceImpl extends ServiceImpl<DocumentsMapper, Documents> implements DocumentsService {
    @Autowired
    private DocumentsProductService documentsProductService;

    @Autowired
    private ContractService contractService;

    @Autowired
    private PackDetailService packDetailService;

    @Autowired
    private PackDetailGoodsService packDetailGoodsService;

    @Autowired
    private PackDetailProductService packDetailProductService;

    @Autowired
    private DocumentsTransportService documentsTransportService;

    @Autowired
    private CorporationService corporationService;

    @Autowired
    private PackShipmentService packShipmentService;

    @Autowired
    private CustomerService customerService;

    @Autowired
    private DocumentsPdfService documentsPdfService;

    @Autowired
    private ProductInfoService productInfoService;

    @Autowired
    private ContractProjectService contractProjectService;

    @Autowired
    private FlowExampleService flowExampleService;

    private static final SimpleDateFormat sdf = new SimpleDateFormat("dd/MMM/yyyy", Locale.ENGLISH);

    /**
     * 单证表分页
     */
    @Override
    public Page<DocumentsVo> getPage(DocumentsSelectDto dto) {
        IWrapper<Documents> wrapper = getWrapper();
        wrapper.orderByDesc("d", Documents::getCreateTime);
        if (StringUtils.isNotEmpty(dto.getKeyword())) {
            //归属公司
            List<Long> corporationIds = corporationService.listObject(Corporation::getId, q -> q.like(Corporation::getName, dto.getKeyword()));
            List<Long> customerIds = customerService.listObject(Customer::getId, q -> q.like(Customer::getName, dto.getKeyword()));
            wrapper.and(q -> q
                    .like("c", Contract::getCode, dto.getKeyword())
                    .or().in("c", Contract::getSellCorporationId, corporationIds)
                    .or().in("c", Contract::getBuyCorporationId, customerIds)
            );
        }
        Page<DocumentsVo> page = this.baseMapper.getPage(dto.getPage(), wrapper);
        //切换数据源
        DynamicDataSourceContextHolder.push(SourceConstant.COMMON);
        //查询公司名称信息
        List<Corporation> corporationList = corporationService.list();
        Map<Long, List<Corporation>> corporationMap = corporationList.stream().collect(Collectors.groupingBy(Corporation::getId));
        DynamicDataSourceContextHolder.poll();

        List<DocumentsVo> records = page.getRecords();
        if (ObjectUtil.isEmpty(records)) {
            return page;
        }
        for (DocumentsVo record : records) {
            //赋值归属公司名称
            List<Corporation> corporationList2 = corporationMap.get(record.getSellCorporationId());
            if (ObjectUtil.isNotEmpty(corporationList2)) {
                record.setSellCorporationName(corporationList2.get(0).getName());
            }
        }
        //赋值客户名称
        customerService.attributeAssign(records, DocumentsVo::getBuyCorporationId, (item, customer) -> {
            item.setBuyCorporationName(customer.getName());
        });
        //  赋值流程id
        flowExampleService.setFlowId(records, DocumentsVo::getContractId, DocumentsVo::setFlowId);
        return page;
    }

    @Override
    public DocumentsVo detail(Long id) {
        Documents Documents = this.getById(id);
        DocumentsVo result = BeanUtil.toBean(Documents, DocumentsVo.class);
        return result;
    }

    /**
     * 单证表新增
     */
    @Override
    public void add(DocumentsDto documentsDto) {
        //添加单证表的数据
        this.save(documentsDto);

        //添加单证-产品信息
        List<DocumentsProduct> documentsProductList = documentsDto.getDocumentsProductList();
        documentsProductList.forEach(documentsProduct -> documentsProduct.setDocumentsId(documentsDto.getId()));
        documentsProductService.saveBatch(documentsProductList);
    }

    @Override
    public void edit(DocumentsDto documentsDto) {
        this.updateById(documentsDto);
    }

    /**
     * 单证表删除
     */
    @Override
    public void delete(Long id) {
        //删除单证表的数据
        this.removeById(id);
        //删除单证-产品表的数据
        documentsProductService.remove(Wrappers.<DocumentsProduct>lambdaQuery().eq(DocumentsProduct::getDocumentsId, id));

        //删除单证-货运表的数据
        documentsTransportService.remove(Wrappers.<DocumentsTransport>lambdaQuery().eq(DocumentsTransport::getDocumentsId, id));
    }

    /**
     * 生成PDF---商业发票、装箱单
     *
     * @return
     */
    @Override
    public Map<String, Object> generateInvoiceAPackPdf(Long id) {
        Map<String, Object> map = new HashMap<>();
        //查询单证
        Documents documents = this.getById(id);
        if (ObjectUtil.isEmpty(documents)) {
            throw new ServiceException("单证不存在");
        }
        setDocumentArea(documents);
        //查询合同
        Contract contract = contractService.getById(documents.getContractId());
        if (ObjectUtil.isEmpty(contract)) {
            throw new ServiceException("该单证合同不存在");
        }
        //查询合同
        ContractVo contractVo = BeanUtil.toBean(contract, ContractVo.class);
        setContractArea(contractVo);
        //查询收费项目
        List<ContractProject> contractProjectList = contractProjectService.list(Wrappers.<ContractProject>query().lambda().eq(ContractProject::getContractId, contractVo.getId()));
        //查询买方
        Customer customer = customerService.getById(contractVo.getBuyCorporationId());
        //查询卖方
        Corporation corporation = corporationService.getById(contractVo.getSellCorporationId());
        //查询单证货物
        List<DocumentsProduct> documentsProducts = documentsProductService.getDpList(documents.getId());
        // 赋值产品属性
        productInfoService.attributeAssign(documentsProducts, DocumentsProduct::getProductId, (item, product) -> {
            item.setProductCode(product.getCode());
            item.setProductUnit(product.getUnit());
            item.setProductName(product.getName());
            item.setProductSpec(product.getSpec());
        });
        Map<Long, List<DocumentsProduct>> docuProductMap = documentsProducts.stream().collect(Collectors.groupingBy(DocumentsProduct::getPackDetailId));
        PackShipment packShipment = packShipmentService.getById(documents.getPackShipmentId());
        //装箱单
        List<PackDetail> packDetailList = new ArrayList<>();
        //总毛重
        BigDecimal sumRoughWeight = BigDecimal.ZERO;
        //总净重
        BigDecimal sumNetWeight = BigDecimal.ZERO;
        //总体积
        BigDecimal sumBomVolume = BigDecimal.ZERO;
        //总件数
        BigDecimal sumPackQuantity = BigDecimal.ZERO;
        //装箱商品明细
        List<PackDetailGoods> packDetailGoodsList = new ArrayList<>();
        if (ObjectUtil.isNotEmpty(packShipment)) {//查询装箱单
            packDetailList = packDetailService.list(Wrappers.<PackDetail>query().lambda().in(PackDetail::getId, Arrays.asList(packShipment.getPackDetailIds().split(","))));
            List<Long> packDetailIds = packDetailList.stream().map(PackDetail::getId).collect(Collectors.toList());
            packDetailGoodsList = packDetailGoodsService.list(Wrappers.<PackDetailGoods>query().lambda().in(PackDetailGoods::getPackDetailId, packDetailIds));
            Map<Long, List<PackDetailGoods>> packGoodMap = packDetailGoodsList.stream().collect(Collectors.groupingBy(PackDetailGoods::getPackDetailId));
            for (PackDetail p : packDetailList) {
                p.setPackDetailGoodsList(packGoodMap.getOrDefault(p.getId(), null));
                p.setDocumentsProductList(docuProductMap.getOrDefault(p.getId(), null));
            }
            sumPackQuantity = packDetailList.stream().map(PackDetail::getPackQuantity).reduce(BigDecimal.ZERO, BigDecimal::add);
            sumRoughWeight = packDetailList.stream().map(PackDetail::getRoughWeight).reduce(BigDecimal.ZERO, BigDecimal::add);
            sumNetWeight = packDetailList.stream().map(PackDetail::getNetWeight).reduce(BigDecimal.ZERO, BigDecimal::add);
            sumBomVolume = packDetailList.stream().map(PackDetail::getBomVolume).reduce(BigDecimal.ZERO, BigDecimal::add);
        }
        map.put("contract", contractVo);//合同信息
        map.put("date", sdf.format(contractVo.getCreateTime()));//日期
        map.put("documents", documents);//单证信息
        map.put("documentsProducts", documentsProducts);//单证信息货物
        map.put("packDetailList", packDetailList);//单证信息货物
        map.put("sumRoughWeight", sumRoughWeight);//总毛重
        map.put("sumNetWeight", sumNetWeight);//总净重
        map.put("sumBomVolume", sumBomVolume);//总体积
        map.put("sumPackQuantity", sumPackQuantity);//总箱数
        map.put("customer", customer);//买方信息
        map.put("corporation", corporation);//卖方信息
        map.put("contractProjectList", contractProjectList);//卖方信息

//        map.put("packDetailGoodsList",packDetailGoodsList);//装箱商品明细
        return map;
    }

    /**
     * 生成pdf----报关单
     *
     * @param id
     * @return
     */
    @Override
    public DocumentsPdf generateClearanceePdf(Long id) {
        //获取单证PDF数据
        DocumentsPdf pdfData = documentsPdfService.getOne(Wrappers.<DocumentsPdf>query().lambda()
                .eq(DocumentsPdf::getDocumentId, id).eq(DocumentsPdf::getDataType, 0));
        if (ObjectUtil.isEmpty(pdfData)) {
            JSONObject data = new JSONObject();
            List<JSONObject> productData = new ArrayList<>();
            pdfData = new DocumentsPdf();
            //获取初始数据
            Map<String, Object> dataMap = generateInvoiceAPackPdf(id);

            //单证信息
            Documents documents = (Documents) dataMap.get("documents");
            //合同信息
            ContractVo contract = (ContractVo) dataMap.get("contract");
            //产品信息
            List<DocumentsProduct> products = (List<DocumentsProduct>) dataMap.get("documentsProducts");
            //卖方信息
            Corporation corporation = (Corporation) dataMap.get("corporation");
            //买方信息
            Customer customer = (Customer) dataMap.get("customer");
            //箱子的总毛重、净重
            Map<String, BigDecimal> packingWeightMap = (Map<String, BigDecimal>) dataMap.get("packingWeightMap");
            //总箱数
            BigDecimal sumPackQuantity = (BigDecimal) dataMap.get("sumPackQuantity");

            //获取合同其他收费项目
            List<ContractProject> contractProjectList = contractProjectService.list(q -> q.eq(ContractProject::getContractId, contract.getId()));
            BigDecimal contractProjectAmountCount = contractProjectList.stream().map(ContractProject::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
            //获取买方 客户信息里面的 国家名称
            Map<Long, String> buyCountryAreaMapByIds = CustomizeAreaUtil.getAreaMapByIds(Arrays.asList(customer.getCountryId()));
            String buyCountryName = buyCountryAreaMapByIds.get(customer.getCountryId());

            //------------------ 封装页面展示数据 ------------------
            //发件公司清关负责人
            data.put("contacts", contract.getSellContactName());
            //发件公司清关负责人联系电话/手机
            data.put("contactsMobile", contract.getSellContactNumber());
            //联系人邮箱
            data.put("contactsEmail", "");
            //境内发货人名称（填写发货公司中文名称）
            data.put("companyNameChinese", corporation.getName());
            //境内发货人代码（填写18位统一社会信用代码,没有信用证代码填报10位海关备案编码）
            data.put("organizationCode", corporation.getIaeeCode());
            //出境关别（不用填写）
            data.put("exitCustoms", "");
            //备案号（如是手册的请填写）
            data.put("recordNo", "");
            //境外收货人（指合同买方或合同指定的收货人公司英文名称）
            data.put("customerCompanyName", customer.getName());
            //境外收货人代码（AEO互认企业需填报AEO编码；不填默认非AEO互认）
            data.put("overseasConsigneeCode", "");
            //运输方式（不用填写）
            data.put("typeOfShipping", "");
            //运输工具名称及航次号（不用填写）
            data.put("meansOfTransport", "");
            //提运单号（指12位快递运单号码）
            data.put("waybillCode", "");
            //生产销售单位（指生产该产品的公司名称）
            data.put("productCompanyNameChinese", corporation.getName());
            //生产销售单位代码（填写18位统一社会信用代码，没有信用证代码填写“NO”）
            data.put("productOrganizationCode", corporation.getIaeeCode());
            //监管方式
            data.put("supervisionMode", "");
            //征免性质（与监管方式对应填写）
            data.put("exemptionNature", "");
            //许可证号（如需许可证的请填写）
            data.put("licenseKey", "");
            //合同协议号（根据合同填写）
            data.put("contractCode", contract.getCode());
            //贸易国（合同买方所在国）
            data.put("tradingCountry", buyCountryName);
            //运抵国
            data.put("arrivalCountry", buyCountryName);//原来是documents.getCountryName()
            //指运港（不用填写）
            data.put("portOfDestination", "");
            //离境口岸（不用填写）
            data.put("departurePort", "");
            //包装种类
            data.put("packageType", "");
            //件数（运单和装箱单一致）
            data.put("sumPackQuantity", sumPackQuantity);
            //毛重（千克）
            data.put("sumRoughWeight", dataMap.get("sumRoughWeight"));
            //净重（千克）
            data.put("sumNetWeight", dataMap.get("sumNetWeight"));
            //总体积 立方米
            data.put("sumBomVolume", dataMap.get("sumBomVolume"));
            //成交方式
            data.put("tradeModeName", contract.getTradeMethods());
            //运费
            data.put("freightPrice", contractProjectAmountCount);//暂无
            // 保费
            data.put("premiumPrice", BigDecimal.ZERO);//暂无
            // 杂费（如有请填写）
            data.put("incidentalPrice", "");
            // 随附单证及编号（常见如通关单号、原进口报关单号）
            data.put("documentsAttached", "");
            // 标记唛码及备注
            data.put("shippingMark", documents.getRemark());
            // 境内货源地
            data.put("cityChinese", contract.getSellCountryName());
            //获取卖方公司 多公司信息里的国家信息
            Map<Long, String> areaMapByIds = CustomizeAreaUtil.getAreaMapByIds(Arrays.asList(corporation.getCountryId()));
            String sellCountryName = areaMapByIds.get(corporation.getCountryId());

            // 产品数据
            if (CollectionUtils.isNotEmpty(products)) {
                Integer num = 1;
                for (DocumentsProduct product : products) {
                    JSONObject object = new JSONObject();
                    // 项号
                    object.put("num", num);
                    //产品id
                    object.put("productId", product.getProductId());
                    // 商品编号(13位)原10位海关编码+3位检验检疫附加编码
                    object.put("customsCode", product.getCustomsCode());
                    // 商品名称
                    object.put("productName", product.getSubDescribe());
                    //品牌
                    object.put("brand", "");
                    //品牌类型
                    object.put("brandType", "");
                    //出口享惠情况（不填写则默认不享受）
                    object.put("exportBenefits", "");
                    //型号
                    object.put("productModelChinese", "");
                    //税号所需申报要素(如:用途、材质等）
                    object.put("declareRemark", "");
                    //各项净重
                    object.put("netWeight", "");//暂无
                    //成交数量
                    object.put("quantity", product.getQuantity());
                    //成交单位
                    object.put("unit", product.getProductUnit());
                    //原产国（地区）
                    object.put("countryChinese", sellCountryName);
                    //总价与币制
                    object.put("sumPrice", "");
                    //成交单价
                    object.put("declaredPrice", "");//暂无
                    //EXW单价
                    object.put("exwPrice", "");//暂无
                    productData.add(object);
                    num++;
                }
            }
            data.put("products", productData);

            pdfData.setDocumentId(documents.getId());
            pdfData.setContractCode(contract.getCode());
            pdfData.setDataType(0);//报关单
            pdfData.setContent(JSONObject.toJSONString(data, JSONWriter.Feature.WriteLongAsString));
        }
        return pdfData;
    }

    /**
     * 获取合同数据
     *
     * @param id
     * @return
     */
    @Override
    public Map<String, Object> getContractDataById(Long id) {
        return baseMapper.getContractDataById(id);
    }

    /**
     * 赋值买卖公司国家省市区名称
     */
    private void setContractArea(ContractVo contractVo) {

        List<Long> areaIdList = Arrays.asList(
                contractVo.getBuyCountryId(),
                contractVo.getBuyProvinceId(),
                contractVo.getBuyCityId(),
                contractVo.getSellCountryId(),
                contractVo.getSellProvinceId(),
                contractVo.getSellCityId()
        );
        Map<Long, String> areaMap = CustomizeAreaUtil.getAreaMapByIds(areaIdList);
        contractVo.setBuyCountryName(areaMap.getOrDefault(contractVo.getBuyCountryId(), contractVo.getBuyCountryName()));
        contractVo.setBuyProvinceName(areaMap.getOrDefault(contractVo.getBuyProvinceId(), contractVo.getBuyProvinceName()));
        contractVo.setBuyCityName(areaMap.getOrDefault(contractVo.getBuyCityId(), contractVo.getBuyCityName()));
        contractVo.setSellCountryName(areaMap.getOrDefault(contractVo.getSellCountryId(), contractVo.getSellCountryName()));
        contractVo.setSellProvinceName(areaMap.getOrDefault(contractVo.getSellProvinceId(), contractVo.getSellProvinceName()));
        contractVo.setSellCityName(areaMap.getOrDefault(contractVo.getSellCityId(), contractVo.getSellCityName()));
    }

    /**
     * 赋值单证目的国家名称
     */
    private void setDocumentArea(Documents documents) {

        List<Long> areaIdList = Collections.singletonList(documents.getCountryId());
        Map<Long, String> areaMap = CustomizeAreaUtil.getAreaMapByIds(areaIdList);

        documents.setCountryName(areaMap.get(documents.getCountryId()));
    }
}
