package com.boman.web.core.domain;

import com.alibaba.fastjson.JSONObject;
import com.boman.common.core.utils.SpringUtils;
import com.boman.common.redis.RedisKey;
import com.boman.common.redis.service.RedisService;
import com.boman.domain.GenTable;
import com.boman.domain.GenTableColumn;
import com.boman.domain.constant.GlobalBtn;
import com.boman.domain.dto.FormDataDto;
import com.boman.system.api.RemoteMenuService;
import com.boman.system.api.RemoteRoleDataService;
import com.boman.domain.SysUser;
import com.boman.system.api.model.LoginUser;
import com.boman.web.core.service.TableServiceCmdService;
import com.boman.web.core.service.common.ICommonService;
import com.boman.web.core.service.select.IBaseSelectService;
import com.boman.web.core.utils.IdUtils;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;

import static com.boman.common.core.utils.obj.ObjectUtils.*;
import static com.boman.domain.constant.MaskConstant.*;
import static com.boman.web.core.utils.AuthUtils.*;
import static com.boman.web.core.utils.ColumnUtils.withoutHr;

/**
 * @author shiqian
 * @date 2021年04月13日 11:07
 **/
@Component
public class TableContext {

    @Resource
    private TableServiceCmdService cmdService;
    @Resource
    private RemoteMenuService remoteMenuService;
    @Resource
    private RemoteRoleDataService remoteRoleDataService;
    @Resource
    private ICommonService commonService;
    @Resource
    private IBaseSelectService selectService;

    private Long id;
    private String pkName;
    private GenTable table;
    private ActionType actionType;
    private String tableName;
    private String functionName;
    private JSONObject fixedData;
    private JSONObject commitData;
    private List<GenTableColumn> columns;

    public TableContext createContext(FormDataDto dto) {
        this.actionType = ltZero(dto.getObjId()) ? ActionType.INSERT : ActionType.UPDATE;
        this.id = dto.getObjId();

        RedisService redisService = SpringUtils.getBean(RedisService.class);
        String tableName = requireNonNull(dto.getTable(), "tableName is empty");
        this.tableName = tableName;

        GenTable table = redisService.getCacheObject(RedisKey.TABLE_INFO + tableName);
        this.table = requireNonNull(table, "redis中没有此表，表名: " + tableName);
        this.functionName = table.getFunctionName();

        JSONObject fixedData = requireNonNull(dto.getFixedData(), "fixedData is empty");
        this.fixedData = fixedData;

        List<GenTableColumn> columns = table.getColumns();
        this.columns = columns;
        this.pkName = IdUtils.getPkName(columns);

        // 检查权限
        checkAuthObjectSave(this);

        this.commitData = packCommitData(this, columns, fixedData);
        return this;

    }

    private void checkAuthObjectSave(TableContext context) {
        GenTable genTable = context.getTable();
        String tableName = genTable.getTableName();
        String functionName = genTable.getFunctionName();

        LoginUser loginUser = getLoginUser();
        if (SysUser.isAdmin(loginUser.getUserid())) {
            return;
        }

        if (ActionType.INSERT.equals(context.getActionType())) {
            containsFunction(genTable.getMenuRole(), GlobalBtn.A, "模块:[" + functionName + "], 没有新增功能");
            checkPermsAuth(tableName, GlobalBtn.A);
        } else {
            containsFunction(genTable.getMenuRole(), GlobalBtn.M, "模块:[" + functionName + "], 没有修改功能");
            checkPermsAuth(tableName, GlobalBtn.M);
            checkRoleDataAuth(tableName, context.getPkName(), context.getId());
        }
    }


    private static JSONObject packCommitData(TableContext context, List<GenTableColumn> columns, JSONObject fixedData) {
        JSONObject commitData = new JSONObject();
        // 过滤掉hr字段
        columns = withoutHr(columns);
        for (GenTableColumn column : columns) {
            String[] maskArray = requireNonNull(column.getMask(), "mask is empty, columnName = " + column.getColumnName()).split("");
            assert maskArray.length == 6;
            // 新增可见 修改可见
            //String insertVisible = maskArray[0], updateVisible = maskArray[2];
            // 新增可修改 修改可修改
            String insertCanEdit = maskArray[1], updateCanEdit = maskArray[3];
            for (Map.Entry<String, Object> entry : fixedData.entrySet()) {
                if (column.getColumnName().equalsIgnoreCase(entry.getKey())) {
                    // 新增
                    if (ActionType.INSERT.equals(context.getActionType())) {
                        // 新增可可见, 并且新增修改，把新增的字段单独拿出来
                        if (INSERT_CAN_EDIT.equals(insertCanEdit)) {
                            commitData.put(entry.getKey(), entry.getValue());
                        } else {
                            // 如果新增不可见，新增也不可以修改，但是你是外键的话或者是计算以后的值，就可以修改
                            if (isNotEmpty(column.getForeignKey()) || isNotEmpty(column.getExtendedAttributes())) {
                                commitData.put(entry.getKey(), entry.getValue());
                            }
                        }
                    } else {
                        // 编辑可见, 并且编辑可修改
                        if (UPDATE_CAN_EDIT.equals(updateCanEdit)) {
                            commitData.put(entry.getKey(), entry.getValue());
                        } else {
                            // 如果编辑不可见，编辑也不可以修改，但是你是外键的话或者是计算以后的值，就可以修改
                            if (isNotEmpty(column.getForeignKey()) || isNotEmpty(column.getExtendedAttributes())) {
                                commitData.put(entry.getKey(), entry.getValue());
                            }
                        }
                    }
                }
            }
        }

        return commitData;
    }

    /**                 get and set                               **/

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getPkName() {
        return pkName;
    }

    public void setPkName(String pkName) {
        this.pkName = pkName;
    }

    public GenTable getTable() {
        return table;
    }

    public void setTable(GenTable table) {
        this.table = table;
    }

    public String getTableName() {
        return tableName;
    }

    public void setTableName(String tableName) {
        this.tableName = tableName;
    }

    public JSONObject getFixedData() {
        return fixedData;
    }

    public void setFixedData(JSONObject fixedData) {
        this.fixedData = fixedData;
    }

    public JSONObject getCommitData() {
        return commitData;
    }

    public void setCommitData(JSONObject commitData) {
        this.commitData = commitData;
    }

    public List<GenTableColumn> getColumns() {
        return columns;
    }

    public void setColumns(List<GenTableColumn> columns) {
        this.columns = columns;
    }

    public ActionType getActionType() {
        return actionType;
    }

    public void setActionType(ActionType actionType) {
        this.actionType = actionType;
    }

    public String getFunctionName() {
        return functionName;
    }

    public void setFunctionName(String functionName) {
        this.functionName = functionName;
    }
}
