package yem.wm.sex.tpl;

import kd.bos.bill.AbstractBillPlugIn;
import kd.bos.bill.OperationStatus;
import kd.bos.dataentity.entity.DynamicObject;
import kd.bos.dataentity.entity.DynamicObjectCollection;
import kd.bos.entity.datamodel.IDataModel;
import kd.bos.entity.datamodel.events.ChangeData;
import kd.bos.entity.datamodel.events.PropertyChangedArgs;
import kd.bos.entity.plugin.annotation.PluginEvent;
import kd.bos.form.field.BasedataEdit;
import kd.bos.form.field.events.BeforeF7SelectEvent;
import kd.bos.form.field.events.BeforeF7SelectListener;
import kd.bos.list.ListShowParameter;
import kd.bos.orm.query.QCP;
import kd.bos.orm.query.QFilter;
import kd.bos.servicehelper.BusinessDataServiceHelper;
import yem.base.common.utils.DynamicObjectUtil;
import yem.base.common.utils.YEM;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;


/**
 * @Description 自营出口（一般）模板（抬头+商品+财务） 表单插件
 * @Author: bang
 * @CreateTime: 2025-02-18  11:31
 */
public class SexTemplateFormPlugin extends AbstractBillPlugIn implements BeforeF7SelectListener {


    @Override
    @PluginEvent(enableOverride = true)
    public void registerListener(EventObject e) {
        super.registerListener(e);
        ((BasedataEdit) this.getControl("org")).addBeforeF7SelectListener(this);
        ((BasedataEdit) this.getControl("yem_department")).addBeforeF7SelectListener(this);
        ((BasedataEdit) this.getControl("yem_salegroup")).addBeforeF7SelectListener(this);
        ((BasedataEdit) this.getControl("yem_operator")).addBeforeF7SelectListener(this);
        ((BasedataEdit) this.getControl("yem_material")).addBeforeF7SelectListener(this);
    }

    @Override
    @PluginEvent(enableOverride = true)
    public void afterBindData(EventObject e) {
        super.afterBindData(e);
        OperationStatus status = this.getView().getFormShowParameter().getStatus();
        if (status.equals(OperationStatus.ADDNEW))orgPropertyChanged();
    }

    @Override
    @PluginEvent(enableOverride = true)
    public void beforeF7Select(BeforeF7SelectEvent evt) {
        String name = evt.getProperty().getName();
        switch (name){
            case "org":// 组织
                setOrgF7Filter(evt);
                break;
            case "yem_department":// 部门
                setDeptF7Filter(evt);
                break;
            case "yem_salegroup": // 业务组
                setGroupF7Filter(evt);
                break;
            case "yem_operator": // 业务员
                setOperatorF7Filter(evt);
                break;
            case "yem_material": // 商品
                setMaterialF7Filter(evt);
                break;
            default:
                break;
        }
    }

    @Override
    @PluginEvent(enableOverride = true)
    public void propertyChanged(PropertyChangedArgs e) {
        super.propertyChanged(e);
        ChangeData[] changeSet = e.getChangeSet();
        int rowIndex = changeSet[0].getRowIndex();
        String name = e.getProperty().getName();
        switch (name){
            case "org":// 组织
                // 判断 部门、业务员 是否是当前组织下，如果不是则清空
                orgPropertyChanged();
                break;
            case "yem_department":// 部门
                deptPropertyChange();
                break;
            case "yem_salegroup": // 业务组
                break;
            case "yem_operator": // 业务员
                operatorPropertyChange();
                break;
            case "yem_materialtype": // 商品分类
                materialTypePropertyChange(rowIndex);
                break;
            case "yem_material": // 商品
                materialPropertyChange(rowIndex);
                updateBaseUnitQty(rowIndex);
                break;
            case "yem_qty": // 数量
            case "yem_unit": // 计量单位
                updateBaseUnitQty(rowIndex);
                break;
            default:
                break;
        }

    }


    /**
     * @Description: 单据组织人员相关字段合规
     * @function 功能： 判断 部门、业务员 是否是当前组织下，如果不是则清空
     * @purposes 用途：单据新增时、组织值改变时
     */
    private void orgPropertyChanged(){
        IDataModel model = this.getView().getModel();
        DynamicObject org = (DynamicObject) model.getValue("org");
        if (YEM.isEmpty(org)) return;
        // 部门
        DynamicObject yemDepartment = (DynamicObject) model.getValue("yem_department");
        if (!YEM.isEmpty(yemDepartment)){
            // 判断组织是否在 部门的上级组织中
            boolean isOrgSubDept = isOrgSubDept(org, yemDepartment);
            if (!isOrgSubDept) model.setValue("yem_department",null);
        }
        // 业务员
        DynamicObject yemOperator = (DynamicObject) model.getValue("yem_operator");
        if (!YEM.isEmpty(yemOperator)){
            Map<Long, Boolean> orgSubUserDeptInfo = getOrgSubUserDeptInfo(org, yemOperator);
            if (orgSubUserDeptInfo.isEmpty()) model.setValue("yem_operator",null);
        }
    }

    
    /**
     * @Description: 部门值更新
     * @function 功能：判断业务员是否合规，如果在对应部门没有职能，则清空
     * @purposes 用途
     */
    private void deptPropertyChange(){
        IDataModel model = this.getView().getModel();
        DynamicObject yemDepartment = (DynamicObject) model.getValue("yem_department");// 部门
        DynamicObject yemOperator = (DynamicObject) model.getValue("yem_operator");// 业务员
        if (!YEM.isEmpty(yemOperator) && !YEM.isEmpty(yemDepartment)){
            // 判断业务员是否合规
            DynamicObjectCollection entryentity = yemOperator.getDynamicObjectCollection("entryentity");
            List<Long> deptIds = entryentity.stream().map(x ->
                    x.getDynamicObject("dpt").getLong("id")).collect(Collectors.toList());
            if (!deptIds.contains(yemDepartment.getLong("id"))){
                model.setValue("yem_operator",null);
            }
        }

    }

    /**
     * @Description: 业务员值更新
     * @function 功能： 1、更新部门：
     *                    如果部门不为空：判断部门是否合规：部门是否在 人员的部门范围内
     *                    如果为空：携带人员的部门，优先主职部门 次选 兼职部门
 *                    2、更新销售组：
     *                    如果销售组不为空：判断销售组是否合规：业务组的 业务员分录是否存在与当前分录匹配的
     *                   如果为空：根据人员、部门 查询 业务组  首个默认赋值，查不到 为空
     * @purposes 用途：单据新增时、组织值改变时
     */
    private void operatorPropertyChange(){
        IDataModel model = this.getView().getModel();
        DynamicObject org = (DynamicObject) model.getValue("org");
        DynamicObject yemOperator = (DynamicObject) model.getValue("yem_operator");
        if (YEM.isEmpty(yemOperator)) return;

        // 部门
        DynamicObject yemDepartment = (DynamicObject) model.getValue("yem_department");
        Map<Long, Boolean> orgSubUserDeptInfo = getOrgSubUserDeptInfo(org, yemOperator);
        if (!YEM.isEmpty(yemDepartment)){
            // 判断是否合规
            if (!orgSubUserDeptInfo.containsKey(yemDepartment.getLong("id"))){
                yemDepartment = null;
            }
        }
        if (YEM.isEmpty(yemDepartment)){
            // 默认赋值
            boolean aFalse = orgSubUserDeptInfo.containsValue(false);// 是否兼职
            Set<Long> deptIds = orgSubUserDeptInfo.keySet();
            for (Long id : deptIds){
                if (aFalse){
                   if (!orgSubUserDeptInfo.get(id)){
                       yemDepartment = BusinessDataServiceHelper.loadSingle(id,"bos_adminorg");
                       break;
                   }
                } else {
                    yemDepartment = BusinessDataServiceHelper.loadSingle(id,"bos_adminorg");
                    break;
                }
            }
            model.setValue("yem_department",yemDepartment);
        }

        // 销售组
        DynamicObject yemSalegroup = (DynamicObject) model.getValue("yem_salegroup");
        boolean isRational = false;
        if (!YEM.isEmpty(yemSalegroup)){
             // 判断是否合规 ：业务组-业务员分录中是否存在数据与当前业务员匹配
            DynamicObjectCollection entryentity = yemSalegroup.getDynamicObjectCollection("entryentity");
            for (DynamicObject entry : entryentity){
                DynamicObject operator = entry.getDynamicObject("operator");
                if (YEM.isEmpty(operator)) continue;
                long operatorId = operator.getLong("id");
                long yemOperatorId = yemOperator.getLong("id");
                if (operatorId == yemOperatorId) isRational = true;
            }
        }
        if (YEM.isEmpty(yemSalegroup) || !isRational){
            List<DynamicObject> groups = queryGroup(yemDepartment, yemOperator);
            if (groups != null && !groups.isEmpty()){
                model.setValue("yem_salegroup",groups.get(0));
            } else {
                model.setValue("yem_salegroup",null);
            }
        }
    }

    
    /**
     * @Description: 商品分类值更新
     * @function 功能： 商品分类更新时，如果商品分类为空 或者 商品的商品分类 与其不一致，则清空商品
     * @param rowIndex  值更新触发行
     */
    private void materialTypePropertyChange(int rowIndex){
        IDataModel model = this.getView().getModel();
        DynamicObject yemMaterialtype = (DynamicObject) model.getValue("yem_materialtype",rowIndex);// 商品分类
        DynamicObject yemMaterial = (DynamicObject) model.getValue("yem_material",rowIndex); // 商品
        if (YEM.isEmpty(yemMaterialtype)){
            model.setValue("yem_material",null,rowIndex);
            return;
        }
        if (!YEM.isEmpty(yemMaterial)){
           // 判断是否合规
            DynamicObject group = yemMaterial.getDynamicObject("group");
            if (group.getLong("id") != yemMaterialtype.getLong("id"))
                model.setValue("yem_material",null,rowIndex);
        }
    }


    /**
     * @Description: 商品值更新
     * @function 功能  商品更新时 给计量单位、基本计量单位赋值
     * @param rowIndex 值更新触发行
     */
    private void materialPropertyChange(int rowIndex){
        IDataModel model = this.getView().getModel();
        DynamicObject yemMaterial = (DynamicObject) model.getValue("yem_material",rowIndex); // 商品
        if (!YEM.isEmpty(yemMaterial)){
            DynamicObject baseunit = yemMaterial.getDynamicObject("baseunit");
            model.setValue("yem_unit",baseunit,rowIndex); // 计量单位
            model.setValue("yem_baseunit",baseunit,rowIndex); // 基本计量单位
        }
    }


    /**
     * @Description: 计算基本单位数量
     * @function 功能 ：根基 计量单位、基本计量单位 换算率  和数量 计算基本单位数量
     * @purposes 用途 物料 数量、 计量单位值更新
     * @param rowIndex 值更新触发行
     */
    private void updateBaseUnitQty(int rowIndex){
        IDataModel model = this.getView().getModel();
        DynamicObject yemMaterial = (DynamicObject) model.getValue("yem_material",rowIndex); // 商品
        DynamicObject yemUnit = (DynamicObject) model.getValue("yem_unit",rowIndex); // 商品
        DynamicObject yemBaseunit = (DynamicObject) model.getValue("yem_baseunit",rowIndex); // 商品
        BigDecimal yemQty = (BigDecimal) model.getValue("yem_qty"); // 数量
        if (!YEM.isEmpty(yemMaterial) && !YEM.isEmpty(yemUnit) && !YEM.isEmpty(yemBaseunit) && !YEM.isEmpty(yemQty)){
            BigDecimal unitRate = YEM.getUnitRate(yemMaterial,yemUnit,yemBaseunit);
            if (!YEM.isEmpty(unitRate)){
                model.setValue("yem_baseqty", unitRate.multiply(yemQty),rowIndex);
                return;
            } else {
                this.getView().showErrorNotification("没有找到对应的单位转换率,请检查后重试！");
            }
        }
        model.setValue("yem_baseqty",BigDecimal.ZERO,rowIndex);
    }
    /**
     * @Description: 是否组织下级部门
     * @function 功能 ：判断组织是否在 部门的上级组织分录中
     * @purposes 用途： 单据组织人员相关字段合规
     * @param org   组织
     * @param dept  部门
     * @return boolean 是否下级
     */
    private boolean isOrgSubDept(DynamicObject org,DynamicObject dept){
        DynamicObjectCollection structure = dept.getDynamicObjectCollection("structure");
        List<Long> parentOrgIds = new ArrayList<>();
        for (DynamicObject entry : structure){
            DynamicObject viewparent = entry.getDynamicObject("viewparent");
            if (!YEM.isEmpty(viewparent))parentOrgIds.add(viewparent.getLong("id"));
        }
        return parentOrgIds.contains(org.getLong("id"));
    }

    /**
     * @Description: 组织下人员部门信息
     * @function 功能 ： 人员部门分录，判断部门是否组织下级
     * @purposes 用途 ： 判断人员在组织下是否有职能
     *                  部门选择时 根据组织人员过滤
     * @param org  组织
     * @param user  人员
     * @return Map<Long,Boolean>： key 部门id，value ： 是否兼职
     */
    private Map<Long,Boolean> getOrgSubUserDeptInfo(DynamicObject org, DynamicObject user){
        // 定义Map统计部门信息
        Map<Long,Boolean> result = new HashMap<>();
        // 人员部门分录
        DynamicObjectCollection entryentity = user.getDynamicObjectCollection("entryentity");
        for (DynamicObject entry : entryentity){
            DynamicObject dpt = entry.getDynamicObject("dpt");
            dpt = BusinessDataServiceHelper.loadSingle(dpt.getLong("id"),"bos_adminorg");
            boolean orgSubDept = isOrgSubDept(org, dpt);// 是否组织下部门
            boolean ispartjob = entry.getBoolean("ispartjob");// 是否兼职
            if (orgSubDept)result.put(dpt.getLong("id"),ispartjob);
        }
        return result;
    }


    /**
     * @Description: 根据当前登录人员的过滤可选组织
     * @function 功能 ：获取当前用户可切换的组织集合，设置过滤条件
     * @purposes 用途 组织选择时
     */
    private void setOrgF7Filter(BeforeF7SelectEvent e) {
        // 获取当前用户可切换的组织集合
        List<Long> orgIds = YEM.getUserChangeAbleOrgIds();
        // 设置过滤条件
        if (orgIds != null){
            f7SetFilters(e,new QFilter("id", QCP.in, orgIds.toArray()));
        }
    }


    /**
     * @Description: 根据销售组织、销售业务员 过滤可选部门
     * @function 功能 ：根据情况设置过滤条件：销售组织下的所有行政组织
     *                销售业务员不为空时：可选 业务员 在该组织下的所有职能部门
     * @purposes 用途 部门选择时
     * @param e 选择事件参数
     */
    private void setDeptF7Filter(BeforeF7SelectEvent e) {
        DynamicObject org = (DynamicObject) this.getView().getModel().getValue("org");
        if (YEM.isEmpty(org)){
            e.setCancel(true);
            this.getView().showErrorNotification("请先选择销售组织！");
        }
        DynamicObject yemOperator = (DynamicObject) this.getView().getModel().getValue("yem_operator");
        QFilter filter = new QFilter("structure.viewparent.id", QCP.equals, org.getLong("id"))
                .or(new QFilter("id",QCP.equals,org.getLong("id")));
        if (!YEM.isEmpty(yemOperator)){
            Map<Long, Boolean> orgSubUserDeptInfo = getOrgSubUserDeptInfo(org, yemOperator);
            Long[] deptIds = orgSubUserDeptInfo.keySet().toArray(new Long[0]);
            if (deptIds.length > 0)
               filter = filter.and(new QFilter("id", QCP.in, deptIds));
        }
        f7SetFilters(e,filter);
    }

    /**
     * @Description: 业务组选择过滤
     * @function 功能 ：根据销售组织、销售部门和销售业务员过滤:
     *                    业务组类型为销售组、业务组-业务员分录 未失效、业务组-业务员分录存在当前业务员
     * @purposes 用途：业务组选择
     * @param e 选择事件参数
     */
    private void setGroupF7Filter(BeforeF7SelectEvent e){
        IDataModel model = this.getView().getModel();
        DynamicObject org = (DynamicObject) model.getValue("org"); // 组织
        DynamicObject yemDepartment = (DynamicObject) model.getValue("yem_department"); // 部门
        DynamicObject yemOperator = (DynamicObject) this.getView().getModel().getValue("yem_operator");// 业务员
        QFilter filter = new QFilter("operatorgrouptype",QCP.equals,"XSZ");// 业务组类型为销售组
        filter = filter.and(new QFilter("enable",QCP.equals,"1"));// 可用
        filter = filter.and(new QFilter("entryentity.invalid",QCP.equals,false));// 未失效
        if (!YEM.isEmpty(org) && !YEM.isEmpty(yemDepartment)){
            List<Long> deptId = queryOrgSub(org);
            List<Long> deptIds = queryOrgSub(yemDepartment);
            deptIds.addAll(deptId);
            // 查询部门下所有人员
//            DynamicObject[] load = BusinessDataServiceHelper.load("bos_user", "id",
//                    new QFilter[]{new QFilter("entryentity.dpt.id", QCP.in,
//                            deptIds.toArray(new Long[0]))});

            if (!deptIds.isEmpty())
                filter = filter.and(new QFilter("entryentity.operator.entryentity.dpt.id",QCP.in,
                        deptIds.toArray(new Long[0])));
        } else {
            e.setCancel(true);
            this.getView().showErrorNotification(YEM.isEmpty(org) ? "请先选择销售组织！" : "请先选择销售部门！");
            return ;
        }
        if (yemOperator != null){
            filter = filter.and(new QFilter("entryentity.operator.id",QCP.equals,
                    yemOperator.getLong("id")));
        }
        ListShowParameter showParameter = (ListShowParameter) e.getFormShowParameter();
        showParameter.getListFilterParameter().setFilter(filter);
    }

    /**
     * @Description: 业务员选择过滤
     * @function 功能 ：根据销售组织、销售部门和销售组过滤
     * @purposes 用途 业务员选择
     * @param e 选择事件参数
     */
    private void setOperatorF7Filter(BeforeF7SelectEvent e) {
        IDataModel model = this.getView().getModel();
        DynamicObject org = (DynamicObject) model.getValue("org"); // 组织
        DynamicObject yemDepartment = (DynamicObject) model.getValue("yem_department"); // 部门
        DynamicObject yemSalegroup = (DynamicObject) model.getValue("yem_salegroup"); // 业务组
        QFilter filter = null;
        if (org != null){
            List<Long> deptIds = queryOrgSub(org);
            if (!deptIds.isEmpty())
                filter = new QFilter("entryentity.dpt.id",QCP.in,deptIds.toArray(new Long[0]));
        } else {
            e.setCancel(true);
            this.getView().showErrorNotification( "请先选择销售组织！");
            return;
        }
        if (yemDepartment != null){
            List<Long> deptIds = queryOrgSub(yemDepartment);
            if (!deptIds.isEmpty())
                filter = new QFilter("entryentity.dpt.id",QCP.in,deptIds.toArray(new Long[0]));
        } else {
            e.setCancel(true);
            this.getView().showErrorNotification( "请先选择销售部门！");
            return ;
        }
        if (yemSalegroup != null){
            // 业务组 的业务员分录
            DynamicObjectCollection entryentity = yemSalegroup.getDynamicObjectCollection("entryentity");
            List<Long> operatorIds = new ArrayList<>();
            for (DynamicObject entry : entryentity){
                DynamicObject operator = entry.getDynamicObject("operator");
                if (!YEM.isEmpty(operator))operatorIds.add(operator.getLong("id"));
            }
            if (!operatorIds.isEmpty())filter = new QFilter("id",QCP.in,operatorIds.toArray(new Long[0]));
        }
        f7SetFilters(e,filter);
    }

    /**
     * @Description: 描述 商品选择过滤
     * @function 功能 商品选择时 商品分类不能为空
     * @purposes 用途 商品选择
     * @param e 选择事件参数
     */
    private void setMaterialF7Filter(BeforeF7SelectEvent e){
        IDataModel model = this.getView().getModel();
        DynamicObject yemMaterialtype = (DynamicObject) model.getValue("yem_materialtype", e.getRow());
        if (yemMaterialtype == null){
            e.setCancel(true);
            this.getView().showErrorNotification( "请先选择商品分类！");
            return;
        }
        f7SetFilters(e,new QFilter("group.id",QCP.equals, yemMaterialtype.getLong("id")));
    }

    /**
     * @Description: 根据业务员、部门 查询业务组
     * @function 功能
     * @purposes 用途 ： 业务组选择过滤
     *                  默认赋值
     * @param dept  部门
     * @param operator   业务员
     * @return List<DynamicObject> 符合条件的业务组数据
     */
    private List<DynamicObject> queryGroup(DynamicObject dept,DynamicObject operator){
        if (YEM.isEmpty(operator)) return null;
        String selectfields = DynamicObjectUtil.getSelectfields("bd_operatorgroup", true);
        DynamicObject[] load = BusinessDataServiceHelper.load("bd_operatorgroup", selectfields, new QFilter[]{
                new QFilter("entryentity.operator.dpt.id", QCP.equals, dept.getLong("id")),
                new QFilter("entryentity.operator.id", QCP.equals, operator.getLong("id"))});
        return Arrays.asList(load);
    }

    /**
     * @Description: 查询组织下级组织内码集合（包含当前组织）
     * @function 功能：上级组织 = 组织
     * @purposes  根据组织过滤字段
     * @param org  组织
     * @return List<Long>
     */
    private List<Long> queryOrgSub(DynamicObject org){
         List<Long> orgIds = new ArrayList<>();
         if (org == null) return orgIds;
         orgIds.add(org.getLong("id"));
        DynamicObject[] load = BusinessDataServiceHelper.load("bos_adminorg", "id",
                new QFilter[]{ new QFilter("enable", QCP.equals, "1"),// 可用
                new QFilter("structure.viewparent.id", QCP.equals, org.getLong("id")) });
        for (DynamicObject obj : load){
            orgIds.add(obj.getLong("id"));
        }
        return  orgIds;
    }

    /**
     * @Description: F7 设置过滤条件
     * @function 功能 字段选择是设置过滤条件
     * @param evt  选择事件参数
     * @param filter 业务过滤条件
     */
    private void f7SetFilters(BeforeF7SelectEvent evt , QFilter filter){
        ListShowParameter showParameter = (ListShowParameter) evt.getFormShowParameter();
        List<QFilter> qFilters = showParameter.getListFilterParameter().getQFilters();
        for (QFilter f : qFilters){
            filter = filter != null ? filter.and(f) : f;
        }
        showParameter.getListFilterParameter().setFilter(filter);
    }
}
