package com.ecep.contract.cloud.u8.ctx;

import static com.ecep.contract.SpringApp.getBean;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Collectors;

import org.hibernate.Hibernate;
import org.springframework.data.domain.Sort;
import org.springframework.util.StringUtils;

import com.ecep.contract.MessageHolder;
import com.ecep.contract.SpringApp;
import com.ecep.contract.constant.CloudServiceConstant;
import com.ecep.contract.ds.contract.service.ContractService;
import com.ecep.contract.ds.contract.service.SaleOrdersService;
import com.ecep.contract.ds.contract.service.SalesBillVoucherService;
import com.ecep.contract.model.Company;
import com.ecep.contract.model.CompanyCustomer;
import com.ecep.contract.model.CompanyCustomerEntity;
import com.ecep.contract.model.Contract;
import com.ecep.contract.model.Inventory;
import com.ecep.contract.model.SalesBillVoucher;
import com.ecep.contract.model.SalesBillVoucherItem;
import com.ecep.contract.model.SalesOrder;
import com.ecep.contract.util.NumberUtils;

import lombok.Setter;

public class SalesBillVoucherCtx extends AbstractYongYouU8Ctx {
    @Setter
    private ContractService contractService;
    @Setter
    private SaleOrdersService saleOrdersService;
    @Setter
    private SalesBillVoucherService salesBillVoucherService;

    InventoryCtx inventoryCtx;

    ContractService getContractService() {
        if (contractService == null) {
            contractService = getBean(ContractService.class);
        }
        return contractService;
    }

    SaleOrdersService getSaleOrdersService() {
        if (saleOrdersService == null) {
            saleOrdersService = getBean(SaleOrdersService.class);
        }
        return saleOrdersService;
    }

    SalesBillVoucherService getSalesBillVoucherService() {
        if (salesBillVoucherService == null) {
            salesBillVoucherService = SpringApp.getBean(SalesBillVoucherService.class);
        }
        return salesBillVoucherService;
    }

    InventoryCtx getInventoryCtx() {
        if (inventoryCtx == null) {
            inventoryCtx = new InventoryCtx();
            inventoryCtx.from(this);
        }
        return inventoryCtx;
    }

    public void syncByCompany(Company company, MessageHolder holder) {

        List<SalesBillVoucher> vouchers = salesBillVoucherService.findAll((root, q, cb) -> {
            return cb.equal(root.get("company"), company);
        }, Sort.unsorted());
        holder.debug("查找到 " + vouchers.size() + " 条专用发票记录在数据库中");
        Map<Integer, SalesBillVoucher> voucherMap = vouchers.stream().collect(Collectors.toMap(SalesBillVoucher::getRefId, item -> item));

        CompanyCustomer customer = getCompanyCustomerService().findByCompany(company);
        if (customer != null) {
            List<CompanyCustomerEntity> entities = getCompanyCustomerEntityService().findAllByCustomer(customer);
            for (CompanyCustomerEntity entity : entities) {
                // 查询 U8 数据库
                List<Map<String, Object>> ds = repository.findAllSalesBillVoucherByCustomerCode(entity.getCode());
                holder.debug("查找" + entity.getCode() + "到 " + ds.size() + " 条专用发票记录在 " + CloudServiceConstant.U8_NAME);

                for (Map<String, Object> map : ds) {
                    Integer sbvid = (Integer) map.get("SBVID");
                    if (sbvid == 0) {
                        holder.warn("跳过无效专用发票记录：缺少 SBVID");
                        continue;
                    }
                    SalesBillVoucher voucher = voucherMap.get(sbvid);
                    boolean voucherModified = false;
                    if (voucher == null) {
                        voucher = new SalesBillVoucher();
                        voucher.setCompany(company);
                        voucher.setRefId(sbvid);
                        voucherMap.put(sbvid, voucher);
                        voucherModified = true;

                        holder.info("新增专用发票记录 #" + sbvid);
                    }
                    if (applySalesBillVoucherDetail(voucher, map, holder)) {
                        voucherModified = true;
                    }

                    if (voucherModified) {
                        voucher = salesBillVoucherService.save(voucher);
                        voucherMap.put(sbvid, voucher);
                    }
                }
            }
        }

        List<SalesBillVoucherItem> items = salesBillVoucherService.findAllItems((root, q, cb) -> {
            return cb.equal(root.get("voucher").get("company"), company);
        }, Sort.unsorted());

        // 按 order 分组
        Map<SalesBillVoucher, Map<Integer, SalesBillVoucherItem>> itemMap = items.stream().collect(Collectors.groupingBy(SalesBillVoucherItem::getVoucher,
                Collectors.toMap(SalesBillVoucherItem::getRefId, item -> item)));
        for (SalesBillVoucher voucher : voucherMap.values()) {

            // 查询 U8 数据库
            List<Map<String, Object>> ds = repository.findAllSalesBillVoucherItemBySBVID(voucher.getRefId());
            holder.debug("专用发票#" + voucher.getRefId() + "查找到 " + ds.size() + "条条目记录在 " + CloudServiceConstant.U8_NAME);
            Map<Integer, SalesBillVoucherItem> subItemMap = itemMap.computeIfAbsent(voucher, k -> new HashMap<>());
            for (Map<String, Object> map : ds) {
                Integer refId = (Integer) map.get("ID");
                if (refId == 0) {
                    holder.warn("跳过无效专用发票记录：缺少 ID");
                    continue;
                }
                SalesBillVoucherItem item = subItemMap.remove(refId);
                boolean itemModified = false;
                if (item == null) {
                    item = new SalesBillVoucherItem();
                    item.setVoucher(voucher);
                    item.setRefId(refId);
                    itemModified = true;

                    holder.info("新增专用发票条目 #" + refId);
                }
                MessageHolder subHolder = holder.sub("---| ");
                if (applySalesBillVoucherItemDetail(item, map, subHolder)) {
                    itemModified = true;
                }
                if (itemModified) {
                    item = salesBillVoucherService.save(item);
                }
            }
            for (SalesBillVoucherItem item : subItemMap.values()) {
                holder.info("删除无效专用发票条目");
                salesBillVoucherService.delete(item);
            }
        }
    }

    public void syncBySalesOrder(SalesOrder order, MessageHolder holder) {
        SalesBillVoucherService voucherService = getSalesBillVoucherService();
        List<SalesBillVoucher> vouchers = voucherService.findAll((root, q, cb) -> {
            return cb.equal(root.get("order"), order);
        }, Sort.unsorted());
        holder.debug("查找到 " + vouchers.size() + " 条专用发票记录在数据库中");
        Map<Integer, SalesBillVoucher> voucherMap = vouchers.stream().collect(Collectors.toMap(SalesBillVoucher::getRefId, item -> item));
        {
            // 查询 U8 数据库
            List<Map<String, Object>> ds = repository.findAllSalesBillVoucherBySalesOrderCode(order.getCode());
            holder.debug("查找" + order.getCode() + "到 " + ds.size() + " 条专用发票记录在 " + CloudServiceConstant.U8_NAME);

            for (Map<String, Object> map : ds) {
                Integer sbvid = (Integer) map.get("SBVID");
                if (sbvid == 0) {
                    holder.warn("跳过无效专用发票记录：缺少 SBVID");
                    continue;
                }
                SalesBillVoucher voucher = voucherMap.get(sbvid);
                boolean voucherModified = false;
                if (voucher == null) {
                    voucher = new SalesBillVoucher();

                    Contract contract = order.getContract();
                    if (!Hibernate.isInitialized(contract)) {
                        contract = getContractService().findById(contract.getId());
                    }
                    voucher.setCompany(contract.getCompany());
                    voucher.setRefId(sbvid);
                    voucherMap.put(sbvid, voucher);
                    voucherModified = true;

                    holder.info("新增专用发票记录 #" + sbvid);
                }
                if (applySalesBillVoucherDetail(voucher, map, holder)) {
                    voucherModified = true;
                }

                if (voucherModified) {
                    voucher = voucherService.save(voucher);
                    voucherMap.put(sbvid, voucher);
                }
            }
        }

        List<SalesBillVoucherItem> items = voucherService.findAllItems((root, q, cb) -> {
            return cb.equal(root.get("voucher").get("order"), order);
        }, Sort.unsorted());

        // 按 order 分组
        Map<SalesBillVoucher, Map<Integer, SalesBillVoucherItem>> itemMap = items.stream().collect(Collectors.groupingBy(SalesBillVoucherItem::getVoucher,
                Collectors.toMap(SalesBillVoucherItem::getRefId, item -> item)));
        for (SalesBillVoucher voucher : voucherMap.values()) {

            // 查询 U8 数据库
            List<Map<String, Object>> ds = repository.findAllSalesBillVoucherItemBySBVID(voucher.getRefId());
            holder.debug("专用发票#" + voucher.getRefId() + "查找到 " + ds.size() + "条条目记录在 " + CloudServiceConstant.U8_NAME);
            Map<Integer, SalesBillVoucherItem> subItemMap = itemMap.computeIfAbsent(voucher, k -> new HashMap<>());
            for (Map<String, Object> map : ds) {
                Integer refId = (Integer) map.get("AutoID");
                if (refId == 0) {
                    holder.warn("跳过无效专用发票记录：缺少 AutoID");
                    continue;
                }
                SalesBillVoucherItem item = subItemMap.remove(refId);
                boolean itemModified = false;
                if (item == null) {
                    item = new SalesBillVoucherItem();
                    item.setVoucher(voucher);
                    item.setRefId(refId);
                    itemModified = true;

                    holder.info("新增专用发票条目 #" + refId);
                }
                MessageHolder subHolder = holder.sub("---| ");
                if (applySalesBillVoucherItemDetail(item, map, subHolder)) {
                    itemModified = true;
                }
                if (itemModified) {
                    item = voucherService.save(item);
                }
            }
            for (SalesBillVoucherItem item : subItemMap.values()) {
                holder.info("删除无效专用发票条目");
                voucherService.delete(item);
            }
        }
    }


    private boolean applySalesBillVoucherDetail(SalesBillVoucher voucher, Map<String, Object> map, MessageHolder holder) {
        String code = String.valueOf(map.get("SBVID"));
        String customerCode = (String) map.get("cCusCode");
        String salesOrderCode = (String) map.get("cSOCode");
        String personCode = (String) map.get("cPersonCode");
        String inCode = (String) map.get("cDLCode");
        Timestamp billDate = (Timestamp) map.get("dDate");

        String maker = (String) map.get("cMaker");
        String checker = (String) map.get("cChecker");
        String modifier = (String) map.get("cmodifier");
        String verifier = (String) map.get("cVerifier");
        Timestamp makeTime = (Timestamp) map.get("cmaketime");
        Timestamp verifyTime = (Timestamp) map.get("dverifysystime");
        Timestamp modifyTime = (Timestamp) map.get("dmodifysystime");

        String description = (String) map.get("cMemo");


        boolean modified = false;

        holder.debug("条目：" + code + " x " + salesOrderCode);
        if (updateCompanyByCustomerCode(voucher::getCompany, voucher::setCompany, customerCode, holder, "客户")) {
            modified = true;
        }

        SalesOrder salesOrder = null;
        if (StringUtils.hasText(salesOrderCode)) {
            salesOrder = getSaleOrdersService().findByCode(salesOrderCode);
        }
        if (salesOrder == null) {
            voucher.setOrder(null);
            holder.warn("无效销售订单：" + salesOrderCode);
            modified = true;
        } else {
            if (!Objects.equals(voucher.getOrder(), salesOrder)) {
                voucher.setOrder(salesOrder);
                holder.info("销售订单修改为: " + salesOrder.getCode());
                modified = true;
            }
        }
        if (updateEmployeeByCode(voucher::getEmployee, voucher::setEmployee, personCode, holder, "业务员")) {
            modified = true;
        }
        if (updateEmployeeByName(voucher::getMaker, voucher::setMaker, maker, holder, "制单人")) {
            modified = true;
        }
        if (updateEmployeeByName(voucher::getVerifier, voucher::setVerifier, verifier, holder, "审核人")) {
            modified = true;
        }

        if (updateLocalDateTime(voucher::getMakerDate, voucher::setMakerDate, makeTime, holder, "制单时间")) {
            modified = true;
        }
        if (updateLocalDateTime(voucher::getVerifierDate, voucher::setVerifierDate, verifyTime, holder, "审核时间")) {
            modified = true;
        }

        if (!Objects.equals(voucher.getDescription(), description)) {
            voucher.setDescription(description);
            holder.info("描述修改为: " + description);
            modified = true;
        }
        return modified;
    }


    private boolean applySalesBillVoucherItemDetail(SalesBillVoucherItem item, Map<String, Object> map, MessageHolder holder) {
        String code = String.valueOf(map.get("ID"));
        String inventoryCode = (String) map.get("cInvCode");
        String contractCode = (String) map.get("ContractCode");

        String title = (String) map.get("cInvCode");
        double quantity = (double) map.get("iQuantity");
        double taxRate = (double) map.get("iTaxRate");
        double taxPrice = (double) map.get("iTaxUnitPrice");
        BigDecimal amount = (BigDecimal) map.get("iSum");


        Timestamp signDate = (Timestamp) map.get("dSignDate");

        boolean modified = false;

        holder.debug("条目：" + title + " x " + amount);

        if (updateInventory(item::getInventory, item::setInventory, inventoryCode, holder, "商品")) {
            modified = true;
        }

        if (!NumberUtils.equals(item.getPrice(), taxPrice)) {
            item.setPrice(taxPrice);
            holder.info("含税单价修改为: " + taxPrice);
            modified = true;
        }
        if (!NumberUtils.equals(item.getQuantity(), quantity)) {
            item.setQuantity(quantity);
            holder.info("数量修改为: " + quantity);
            modified = true;
        }
        if (!Objects.equals(item.getDescription(), contractCode)) {
            item.setDescription(contractCode);
            holder.info("描述修改为: " + contractCode);
            modified = true;
        }
        return modified;
    }

    boolean updateInventory(Supplier<Inventory> getter, Consumer<Inventory> setter, String inventoryCode, MessageHolder holder, String topic) {
        return getInventoryCtx().syncInventoryDetailByCode(getter, setter, inventoryCode, holder, topic);
    }
}
