package com.zt.plat.module.contractorder.controller.admin.contract.util;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.zt.plat.module.contractorder.api.vo.contract.ContractReceiveSendSaveReqVO;
import io.swagger.v3.oas.annotations.media.Schema;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

// 补充项目自定义异常相关的import
import static com.zt.plat.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.zt.plat.module.contractorder.enums.ErrorCodeConstants.CONTRACT_PARAMS_ERROR;

public class ContractReceiveSendValidator {

    /**
     * 校验收发货规则列表的合法性（无返回值，校验失败直接抛异常）
     * 规则：排除id和继承字段，需校验字段要么全有值/全为空；报错显示@Schema的description
     */
    public static void validateContractReceiveSend(List<ContractReceiveSendSaveReqVO> contractReceiveSends) {
        // 列表为空时，无需校验，直接结束方法
        if (CollectionUtils.isEmpty(contractReceiveSends)) {
            return;
        }

        // 遍历列表逐个校验
        for (int index = 0; index < contractReceiveSends.size(); index++) {
            ContractReceiveSendSaveReqVO vo = contractReceiveSends.get(index);
            validateSingleVO(vo, index);
        }
    }

    /**
     * 校验单个VO对象（核心：获取@Schema的description并替换字段名）
     */
    private static void validateSingleVO(ContractReceiveSendSaveReqVO vo, int index) {
        if (vo == null) {
            return; // 单个对象为null，视为全空，合法
        }

        Class<?> clazz = vo.getClass();
        Field[] declaredFields = clazz.getDeclaredFields();
        List<Field> targetFields = new ArrayList<>();

        // 过滤：排除id字段，保留自有非id字段
        for (Field field : declaredFields) {
            if (!"id".equals(field.getName())) {
                targetFields.add(field);
            }
        }

        // 统计有值/空值的字段描述（@Schema的description）
        List<String> nonNullFieldDescs = new ArrayList<>(); // 有值字段的描述
        List<String> nullFieldDescs = new ArrayList<>();    // 空值字段的描述

        for (Field field : targetFields) {
            field.setAccessible(true);
            String fieldName = field.getName();
            // 1. 获取字段@Schema注解的description
            String fieldDesc = getFieldSchemaDescription(field);

            try {
                Object value = field.get(vo);
                // 判断是否为“有值”
                boolean hasValue = false;
                if (value != null) {
                    if (value instanceof String) {
                        hasValue = !((String) value).trim().isEmpty();
                    } else {
                        hasValue = true;
                    }
                }

                // 2. 根据值是否为空，将描述加入对应列表
                if (hasValue) {
                    nonNullFieldDescs.add(fieldDesc);
                } else {
                    nullFieldDescs.add(fieldDesc);
                }
            } catch (IllegalAccessException e) {
                throw new RuntimeException("反射获取字段[" + fieldName + "]值失败", e);
            }
        }

        // 校验规则：有值字段数>0 且 <总校验字段数 → 不合法，抛自定义异常
        int totalTargetCount = targetFields.size();
        int nonNullCount = nonNullFieldDescs.size();
        if (nonNullCount > 0 && nonNullCount < totalTargetCount) {
            // 拼接错误提示信息
            String errorMsg = String.format("列表中第%d个收发货规则对象不符合规则！" +
                            "需校验字段中，有值字段：%s；空值字段：%s。" +
                            "规则要求：要么所有需校验字段都有值，要么都为空。",
                    index, nonNullFieldDescs, nullFieldDescs);
            // 抛项目自定义异常
            throw exception(CONTRACT_PARAMS_ERROR, errorMsg);
        }
    }

    /**
     * 获取字段上@Schema注解的description值，无注解则返回字段名
     */
    private static String getFieldSchemaDescription(Field field) {
        // 检查字段是否有@Schema注解
        if (field.isAnnotationPresent(Schema.class)) {
            Schema schema = field.getAnnotation(Schema.class);
            String description = schema.description();
            // 若description为空（如注解只写了example），仍返回字段名
            return description == null || description.trim().isEmpty() ? field.getName() : description;
        }
        // 无@Schema注解，返回字段名兜底
        return field.getName();
    }

    // 测试示例
    public static void main(String[] args) {
        // 测试：部分有值 → 抛自定义异常
        List<ContractReceiveSendSaveReqVO> list = new ArrayList<>();
        ContractReceiveSendSaveReqVO vo = new ContractReceiveSendSaveReqVO();
        vo.setId(1L);
        vo.setMaterialName("ZT"); // 物料名称有值
        list.add(vo);

        try {
            validateContractReceiveSend(list); // 无返回值，仅执行校验
        } catch (Exception e) {
            // 输出报错信息
            System.out.println(e.getMessage());
        }
    }
}