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.springframework.data.domain.Sort;

import com.ecep.contract.MessageHolder;
import com.ecep.contract.constant.CloudServiceConstant;
import com.ecep.contract.ds.contract.service.PurchaseBillVoucherItemService;
import com.ecep.contract.ds.contract.service.PurchaseBillVoucherService;
import com.ecep.contract.ds.contract.service.PurchaseOrderItemService;
import com.ecep.contract.ds.contract.service.PurchaseOrdersService;
import com.ecep.contract.model.Company;
import com.ecep.contract.model.CompanyVendor;
import com.ecep.contract.model.CompanyVendorEntity;
import com.ecep.contract.model.Contract;
import com.ecep.contract.model.Inventory;
import com.ecep.contract.model.Invoice;
import com.ecep.contract.model.PurchaseBillVoucher;
import com.ecep.contract.model.PurchaseBillVoucherItem;
import com.ecep.contract.model.PurchaseOrder;
import com.ecep.contract.model.PurchaseOrderItem;

import lombok.Setter;

public class PurchaseBillVoucherCtx extends AbstractYongYouU8Ctx {
    @Setter
    private PurchaseOrdersService purchaseOrdersService;
    @Setter
    private PurchaseOrderItemService purchaseOrderItemService;
    @Setter
    private PurchaseBillVoucherService purchaseBillVoucherService;
    @Setter
    private PurchaseBillVoucherItemService purchaseBillVoucherItemService;

    InventoryCtx inventoryCtx;
    InvoiceCtx invoiceCtx;
    ContractCtx contractCtx;

    PurchaseOrdersService getPurchaseOrdersService() {
        if (purchaseOrdersService == null) {
            purchaseOrdersService = getBean(PurchaseOrdersService.class);
        }
        return purchaseOrdersService;
    }

    PurchaseBillVoucherService getPurchaseBillVoucherService() {
        if (purchaseBillVoucherService == null) {
            purchaseBillVoucherService = getBean(PurchaseBillVoucherService.class);
        }
        return purchaseBillVoucherService;
    }

    private PurchaseOrderItemService getPurchaseOrderItemService() {
        if (purchaseOrderItemService == null) {
            purchaseOrderItemService = getBean(PurchaseOrderItemService.class);
        }
        return purchaseOrderItemService;
    }

    PurchaseBillVoucherItemService getPurchaseBillVoucherItemService() {
        if (purchaseBillVoucherItemService == null) {
            purchaseBillVoucherItemService = getBean(PurchaseBillVoucherItemService.class);
        }
        return purchaseBillVoucherItemService;
    }

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

    InvoiceCtx getInvoiceCtx() {
        if (invoiceCtx == null) {
            invoiceCtx = new InvoiceCtx();
            invoiceCtx.from(this);
        }
        return invoiceCtx;
    }

    ContractCtx getContractCtx() {
        if (contractCtx == null) {
            contractCtx = new ContractCtx();
            contractCtx.from(this);
        }
        return contractCtx;
    }

    public void syncByCompany(Company company, MessageHolder holder) {
        PurchaseBillVoucherService voucherService = getPurchaseBillVoucherService();
        PurchaseBillVoucherItemService voucherItemService = getPurchaseBillVoucherItemService();
        List<PurchaseBillVoucher> vouchers = voucherService.findAll((root, q, cb) -> {
            return cb.equal(root.get("company"), company);
        }, Sort.unsorted());
        holder.debug("查找到 " + vouchers.size() + " 条专用发票记录在数据库中");
        Map<Integer, PurchaseBillVoucher> voucherMap = vouchers.stream()
                .collect(Collectors.toMap(PurchaseBillVoucher::getRefId, item -> item));

        CompanyVendor vendor = getCompanyVendorService().findByCompany(company);
        if (vendor != null) {
            List<CompanyVendorEntity> entities = getCompanyVendorEntityService().findAllByVendor(vendor);
            holder.debug(company.getName() + " 有 "
                    + entities.stream().map(CompanyVendorEntity::getCode).collect(Collectors.joining(", ")) + " 关联项");
            for (CompanyVendorEntity entity : entities) {
                // 查询 U8 数据库
                List<Map<String, Object>> ds = repository.findAllPurchaseBillVoucherByVendorCode(entity.getCode());
                holder.debug(
                        "供应商关联项： " + entity.getCode() + " 查找到 " + ds.size() + " 条专用发票记录在 " + CloudServiceConstant.U8_NAME);

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

                        holder.info("新增发票记录");
                    }

                    if (applyPurchaseBillVoucherDetail(voucher, map, holder.sub("-- | "))) {
                        voucherModified = true;
                    }

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

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

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

            // 查询 U8 数据库
            List<Map<String, Object>> ds = repository.findAllPurchaseBillVoucherItemByPbvId(voucher.getRefId());
            holder.debug("专用发票#" + voucher.getRefId() + "查找到 " + ds.size() + "条条目记录在 " + CloudServiceConstant.U8_NAME);
            Map<Integer, PurchaseBillVoucherItem> 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;
                }
                PurchaseBillVoucherItem item = subItemMap.remove(refId);
                boolean itemModified = false;
                if (item == null) {
                    item = new PurchaseBillVoucherItem();
                    item.setVoucher(voucher);
                    item.setRefId(refId);
                    itemModified = true;

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

    public void syncByContract(Contract contract, MessageHolder holder) {
        PurchaseBillVoucherService voucherService = getPurchaseBillVoucherService();
        PurchaseBillVoucherItemService voucherItemService = getPurchaseBillVoucherItemService();
        List<PurchaseBillVoucherItem> items = voucherItemService.findAll((root, q, cb) -> {
            return cb.equal(root.get("contract"), contract);
        }, Sort.unsorted());

        Map<Integer, PurchaseBillVoucherItem> itemMap = items.stream()
                .collect(Collectors.toMap(PurchaseBillVoucherItem::getRefId, item -> item));
        // 查询 U8 数据库
        List<Map<String, Object>> ds = repository.findAllPurchaseBillVoucherItemByContractCode(contract.getCode());
        holder.debug("合同编号#" + contract.getCode() + "查找到 " + ds.size() + "条发票条目记录在 " + CloudServiceConstant.U8_NAME);

        for (Map<String, Object> map : ds) {
            Integer refId = (Integer) map.get("ID");
            if (refId == 0) {
                holder.warn("跳过无效专用发票记录：缺少 ID");
                continue;
            }
            PurchaseBillVoucherItem item = itemMap.remove(refId);
            boolean itemModified = false;
            if (item == null) {
                item = new PurchaseBillVoucherItem();
                PurchaseBillVoucher voucher = this.updateVoucherByPBVID((Integer) map.get("PBVID"), holder);
                item.setVoucher(voucher);
                item.setRefId(refId);
                itemModified = true;

                holder.info("新增专用发票条目 #" + refId);
            }
            MessageHolder subHolder = holder.sub("-- | ");
            if (applyPurchaseBillVoucherItemDetail(item, map, subHolder)) {
                itemModified = true;
            }
            if (itemModified) {
                item = voucherItemService.save(item);
            }
        }
    }

    private PurchaseBillVoucher updateVoucherByPBVID(Integer pbvId, MessageHolder holder) {
        PurchaseBillVoucherService voucherService = getPurchaseBillVoucherService();
        PurchaseBillVoucher voucher = voucherService.findByRefId(pbvId);
        if (voucher != null) {
            return voucher;
        }
        voucher = new PurchaseBillVoucher();
        // 查询 U8 数据库
        Map<String, Object> map = repository.findPurchaseBillVoucherById(pbvId);
        applyPurchaseBillVoucherDetail(voucher, map, holder.sub("-- | "));
        voucher = voucherService.save(voucher);
        return voucher;
    }

    private boolean applyPurchaseBillVoucherDetail(PurchaseBillVoucher voucher, Map<String, Object> map,
            MessageHolder holder) {
        String code = String.valueOf(map.get("PBVID"));
        String vendorCode = (String) map.get("cVenCode");
        String invoiceNumber = (String) map.get("cPBVCode");
        String personCode = (String) map.get("cPersonCode");
        String inCode = (String) map.get("cInCode");

        Timestamp invoiceDate = (Timestamp) map.get("dPBVDate");
        Timestamp voucherDate = (Timestamp) map.get("dVouDate");

        BigDecimal amount = (BigDecimal) map.get("iSum");

        String maker = (String) map.get("cPBVMaker");
        String verifier = (String) map.get("cPBVVerifier");
        Timestamp makeTime = (Timestamp) map.get("cmaketime");
        Timestamp auditTime = (Timestamp) map.get("dverifysystime");

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

        boolean modified = false;

        holder.debug("发票号码：" + invoiceNumber);

        if (updateCompanyByVendorCode(voucher::getCompany, voucher::setCompany, vendorCode, holder, "供应商")) {
            modified = true;
        }
        if (updateInvoice(voucher::getInvoice, voucher::setInvoice, invoiceNumber, holder, "发票")) {
            modified = true;
        }

        if (voucher.getInvoice() != null) {
            Invoice invoice = voucher.getInvoice();
            if (updateLocalDate(invoice::getInvoiceDate, invoice::setInvoiceDate, voucherDate, holder, "开票日期")) {
                invoice = getInvoiceCtx().getInvoiceService().save(invoice);
                voucher.setInvoice(invoice);
            }
        }

        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, auditTime, holder, "审核时间")) {
            modified = true;
        }
        if (!Objects.equals(voucher.getDescription(), description)) {
            voucher.setDescription(description);
            holder.info("描述修改为: " + description);
            modified = true;
        }
        return modified;
    }

    private boolean applyPurchaseBillVoucherItemDetail(PurchaseBillVoucherItem 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("iPBVQuantity");
        BigDecimal taxRate = (BigDecimal) map.get("iOriTaxPrice");
        BigDecimal taxPrice = (BigDecimal) map.get("iTaxPrice");
        BigDecimal amount = (BigDecimal) map.get("iSum");

        // RdsId

        // 采购订单条目refId
        Integer purchaseOrderItemId = (Integer) map.get("iPOsID");

        String description = (String) map.get("cdescription");
        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 (updatePurchaseOrderItem(item::getOrderItem, item::setOrderItem, purchaseOrderItemId, holder, "采购订单条目")) {
            modified = true;
        }
        if (updateContractByContractCode(item::getContract, item::setContract, contractCode, holder, "合同")) {
            modified = true;
        }

        if (updateNumber(item::getPrice, item::setPrice, taxPrice, holder, "含税单价")) {
            modified = true;
        }
        if (updateNumber(item::getQuantity, item::setQuantity, quantity, holder, "数量")) {
            modified = true;
        }
        if (updateAppendText(item::getDescription, item::setDescription, description, holder, "描述")) {
            modified = true;
        }
        return modified;
    }

    boolean updatePurchaseOrderItem(Supplier<PurchaseOrderItem> getter, Consumer<PurchaseOrderItem> setter,
            Integer orderItemRefId, MessageHolder holder, String topic) {
        PurchaseOrderItem item = null;
        if (orderItemRefId != null) {
            item = getPurchaseOrderItemService().findByRefId(orderItemRefId);
        }
        if (item == null) {
            setter.accept(null);
            holder.warn("无效" + topic + "：" + orderItemRefId);
            return true;
        } else {
            if (!Objects.equals(getter.get(), item)) {
                setter.accept(item);
                holder.info(topic + "修改为: " + item.getRefId());
                return true;
            }
        }
        return false;
    }

    boolean updatePurchaseOrder(Supplier<PurchaseOrder> getter, Consumer<PurchaseOrder> setter, Integer orderRefId,
            MessageHolder holder, String topic) {
        PurchaseOrder order = null;
        if (orderRefId != null) {
            order = getPurchaseOrdersService().findByRefId(orderRefId);
        }
        if (order == null) {
            setter.accept(null);
            holder.warn("无效" + topic + "：" + orderRefId);
            return true;
        } else {
            if (!Objects.equals(getter.get(), order)) {
                setter.accept(order);
                holder.info(topic + "修改为: " + order.getCode());
                return true;
            }
        }
        return false;
    }

    boolean updateContractByContractCode(Supplier<Contract> getter, Consumer<Contract> setter, String contractCode,
            MessageHolder holder, String topic) {
        Contract contract = null;
        if (contractCode != null) {
            contract = getContractCtx().findContractByCode(contractCode);
        }
        if (contract == null) {
            setter.accept(null);
            holder.warn("无效" + topic + "：" + contractCode);
            return true;
        } else {
            if (!Objects.equals(getter.get(), contract)) {
                setter.accept(contract);
                holder.info(topic + "修改为: " + contract.getCode());
                return true;
            }
        }
        return false;
    }

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

    private boolean updateInvoice(Supplier<Invoice> getter, Consumer<Invoice> setter, String invoiceNumber,
            MessageHolder holder, String topic) {
        return getInvoiceCtx().updateInvoiceByNumber(getter, setter, invoiceNumber, holder, topic);
    }

}
