package com.huigou.uasp.bmp.intercept;

import com.huigou.context.ContextUtil;
import com.huigou.context.Operator;
import com.huigou.context.ThreadLocalUtil;
import com.huigou.data.domain.model.AbstractEntity;
import com.huigou.data.repository.GeneralRepository;
import com.huigou.exception.ApplicationException;
import com.huigou.uasp.bmp.operator.OperatorUIElementPermissionBuilder;
import com.huigou.uasp.bpm.event.ProcessEventContext;
import com.huigou.uasp.log.application.LogApplication;
import com.huigou.uasp.log.aspect.BizLogBuilder;
import com.huigou.uasp.log.domain.model.BizLog;
import com.huigou.uasp.log.domain.model.OperationType;
import com.huigou.util.ClassHelper;
import com.huigou.util.Constants;
import com.huigou.util.SpringBeanFactory;
import com.huigou.util.StringUtil;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 系统权限获取 页面元素使用
 *
 * @author xx
 */
public class ExecuteContextInterceptor extends HandlerInterceptorAdapter {

    @Autowired
    private LogApplication logApplication;
    @Autowired
    private GeneralRepository generalRepository;

    private OperatorUIElementPermissionBuilder operatorUIElementPermissionBuilder;

    public void setOperatorUIElementPermissionBuilder(OperatorUIElementPermissionBuilder operatorUIElementPermissionBuilder) {
        this.operatorUIElementPermissionBuilder = operatorUIElementPermissionBuilder;
    }

    /**
     * 字段及按钮权限处理
     *
     * @param permissions
     */
    private void handlePermission(Collection<Map<String, Object>> permissions, HttpServletRequest request) {
        if (permissions != null && permissions.size() > 0) {
            request.getSession().setAttribute("PermissionInterceptorSet", permissions);
            Map<String, Object> noaccessField = new HashMap<>(permissions.size());
            Map<String, Object> noaccessDetail = new HashMap<>(permissions.size());
            String code = "", operationId = "", uiElmentKindId = "";
            for (Map<String, Object> m : permissions) {
                // 如果界面元素的formFieldId不为空，则说明该界面元素是与表单字段进行的绑定，这时需要将界面元素的code替换为：field+表单字段排序
                String formFieldId = (String) m.get("formFieldId");
                if (StringUtils.isNotBlank(formFieldId)) {
                    ((List<? extends AbstractEntity>) generalRepository.getEntityManager().createQuery("select fa from FormAttribute fa where fa.id=?1")
                            .setParameter(1, formFieldId)
                            .getResultList())
                            .stream()
                            .findAny()
                            .map(this::formatFormFieldName)
                            .ifPresent(formFieldName -> m.put("code", formFieldName));
                }

                code = ClassHelper.convert(m.get("code"), String.class);
                operationId = ClassHelper.convert(m.get("operationId"), String.class, "");
                uiElmentKindId = ClassHelper.convert(m.get("kindId"), String.class, "");

                // 判读输入的key 是否为 noaccess
                if (!StringUtil.isBlank(code) && operationId.equals("noaccess")) {
                    if (uiElmentKindId.equals("0")) {// fieldType.equals("0")主集字段
                        noaccessField.put(code, "1");
                    } else if (uiElmentKindId.equals("1")) {// fieldType.equals("1")子集
                        noaccessDetail.put(code, "1");
                    }
                }
            }
            if (noaccessField.size() > 0) {
                ThreadLocalUtil.putVariable("noaccessField", noaccessField);
            }
            if (noaccessDetail.size() > 0) {
                ThreadLocalUtil.putVariable("noaccessDetail", noaccessDetail);
            }
            ThreadLocalUtil.putVariable("permissions", permissions);
        }
    }

    private String formatFormFieldName(AbstractEntity formField) {
        String formId, tableName;
        Integer tableType;
        try {
            formId = BeanUtils.getProperty(formField, "formId");
            tableName = BeanUtils.getProperty(formField, "tableName");
            tableType = Integer.valueOf(BeanUtils.getProperty(formField, "tableType"));
        } catch (Exception e) {
            throw new ApplicationException(e);
        }
        int index = -1;
        // 从SAF_FORM_ATTRIBUTE从解析字段的显示index
        List<Map<String, Object>> formFields = ((List<? extends AbstractEntity>) generalRepository.getEntityManager()
                .createQuery("select fa from FormAttribute fa where fa.formId=:formId order by fa.sequence")
                .setParameter("formId", formId)
                .getResultList())
                .stream()
                .map(ClassHelper::beanToMap)
                // 根据表名分组
                .collect(Collectors.groupingBy(field -> field.get("tableName")))
                .getOrDefault(tableName, Collections.emptyList());
        for (Map<String, Object> f : formFields) {
            index++;
            if (formField.getId().equals(f.get("id"))) {
                break;
            }
        }
        return Objects.equals(tableType, 2) ?
                String.format("%s.field%d", StringUtil.getHumpName(tableName), index)
                : String.format("field%d", index);
    }

    public void intercept(HttpServletRequest request, HttpServletResponse response) throws Exception {
        Operator operator = (Operator) request.getSession().getAttribute(Constants.SESSION_OPERATOR_ATTRIBUTE);
        String func = null;
        if (!ContextUtil.isAjaxRequest()) {
            String functionId = request.getParameter("functionId");
            String functionCode = request.getParameter("functionCode");
            if (!StringUtil.isBlank(functionId)) {
                func = functionId;
            } else if (!StringUtil.isBlank(functionCode)) {
                func = functionCode;
            }
            // 存在功能ID需要查询字段权限，及按钮权限
            if (!StringUtil.isBlank(func)) {
                try {
                    List<Map<String, Object>> permissions = operatorUIElementPermissionBuilder.queryUIElementPermissionsByFunction(func,
                            operator.getUserId(),
                            !StringUtil.isBlank(functionId));
                    handlePermission(permissions, request);
                    // 记录访问日志
                    BizLog bizLog = SpringBeanFactory.getBean(request.getSession().getServletContext(), "bizLog", BizLog.class);
                    BizLogBuilder.buildLogInfo(bizLog, OperationType.FUN, request.getRequestURI(), func);
                    logApplication.savelog(bizLog);
                } catch (Exception e) {
                    throw new ApplicationException(e);
                }
            }
        }
        // 处理任务请求
        if (ContextUtil.isJobRequest()) {
            try {
                String taskId = request.getParameter("taskId");
                if (!StringUtil.isBlank(taskId)) {
                    Collection<Map<String, Object>> permissions = operatorUIElementPermissionBuilder.queryUIElementPermissionsByTaskId(taskId);
                    handlePermission(permissions, request);
                }
            } catch (Exception e) {
                throw new ApplicationException(e);
            }
        }
    }

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        this.intercept(request, response);
        return true;
    }

    public void afterCompletion(HttpServletRequest httpservletrequest, HttpServletResponse httpservletresponse, Object obj, Exception exception) throws Exception {
        ThreadLocalUtil.removeVariableMap();
        ProcessEventContext.remove();
    }
}
