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

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

import org.springframework.util.StringUtils;

import com.ecep.contract.MessageHolder;
import com.ecep.contract.constant.CloudServiceConstant;
import com.ecep.contract.ds.company.model.Company;
import com.ecep.contract.ds.company.service.CompanyService;
import com.ecep.contract.ds.contract.service.ContractItemService;
import com.ecep.contract.ds.contract.service.ContractService;
import com.ecep.contract.ds.contract.service.SaleOrdersService;
import com.ecep.contract.ds.contract.service.SalesOrderItemService;
import com.ecep.contract.ds.customer.model.SalesOrder;
import com.ecep.contract.ds.customer.model.SalesOrderItem;
import com.ecep.contract.ds.customer.service.CompanyCustomerEntityService;
import com.ecep.contract.ds.customer.service.CustomerService;
import com.ecep.contract.util.BeanContext;
import com.ecep.contract.util.NumberUtils;
import com.ecep.contract.vo.ContractVo;

import lombok.Setter;

public class SalesOrderCtx extends AbstractYongYouU8Ctx {

    @Setter
    private SaleOrdersService saleOrdersService;
    @Setter
    private SalesOrderItemService orderItemService;

    public SalesOrderCtx() {
        super();
    }

    public SalesOrderCtx(BeanContext ctx) {
        super(ctx);
    }

    SaleOrdersService getSaleOrdersService() {
        return getCachedBean(SaleOrdersService.class);
    }

    /**
     * 更新客户信息
     * 
     * @param getter    获取当前客户的函数
     * @param setter    设置客户的函数
     * @param code      客户代码
     * @param name      客户名称
     * @param holder    消息持有者
     * @param fieldName 字段名称
     * @return 是否发生了修改
     */
    private boolean updateCustomer(Supplier<Company> getter,
            java.util.function.Consumer<Company> setter,
            String code,
            String name,
            MessageHolder holder,
            String fieldName) {

        Company current = getter.get();
        CompanyService companyService = getBean(CompanyService.class);
        if (StringUtils.hasText(code)) {
            var customerEntity = getCachedBean(CompanyCustomerEntityService.class).findByCustomerCode(code);
            if (customerEntity == null) {
                holder.warn("未找到客户：" + name + " (代码: " + code + ")");
            } else {
                var customer = getCachedBean(CustomerService.class).findById(customerEntity.getCustomerId());
                if (customer == null) {
                    holder.warn("未找到客户：" + name + " (代码: " + code + ")");
                } else {
                    var companyId = customer.getCompanyId();
                    if (current == null) {
                        var updated = companyService.getById(companyId);
                        setter.accept(updated);
                        holder.info(fieldName + " 更新为 " + updated.getName());
                        return true;
                    }
                    if (!Objects.equals(current.getId(), companyId)) {
                        var updated = companyService.getById(companyId);
                        setter.accept(updated);
                        holder.info(fieldName + " 更新为 " + updated.getName());
                        return true;
                    }
                }
            }
        }

        // 尝试通过名称或简称查找公司
        Company updated = companyService.findAndRemoveDuplicateCompanyByNameOrAbbName(name, null);

        if (updated == null) {
            holder.warn("未找到客户：" + name + " (代码: " + code + ")");
            return false;
        }

        if (!Objects.equals(current, updated)) {
            setter.accept(updated);
            holder.info(fieldName + " 更新为 " + updated.getName());
            return true;
        }

        return false;
    }

    SalesOrderItemService getOrderItemService() {
        if (orderItemService == null) {
            orderItemService = getBean(SalesOrderItemService.class);
        }
        return orderItemService;
    }

    public List<SalesOrder> syncByContract(ContractVo contract, MessageHolder holder) {
        SaleOrdersService saleOrdersService = getSaleOrdersService();
        SalesOrderItemService orderItemService = getOrderItemService();

        List<SalesOrder> orders = saleOrdersService.findAllByContract(contract);
        holder.debug("查找到 " + orders.size() + " 条销售订单记录在数据库中");
        Map<String, SalesOrder> ordersMap = orders.stream()
                .collect(Collectors.toMap(SalesOrder::getCode, item -> item));
        // 按 order 分组
        Map<SalesOrder, Map<String, SalesOrderItem>> itemMap = orders.stream()
                .collect(
                        Collectors.toMap(Function.identity(),
                                order -> orderItemService.findAllBySaleOrder(order).stream().collect(
                                        Collectors.toMap(SalesOrderItem::getCode, item -> item))));

        // 查询 U8 数据库
        List<Map<String, Object>> ds = repository.findAllSalesOrderItemByContractCode(contract.getCode());
        holder.debug("查找到 " + ds.size() + " 条销售订单条目记录在 " + CloudServiceConstant.U8_NAME);

        Map<SalesOrder, List<SalesOrderItem>> updateMap = new HashMap<>();
        for (Map<String, Object> map : ds) {
            String orderCode = Optional.ofNullable(map.get("cSOCode")).map(Object::toString).orElse("");
            if (orderCode.isEmpty()) {
                holder.warn("跳过无效销售订单记录：缺少 cSOCode");
                continue;
            }
            SalesOrder order = ordersMap.get(orderCode);
            if (order == null) {
                order = new SalesOrder();
                order.setContract(getCachedBean(ContractService.class).getById(contract.getId()));
                order.setCode(orderCode);

                order = saleOrdersService.save(order);
                ordersMap.put(orderCode, order);
                holder.info("新增销售订单 #" + orderCode);
            }
        }
        for (Map<String, Object> map : ds) {
            // holder.debug("条目：" + map.toString());
            String orderCode = Optional.ofNullable(map.get("cSOCode")).map(Object::toString).orElse("");
            if (orderCode.isEmpty()) {
                holder.warn("跳过无效销售订单记录：缺少 cSOCode");
                continue;
            }
            SalesOrder order = ordersMap.get(orderCode);

            boolean itemModified = false;
            List<SalesOrderItem> updates = updateMap.computeIfAbsent(order, k -> new ArrayList<>());

            // 获取条目标识并处理 null
            String refId = Optional.ofNullable(map.get("iSOsID")).map(Object::toString).orElse("");
            if (refId.isEmpty()) {
                holder.warn("跳过条目：订单 " + orderCode + " 缺少 iSOsID");
                continue;
            }
            Map<String, SalesOrderItem> subItemMap = itemMap.get(order);
            SalesOrderItem item = null;
            if (subItemMap != null) {
                item = subItemMap.remove(refId);
            }

            if (item == null) {
                item = new SalesOrderItem();
                item.setOrder(order);
                item.setCode(refId);
                itemModified = true;

                holder.info("新增销售订单条目 #" + refId);
            }
            MessageHolder subHolder = holder.sub("---| ");
            if (applySaleOrderItemDetail(item, map, subHolder)) {
                itemModified = true;
            }
            if (itemModified) {
                item = orderItemService.save(item);
            }
            updates.add(item);
        }

        for (SalesOrder order : updateMap.keySet()) {
            holder.debug("销售订单 #" + order.getCode());
            if (applySalesOrderDetail(order, repository.querySalesOrderDetail(order.getCode()), holder)) {
                saleOrdersService.save(order);
            }
        }

        if (!itemMap.isEmpty()) {
            for (Map<String, SalesOrderItem> subMap : itemMap.values()) {
                if (!subMap.isEmpty()) {
                    for (SalesOrderItem item : subMap.values()) {
                        holder.info("删除销售订单条目");
                        orderItemService.delete(item);
                    }
                }
            }

            for (SalesOrder order : updateMap.keySet()) {
                itemMap.remove(order);
            }
            if (!itemMap.isEmpty()) {
                holder.info("剩余 " + itemMap.size() + " 个销售订单条目");
            }
        }

        return new ArrayList<>(updateMap.keySet());

    }

    private boolean applySalesOrderDetail(SalesOrder order, Map<String, Object> map, MessageHolder holder) {
        String code = (String) map.get("cSOCode");
        String employeeCode = (String) map.get("cPersonCode");

        String customerCode = (String) map.get("cCusCode");
        String customerName = (String) map.get("cCusName");
        String customerAddress = (String) map.get("cCusOAddress");

        String makerName = (String) map.get("cMaker");
        Timestamp makerDate = (Timestamp) map.get("dcreatesystime");
        String verifierName = (String) map.get("cVerifier");
        Timestamp verifierDate = (Timestamp) map.get("dverifysystime");
        String modifierName = (String) map.get("cmodifier");
        Timestamp modifierDate = (Timestamp) map.get("dmodifysystime");
        String closerName = (String) map.get("cCloser");
        Timestamp closerDate = (Timestamp) map.get("dclosesystime");

        float taxRate = Optional.ofNullable(map.get("iTaxRate"))
                .map(obj -> obj instanceof Number ? ((Number) obj).floatValue() : null).orElse(0f);

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

        boolean modified = false;

        if (!Objects.equals(order.getCode(), code)) {
            order.setCode(code);
            holder.info("订单编号更新为 " + code);
            modified = true;
        }

        if (updateEmployeeByCode(order::getEmployee, order::setEmployee, employeeCode, holder, "业务员")) {
            modified = true;
        }
        if (updateEmployeeByName(order::getMaker, order::setMaker, makerName, holder, "制单人")) {
            modified = true;
        }
        if (updateEmployeeByName(order::getVerifier, order::setVerifier, verifierName, holder, "审核人")) {
            modified = true;
        }
        if (updateEmployeeByName(order::getModifier, order::setModifier, modifierName, holder, "修改人")) {
            modified = true;
        }
        if (updateEmployeeByName(order::getCloser, order::setCloser, closerName, holder, "关闭人")) {
            modified = true;
        }

        if (updateLocalDate(order::getMakerDate, order::setMakerDate, makerDate, holder, "制单日期")) {
            modified = true;
        }
        if (updateLocalDate(order::getVerifierDate, order::setVerifierDate, verifierDate, holder, "审核日期")) {
            modified = true;
        }
        if (updateLocalDate(order::getModifierDate, order::setModifierDate, modifierDate, holder, "修改日期")) {
            modified = true;
        }
        if (updateLocalDate(order::getCloserDate, order::setCloserDate, closerDate, holder, "关闭日期")) {
            modified = true;
        }

        if (!NumberUtils.equals(order.getTaxRate(), taxRate)) {
            order.setTaxRate(taxRate);
            holder.info("税率修改为: " + taxRate);
            modified = true;
        }

        if (updateCustomer(order::getCustomer, order::setCustomer, customerCode, customerName, holder, "客户")) {
            modified = true;
        }

        if (!Objects.equals(order.getCustomerAddress(), customerAddress)) {
            order.setCustomerAddress(customerAddress);
            holder.info("客户地址修改为: " + customerAddress);
            modified = true;
        }

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

        return modified;
    }

    private boolean applySaleOrderItemDetail(SalesOrderItem item, Map<String, Object> map, MessageHolder holder) {
        String code = String.valueOf(map.get("iSOsID"));
        String spec = (String) map.get("cInvName");
        String title = (String) map.get("cInvName");
        String contractItemRowId = (String) map.get("cContractRowGuid");
        double quantity = (double) map.get("iQuantity");
        double taxRate = (double) map.get("iTaxRate");
        double taxPrice = (double) map.get("iTaxUnitPrice");
        double exclusiveTaxPrice = (double) map.get("iUnitPrice");
        BigDecimal amount = (BigDecimal) map.get("iSum");

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

        boolean modified = false;

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

        if (!Objects.equals(item.getCode(), code)) {
            item.setCode(code);
            holder.info("代码修改为: " + code);
            modified = true;
        }
        if (!Objects.equals(item.getName(), title)) {
            item.setName(title);
            holder.info("名称修改为: " + title);
            modified = true;
        }
        if (!NumberUtils.equals(item.getExclusiveTaxPrice(), exclusiveTaxPrice)) {
            item.setExclusiveTaxPrice(exclusiveTaxPrice);
            holder.info("不含税单价修改为: " + exclusiveTaxPrice);
            modified = true;
        }
        if (!NumberUtils.equals(item.getPrice(), taxPrice)) {
            item.setPrice(taxPrice);
            holder.info("含税单价修改为: " + taxPrice);
            modified = true;
        }
        if (!NumberUtils.equals(item.getTaxRate(), taxRate)) {
            item.setTaxRate(taxRate);
            holder.info("税率修改为: " + taxRate);
            modified = true;
        }
        if (!NumberUtils.equals(item.getQuantity(), quantity)) {
            item.setQuantity(quantity);
            holder.info("数量修改为: " + quantity);
            modified = true;
        }
        if (updateLocalDate(item::getStartDate, item::setStartDate, (Timestamp) map.get("dPreDate"), holder, "开始日期")) {
            modified = true;
        }
        if (updateLocalDate(item::getEndDate, item::setEndDate, (Timestamp) map.get("dPreMoDate"), holder, "结束日期")) {
            modified = true;
        }

        var contractItem = getCachedBean(ContractItemService.class).findByRowId(contractItemRowId);
        if (!Objects.equals(item.getContractItem(), contractItem)) {
            item.setContractItem(contractItem);
            holder.info("合同条目修改为: #" + contractItem.getId());
            modified = true;
        }

        if (!Objects.equals(item.getDescription(), memo)) {
            item.setDescription(memo);
            modified = true;
        }

        return modified;
    }
}
