package yem.base.common.module.attach.form;

import kd.bos.bill.AbstractBillPlugIn;
import kd.bos.bill.OperationStatus;
import kd.bos.dataentity.OperateOption;
import kd.bos.dataentity.entity.DynamicObject;
import kd.bos.dataentity.entity.DynamicObjectCollection;
import kd.bos.dataentity.utils.StringUtils;
import kd.bos.entity.EntityMetadataCache;
import kd.bos.entity.MainEntityType;
import kd.bos.entity.datamodel.IDataModel;
import kd.bos.form.FormShowParameter;
import kd.bos.form.IFormView;
import kd.bos.form.control.AttachmentPanel;
import kd.bos.form.control.events.BeforeAttachmentRemoveEvent;
import kd.bos.form.control.events.BeforeAttachmentRemoveListener;
import kd.bos.form.control.events.UploadEvent;
import kd.bos.form.control.events.UploadListener;
import kd.bos.form.events.AfterDoOperationEventArgs;
import kd.bos.metadata.dao.MetaCategory;
import kd.bos.metadata.dao.MetadataDao;
import kd.bos.metadata.form.ControlAp;
import kd.bos.metadata.form.FormMetadata;
import kd.bos.metadata.form.control.AttachmentPanelAp;
import kd.bos.orm.query.QCP;
import kd.bos.orm.query.QFilter;
import kd.bos.servicehelper.BusinessDataServiceHelper;
import kd.bos.servicehelper.operation.OperationServiceHelper;
import kd.bos.servicehelper.user.UserServiceHelper;
import yem.base.common.utils.DynamicObjectUtil;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description 附件表单功能
 * @Author: LiuHB
 * @CreateTime: 2025-02-17  10:42
 */
public class AccessoryToolsBillPlugin extends AbstractBillPlugIn implements UploadListener ,BeforeAttachmentRemoveListener{


    /**
     * @Description:  注册监听器，定义了在注册监听器时的操作。
     * @param e   事件对象，表示要注册监听的事件。
     * @return void
     */

    @Override
    public void registerListener(EventObject e) {
        super.registerListener(e);
        AttachmentPanel attachmentPanel = this.getView().getControl("attachmentpanel");
        attachmentPanel.addUploadListener(this);
        attachmentPanel.addBeforeRemoveListener(this);

    }


    /**
     * @Description: 根据操作结果控制界面
     * @function 1.点击保存或提交后为附件分录的【单据id】字段赋值
     * @purposes 用户点击按钮、菜单，执行完绑定的操作后，不论成功与否，均会触发此事件
     * @param e
     * @return void
     */

    @Override
    public void afterDoOperation(AfterDoOperationEventArgs e) {
        super.afterDoOperation(e);
        IFormView view = this.getView();
        IDataModel model = view.getModel();
        String operateKey = e.getOperateKey();
        switch (operateKey) {
            case "save":
            case "submit":
                String formName = this.getView().getModel().getDataEntity(true).getDynamicObjectType().getName();
                Set<String> attachmentkey = getAttachControl(formName).keySet();
                //增加/更新附件
                attachmentForm("yem_attachmentinfo_e", attachmentkey);
                DynamicObjectCollection attachmentinfo_e = this.getView().getModel().getDataEntity(true).getDynamicObjectCollection("yem_attachmentinfo_e");
                for (int i = 0; i < attachmentinfo_e.size(); i++) {
                    model.setValue("yem_billid", model.getValue("id"), i);
                }


                break;


            default:
                break;
        }
    }

    /**
     * @Description: 用户在前端附件面板，上传文件后，系统自动调用
     */

    @Override
    public void afterUpload(UploadEvent evt) {
        UploadListener.super.afterUpload(evt);
        String formName = this.getView().getModel().getDataEntity(true).getDynamicObjectType().getName();
        Set<String> attachmentkey = getAttachControl(formName).keySet();
        //增加/更新附件
        attachmentForm("yem_attachmentinfo_e", attachmentkey);
    }
    /**
     * @Description: 用户在前端附件面板，删除文件前，系统自动调用
     * @function 校验：当前登陆人不能删除其他人上传的附件
     * @param e
     * @return void
     */
    @Override
    public void beforeAttachmentRemove(BeforeAttachmentRemoveEvent e) {
        FormShowParameter showParameter = this.getView().getFormShowParameter();
        String status = showParameter.getStatus().toString();
        if (!status.equals("ADDNEW")) {
            long userId = UserServiceHelper.getCurrentUserId();
            DynamicObject bos_user = BusinessDataServiceHelper.loadSingleFromCache(userId, "bos_user");
            Map<String, Object> map = e.getAttachemnt();
            AttachmentPanel attachmentPanel = (AttachmentPanel) e.getSource();
            String uid = (String) map.get("uid");
            List<Map<String, Object>> attachmentData = attachmentPanel.getAttachmentData();
            for (Map<String, Object> data : attachmentData) {
                String uidAttachment = (String) data.get("uid");
                if (!StringUtils.isEmpty(uidAttachment)) {
                    if (uidAttachment.equals(uid)) {
                        String creator = data.get("creator").toString();
                        if (!creator.contains(bos_user.getString("name"))) {
                            e.setMsg("不能删除别人上传的附件!!!");
                            e.setCancel(true);
                        }
                    }
                }
            }
        }
    }

    /**
     * @Description: 用户在前端附件面板，删除文件后，系统自动调用
     */

    @Override
    public void afterRemove(UploadEvent evt) {
        UploadListener.super.afterRemove(evt);
        String formName = this.getView().getModel().getDataEntity(true).getDynamicObjectType().getName();
        Map<String, String> attachControl = getAttachControl(formName);
        Set<String> attachControlkey = attachControl.keySet();
        removeAttachmentContext(attachControlkey,formName);
    }





    /**
     * @Description 附件表格赋值
     * @function 1.根据传入的附件面板标识，获取到各个附件面板的数据，调用buildAttachmentMap()方法，返回附件数据集合
     *                  key: 附件uid  value:附件信息
*                2.将现有的附件uid存入set
     *           3.判断调整后的附件面板的附件uid和附件分录的是否包含
     *              包含：根据获取到的附件信息更新分录数据
     *              不包含：新增附件分录数据
     * @param yemAttachmentdetail  附件分录标识
     * @param attachmentkey   附件面板标识集合
     * @return void
     */

    private void attachmentForm(String yemAttachmentdetail, Set<String> attachmentkey) {
        Map<String, Map<String, Object>> attachmentMap = buildAttachmentMap(attachmentkey);
        DynamicObjectCollection attachmentDetail = this.getView().getModel().getDataEntity(true).getDynamicObjectCollection(yemAttachmentdetail);
        // 获取现有的 UID 列表
        Set<String> existingUids = attachmentDetail.stream()
                .map(detail -> detail.getString("yem_attachedid"))
                .collect(Collectors.toSet());

        // 处理每个附件
        attachmentMap.forEach((uid, value) -> {
            if (existingUids.contains(uid)) {
                //更新
                updateExistingAttachment( attachmentDetail, uid, value,(String) value.get("attachmentpanelKey"));
            } else {
                //新增
                createNewAttachment( yemAttachmentdetail, uid, value, (String) value.get("attachmentpanelKey"));
            }
        });
    }


    /**
     * @Description 更新附件行
     * @param attachmentDetail 附件分录
     * @param uid 附件uid
     * @param data 附件信息
     * @param attachmentpanelKey 附件面板标识
     */
    private void updateExistingAttachment(DynamicObjectCollection attachmentDetail,
                                          String uid, Map<String, Object> data,
                                          String attachmentpanelKey) {
        for (DynamicObject attachment : attachmentDetail) {
            if (uid.equals(attachment.getString("yem_attachedid"))) {
                int rowIndex = attachmentDetail.indexOf(attachment);
                setAttachmentValues(this, rowIndex, uid, data,  attachmentpanelKey);
                break;
            }
        }
    }

    /**
     * @Description 增加新附件行
     * @param entityName 附件分录标识
     * @param uid 附件uid
     * @param data 附件信息
     * @param attachmentpanelKey 附件面板标识
     */
    private void createNewAttachment(String entityName, String uid, Map<String, Object> data,
                                     String attachmentpanelKey) {
        int newRow = this.getView().getModel().createNewEntryRow(entityName);
        setAttachmentValues(this,newRow, uid, data, attachmentpanelKey);
    }
    /**
     * @Description 附件分录赋值
     */
    private static void setAttachmentValues(AbstractBillPlugIn form, int row, String uid,
                                            Map<String, Object> data,
                                            String attachmentpanelKey) {
        //单据标识
        String billName = form.getView().getModel().getDataEntity(true).getDataEntityType().getName();
        form.getView().getModel().setValue("yem_attachmentname", data.get("name"), row);//附件名称
        form.getView().getModel().setValue("yem_atturl", data.get("url"), row);//url
        form.getView().getModel().setValue("yem_panel", attachmentpanelKey, row);//附件面板
        form.getView().getModel().setValue("yem_billno",form.getView().getModel().getValue("billno"), row);//单据编号
        form.getView().getModel().setValue("yem_docid",billName, row);//单据标识
        form.getView().getModel().setValue("yem_billid",form.getView().getModel().getValue("id"), row);//单据id
        form.getView().getModel().setValue("yem_attachedid", uid, row);//uid
        form.getView().getModel().setValue("yem_uploaddate", data.get("createTime"), row);//上传时间
        Long currentUserId = UserServiceHelper.getCurrentUserId();
        form.getView().getModel().setValue("yem_attacheduser", currentUserId, row);//上传人
        QFilter qFilter = new QFilter("yem_bill.number", QCP.equals, billName);
        qFilter.and("yem_isdefault",QCP.equals,true);
        DynamicObject attachmenttype = BusinessDataServiceHelper.loadSingle("yem_bd_attachmenttype", qFilter.toArray());
        form.getView().getModel().setValue("yem_attachmenttype", attachmenttype, row);//上传时间
    }



    /**
     * @Description 构建附件map
     * @function 功能
     * @purposes 准备附件分录需要的数据
     * @param attachmentkey
     * @return java.util.Map<java.lang.String,java.util.Map<java.lang.String,java.lang.Object>>
     *     key:附件uid value:附件信息
     */

    private Map<String, Map<String, Object>> buildAttachmentMap(Set<String> attachmentkey) {
        Map<String, Map<String, Object>> attachmentMap = new HashMap<>();
        for (String sattachmentinfo : attachmentkey) {
            AttachmentPanel attachmentPanel = this.getView().getControl(sattachmentinfo);
            List<Map<String, Object>> attachmentDatas = attachmentPanel.getAttachmentData();

            for (Map<String, Object> attachmentData : attachmentDatas) {
                String uid = (String) attachmentData.get("uid");
                String name = (String) attachmentData.get("name");
                String url = (String) attachmentData.get("url");
                Long createTime = (Long) attachmentData.get("createdate");
                // 格式化时间
                String formattedTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(createTime));
                // 获取创建人
                @SuppressWarnings("unchecked")
                Map<String, Object> creator = (Map<String, Object>) attachmentData.get("creator");
                String creatorName = creator != null ? (String) creator.get("zh_CN") : null;

                // 存储数据
                Map<String, Object> dataMap = new HashMap<>();
                dataMap.put("name", name);
                dataMap.put("url", url);
                dataMap.put("createTime", formattedTime);
                dataMap.put("creator", creatorName);
                dataMap.put("attachmentpanelKey",sattachmentinfo);
                attachmentMap.put(uid, dataMap);
            }
        }
        return attachmentMap;
    }


    /**
     * @Description: 删除附件
     * @function 1.获取当前页面所有附件面板的附件id
     *           2.遍历附件分录，判断分录id是否包含在附件面板id集合中，包含则记录行号，遍历完成删行处理
     * @purposes 用途
     * @param attachmentpanelKey   附件面板标识集合
     * @param formName 单据标识
     * @return void
     */

    private void removeAttachmentContext(Set<String> attachmentpanelKey, String formName) {

        Set<String> urlSet = new HashSet<>();
        for (String attachmentpanel : attachmentpanelKey) {
            AttachmentPanel attachment = this.getView().getControl(attachmentpanel);
            List<Map<String, Object>> attachmentDatas = attachment.getAttachmentData();
            for (Map<String, Object> attachmentData : attachmentDatas) {
                urlSet.add((String) attachmentData.get("uid"));
            }
        }
        //附件分录
        DynamicObjectCollection attachmentDetail = this.getView().getModel()
                .getDataEntity(true).
                getDynamicObjectCollection("yem_attachmentinfo_e");
        // 找出需要删除的记录（在urld中有但在urls中没有的记录）
        List<Integer> toDelete = new ArrayList<>();
        for (int i = 0; i < attachmentDetail.size(); i++) {
            DynamicObject attachment = attachmentDetail.get(i);
            if (!urlSet.contains(attachment.getString("yem_attachedid"))) {
                toDelete.add(i);
            }
        }
        if (!toDelete.isEmpty()) {
            int[] array = toDelete.stream().mapToInt(Integer::intValue).toArray();
            this.getView().getModel().deleteEntryRows("yem_attachmentinfo_e", array);
        }
        FormShowParameter showParameter = this.getView().getFormShowParameter();
        if (!showParameter.getStatus().equals(OperationStatus.ADDNEW)) {
            OperationServiceHelper.executeOperate("save", formName, new DynamicObject[]{this.getView().getModel().getDataEntity(true)}, OperateOption.create());
        }
    }


    /**
     * @Description: 获取源单实体所有附件面板的key\name
     * @param formName   源单标识
     * @return java.util.Map<java.lang.String,java.lang.String>
     *     key：附件面板标识
     *     value:附件面板名称
     */

    private Map<String, String> getAttachControl(String formName) {
        MainEntityType entityType = EntityMetadataCache.getDataEntityType(formName);
        FormMetadata taskMeta = (FormMetadata) MetadataDao.readRuntimeMeta(MetadataDao.getIdByNumber(
                entityType.getName(), MetaCategory.Form), MetaCategory.Form);
        List<ControlAp<?>> items = taskMeta.getItems();
        // 附件面板标识集合。
        Map<String, String> attachmentPanelAp = new HashMap<>();
        items.forEach(item -> {
            if (item instanceof AttachmentPanelAp) {
                AttachmentPanelAp attachmentPanel = (AttachmentPanelAp) item;
                attachmentPanelAp.put(attachmentPanel.getKey(), String.valueOf(attachmentPanel.getName()));
            }
        });
        return attachmentPanelAp;
    }

}

