package com.yhy.module.core.service.quota.impl;

import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.*;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.*;
import static com.yhy.module.core.enums.ErrorCodeConstants.*;

import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import com.yhy.module.core.controller.admin.quota.vo.QuotaAdjustmentSettingSaveReqVO;
import com.yhy.module.core.dal.dataobject.quota.QuotaAdjustmentSettingDO;
import com.yhy.module.core.dal.dataobject.quota.QuotaItemDO;
import com.yhy.module.core.dal.mysql.quota.QuotaAdjustmentDetailMapper;
import com.yhy.module.core.dal.mysql.quota.QuotaAdjustmentSettingMapper;
import com.yhy.module.core.dal.mysql.quota.QuotaCatalogItemMapper;
import com.yhy.module.core.dal.mysql.quota.QuotaCatalogTreeMapper;
import com.yhy.module.core.dal.mysql.quota.QuotaItemMapper;
import com.yhy.module.core.dal.mysql.resource.ResourceItemMapper;
import com.yhy.module.core.service.quota.QuotaAdjustmentSettingService;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

/**
 * 定额调整设置 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
@Slf4j
public class QuotaAdjustmentSettingServiceImpl implements QuotaAdjustmentSettingService {

    @Resource
    private QuotaAdjustmentSettingMapper quotaAdjustmentSettingMapper;

    @Resource
    private QuotaAdjustmentDetailMapper quotaAdjustmentDetailMapper;

    @Resource
    private QuotaItemMapper quotaItemMapper;

    @Resource
    private QuotaCatalogTreeMapper quotaCatalogTreeMapper;

    @Resource
    private QuotaCatalogItemMapper quotaCatalogItemMapper;

    @Resource
    private ResourceItemMapper resourceItemMapper;

    @Override
    public Long createQuotaAdjustmentSetting(QuotaAdjustmentSettingSaveReqVO createReqVO) {
        // 验证定额基价是否存在
        validateQuotaItemExists(createReqVO.getQuotaItemId());

        // 验证调整规则中的编码（如果是动态合并定额类型）
        validateAdjustmentRulesCodes(createReqVO.getQuotaItemId(), createReqVO.getAdjustmentRules());

        // 插入
        QuotaAdjustmentSettingDO setting = BeanUtils.toBean(createReqVO, QuotaAdjustmentSettingDO.class);
        if (setting.getSortOrder() == null) {
            setting.setSortOrder(0);
        }
        quotaAdjustmentSettingMapper.insert(setting);
        return setting.getId();
    }

    @Override
    public void updateQuotaAdjustmentSetting(QuotaAdjustmentSettingSaveReqVO updateReqVO) {
        // 校验存在
        validateQuotaAdjustmentSettingExists(updateReqVO.getId());
        // 验证定额基价是否存在
        validateQuotaItemExists(updateReqVO.getQuotaItemId());

        // 验证调整规则中的编码（如果是动态合并定额类型）
        validateAdjustmentRulesCodes(updateReqVO.getQuotaItemId(), updateReqVO.getAdjustmentRules());

        // 更新
        QuotaAdjustmentSettingDO updateObj = BeanUtils.toBean(updateReqVO, QuotaAdjustmentSettingDO.class);
        quotaAdjustmentSettingMapper.updateById(updateObj);
    }

    @Override
    public void deleteQuotaAdjustmentSetting(Long id) {
        // 校验存在
        validateQuotaAdjustmentSettingExists(id);
        
        // 检查是否有明细
        Long detailCount = quotaAdjustmentDetailMapper.countBySettingId(id);
        if (detailCount > 0) {
            throw exception(QUOTA_ADJUSTMENT_SETTING_HAS_DETAILS);
        }
        
        // 检查是否被其他明细引用
        Long referenceCount = quotaAdjustmentDetailMapper.countByAdjustmentCode(id);
        if (referenceCount > 0) {
            throw exception(QUOTA_ADJUSTMENT_SETTING_REFERENCED);
        }

        // 删除
        quotaAdjustmentSettingMapper.deleteById(id);
    }

    @Override
    public QuotaAdjustmentSettingDO getQuotaAdjustmentSetting(Long id) {
        return quotaAdjustmentSettingMapper.selectById(id);
    }

    @Override
    public List<QuotaAdjustmentSettingDO> getQuotaAdjustmentSettingList(Long quotaItemId) {
        return quotaAdjustmentSettingMapper.selectListByQuotaItemId(quotaItemId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void swapSort(Long id1, Long id2) {
        // 验证两个调整设置是否存在
        QuotaAdjustmentSettingDO setting1 = quotaAdjustmentSettingMapper.selectByIdForUpdate(id1);
        QuotaAdjustmentSettingDO setting2 = quotaAdjustmentSettingMapper.selectByIdForUpdate(id2);

        if (setting1 == null) {
            throw exception(QUOTA_ADJUSTMENT_SETTING_NOT_EXISTS);
        }
        if (setting2 == null) {
            throw exception(QUOTA_ADJUSTMENT_SETTING_NOT_EXISTS);
        }

        // 验证是否在同一定额基价下
        if (!setting1.getQuotaItemId().equals(setting2.getQuotaItemId())) {
            throw exception(QUOTA_ADJUSTMENT_SETTING_NOT_SAME_QUOTA_ITEM);
        }

        // 交换排序值
        Integer tempSort = setting1.getSortOrder();
        setting1.setSortOrder(setting2.getSortOrder());
        setting2.setSortOrder(tempSort);

        quotaAdjustmentSettingMapper.updateById(setting1);
        quotaAdjustmentSettingMapper.updateById(setting2);
    }

    private void validateQuotaAdjustmentSettingExists(Long id) {
        if (quotaAdjustmentSettingMapper.selectById(id) == null) {
            throw exception(QUOTA_ADJUSTMENT_SETTING_NOT_EXISTS);
        }
    }

    private void validateQuotaItemExists(Long quotaItemId) {
        if (quotaItemMapper.selectById(quotaItemId) == null) {
            throw exception(QUOTA_ADJUSTMENT_SETTING_QUOTA_ITEM_NOT_EXISTS);
        }
    }

    /**
     * 验证调整规则中的数据
     * 
     * @param currentQuotaItemId 当前定额基价ID
     * @param adjustmentRules 调整规则Map
     */
    private void validateAdjustmentRulesCodes(Long currentQuotaItemId, Map<String, Object> adjustmentRules) {
        if (adjustmentRules == null || adjustmentRules.isEmpty()) {
            return;
        }

        try {
            // 获取类型
            String type = adjustmentRules.get("type") != null ? adjustmentRules.get("type").toString() : "";
            Object itemsObj = adjustmentRules.get("items");
            
            if (!(itemsObj instanceof java.util.List)) {
                return;
            }
            
            @SuppressWarnings("unchecked")
            java.util.List<Map<String, Object>> items = (java.util.List<Map<String, Object>>) itemsObj;
            
            // 验证 adjust_coefficient 类型的系数字段
            if ("adjust_coefficient".equals(type)) {
                java.util.List<String> invalidCoefficients = new java.util.ArrayList<>();
                for (int i = 0; i < items.size(); i++) {
                    Map<String, Object> item = items.get(i);
                    Object coefficientObj = item.get("coefficient");
                    if (coefficientObj != null) {
                        String coefficientStr = coefficientObj.toString();
                        try {
                            new java.math.BigDecimal(coefficientStr);
                        } catch (NumberFormatException e) {
                            String name = item.get("name") != null ? item.get("name").toString() : "第" + (i + 1) + "行";
                            invalidCoefficients.add(name + ": " + coefficientStr);
                        }
                    }
                }
                if (!invalidCoefficients.isEmpty()) {
                    throw exception0(BAD_REQUEST.getCode(), "系数必须是数字，以下数据无效：" + String.join(", ", invalidCoefficients));
                }
            }
            
            // 验证 dynamic_adjust 类型的必填字段和系数设置字段
            if ("dynamic_adjust".equals(type)) {
                java.util.List<String> missingFields = new java.util.ArrayList<>();
                java.util.List<String> invalidCoefficients = new java.util.ArrayList<>();
                
                for (int i = 0; i < items.size(); i++) {
                    Map<String, Object> item = items.get(i);
                    java.util.List<String> rowMissing = new java.util.ArrayList<>();
                    
                    // 验证必填字段（name 字段已从前端移除，不再校验）
                    Object nameObj = item.get("name");
                    Object categoryObj = item.get("category");
                    if (categoryObj == null || categoryObj.toString().trim().isEmpty()) {
                        rowMissing.add("类别");
                    }
                    Object coefficientObj = item.get("coefficientSetting");
                    if (coefficientObj == null || coefficientObj.toString().trim().isEmpty()) {
                        rowMissing.add("系数设置");
                    }
                    Object valueRuleObj = item.get("valueRule");
                    if (valueRuleObj == null || valueRuleObj.toString().trim().isEmpty()) {
                        rowMissing.add("取值规则");
                    }
                    
                    if (!rowMissing.isEmpty()) {
                        String name = nameObj != null && !nameObj.toString().trim().isEmpty() 
                            ? nameObj.toString() : "第" + (i + 1) + "行";
                        missingFields.add(name + "缺少：" + String.join("、", rowMissing));
                    }
                    
                    // 验证所有数值字段是否为有效数字
                    String rowName = nameObj != null && !nameObj.toString().trim().isEmpty() 
                        ? nameObj.toString() : "第" + (i + 1) + "行";
                    validateNumericField(item.get("coefficientSetting"), "系数设置", rowName, invalidCoefficients);
                    validateNumericField(item.get("minValue"), "最小值", rowName, invalidCoefficients);
                    validateNumericField(item.get("maxValue"), "最大值", rowName, invalidCoefficients);
                    validateNumericField(item.get("denominatorValue"), "分母值", rowName, invalidCoefficients);
                    validateNumericField(item.get("baseValue"), "基础值", rowName, invalidCoefficients);
                }
                
                if (!missingFields.isEmpty()) {
                    throw exception0(BAD_REQUEST.getCode(), "必填字段未填写：" + String.join("；", missingFields));
                }
                if (!invalidCoefficients.isEmpty()) {
                    throw exception0(BAD_REQUEST.getCode(), "数值字段必须是数字，以下数据无效：" + String.join(", ", invalidCoefficients));
                }
            }
            
            // 验证动态合并定额类型（编码是定额基价编码）
            // consumption_adjustment 类型的编码是工料机编码，在应用调整时才匹配，不在此处验证
            if ("dynamic_merge".equals(type)) {
                // 限制只允许一行数据
                if (items.size() > 1) {
                    throw exception0(BAD_REQUEST.getCode(), "动态合并定额只允许设置一行数据");
                }
                java.util.List<String> invalidCodes = new java.util.ArrayList<>();
                java.util.List<String> selfBindingCodes = new java.util.ArrayList<>();
                java.util.List<String> differentSpecialtyCodes = new java.util.ArrayList<>();
                
                // 获取当前定额基价的专业节点ID
                Long currentSpecialtyId = getSpecialtyIdByQuotaItemId(currentQuotaItemId);
                QuotaItemDO currentQuotaItem = quotaItemMapper.selectById(currentQuotaItemId);
                String currentCode = currentQuotaItem != null ? currentQuotaItem.getCode() : null;
                
                for (Map<String, Object> item : items) {
                    String code = item.get("code") != null ? item.get("code").toString() : "";
                    if (!code.isEmpty()) {
                        // 1. 禁止自己绑定自己
                        if (code.equals(currentCode)) {
                            selfBindingCodes.add(code);
                            continue;
                        }
                        
                        // 查询定额基价编码是否存在
                        List<QuotaItemDO> quotaItems = quotaItemMapper.selectByCode(code);
                        if (quotaItems == null || quotaItems.isEmpty()) {
                            invalidCodes.add(code);
                            continue;
                        }
                        
                        // 2. 只允许添加同一定额专业节点下的定额
                        if (currentSpecialtyId != null) {
                            for (QuotaItemDO targetQuotaItem : quotaItems) {
                                Long targetSpecialtyId = getSpecialtyIdByQuotaItemId(targetQuotaItem.getId());
                                if (targetSpecialtyId == null || !targetSpecialtyId.equals(currentSpecialtyId)) {
                                    differentSpecialtyCodes.add(code);
                                    break;
                                }
                            }
                        }
                    }
                }
                
                // 抛出错误
                if (!selfBindingCodes.isEmpty()) {
                    throw exception0(BAD_REQUEST.getCode(), "不允许绑定自己：" + String.join(", ", selfBindingCodes));
                }
                if (!invalidCodes.isEmpty()) {
                    throw exception0(BAD_REQUEST.getCode(), "以下定额基价编码不存在：" + String.join(", ", invalidCodes));
                }
                if (!differentSpecialtyCodes.isEmpty()) {
                    throw exception0(BAD_REQUEST.getCode(), "只允许添加本定额专业节点下的定额，以下编码不在同一专业下：" + String.join(", ", differentSpecialtyCodes));
                }
            }
            
            // 验证增减材料消耗量类型（编码是工料机编码）
            if ("consumption_adjustment".equals(type)) {
                java.util.List<String> invalidCodes = new java.util.ArrayList<>();
                java.util.List<String> differentCategoryTreeCodes = new java.util.ArrayList<>();
                
                // 获取当前定额专业绑定的工料机专业节点ID
                Long currentSpecialtyId = getSpecialtyIdByQuotaItemId(currentQuotaItemId);
                Long boundCategoryTreeId = null;
                if (currentSpecialtyId != null) {
                    com.yhy.module.core.dal.dataobject.quota.QuotaCatalogItemDO catalogItem = quotaCatalogItemMapper.selectById(currentSpecialtyId);
                    if (catalogItem != null) {
                        boundCategoryTreeId = catalogItem.getCategoryTreeId();
                    }
                }
                
                for (Map<String, Object> item : items) {
                    String code = item.get("code") != null ? item.get("code").toString() : "";
                    if (!code.isEmpty()) {
                        // 查询工料机是否存在
                        com.yhy.module.core.dal.dataobject.resource.ResourceItemDO resourceItem = resourceItemMapper.selectByCode(code);
                        if (resourceItem == null) {
                            invalidCodes.add(code);
                        } else if (boundCategoryTreeId != null) {
                            // 验证工料机是否属于绑定的工料机专业节点
                            Long resourceCategoryTreeId = resourceItem.getCategoryTreeId();
                            if (resourceCategoryTreeId == null || !resourceCategoryTreeId.equals(boundCategoryTreeId)) {
                                differentCategoryTreeCodes.add(code);
                            }
                        }
                    }
                }
                
                // 抛出错误
                if (!invalidCodes.isEmpty()) {
                    throw exception0(BAD_REQUEST.getCode(), "以下工料机编码不存在：" + String.join(", ", invalidCodes));
                }
                if (!differentCategoryTreeCodes.isEmpty()) {
                    throw exception0(BAD_REQUEST.getCode(), "只允许添加本定额专业绑定的工料机专业下的工料机，以下编码不在绑定的工料机专业下：" + String.join(", ", differentCategoryTreeCodes));
                }
            }
        } catch (Exception e) {
            if (e instanceof cn.iocoder.yudao.framework.common.exception.ServiceException) {
                throw (cn.iocoder.yudao.framework.common.exception.ServiceException) e;
            }
            log.error("[validateAdjustmentRulesCodes] 验证调整规则失败", e);
        }
    }

    /**
     * 根据定额基价ID获取所属的定额专业节点ID
     * 定额基价 -> 定额子目树(catalog_item_id) -> 定额专业节点(catalog_item_id)
     * 
     * @param quotaItemId 定额基价ID
     * @return 定额专业节点ID，如果找不到返回null
     */
    private Long getSpecialtyIdByQuotaItemId(Long quotaItemId) {
        if (quotaItemId == null) {
            return null;
        }
        QuotaItemDO quotaItem = quotaItemMapper.selectById(quotaItemId);
        if (quotaItem == null || quotaItem.getCatalogItemId() == null) {
            return null;
        }
        // 查询定额子目树节点
        com.yhy.module.core.dal.dataobject.quota.QuotaCatalogTreeDO catalogTree = quotaCatalogTreeMapper.selectById(quotaItem.getCatalogItemId());
        if (catalogTree == null) {
            return null;
        }
        // 返回定额专业节点ID
        return catalogTree.getCatalogItemId();
    }

    /**
     * 验证数值字段是否为有效数字
     */
    private void validateNumericField(Object value, String fieldName, String rowName, java.util.List<String> invalidList) {
        if (value == null || value.toString().trim().isEmpty()) {
            return;
        }
        String valueStr = value.toString().trim();
        try {
            new java.math.BigDecimal(valueStr);
        } catch (NumberFormatException e) {
            invalidList.add(rowName + "的" + fieldName + ": " + valueStr);
        }
    }

}
