import com.sdtool.common.datas.TokenUserFrom
import com.sdtool.common.entity.mall.MallUser
import com.sdtool.common.entity.system.SocialUser
import com.dySweetFishPlugin.sql.dao.TunaService
import com.dySweetFishPlugin.tool.crypto.EncryptUtil
import com.sweetfish.convert.json.JsonConvert
import com.sweetfish.service.RetResult
import com.sdtool.business.dao.LoginDao
import com.sdtool.common.api.*
import com.sdtool.common.datas.ERPModule
import com.sdtool.common.entity.base.DataBaseMultiItemEx
import com.sdtool.common.entity.base.ProcessEntityItem
import com.sdtool.common.entity.site.ERPTokenUser
import com.sdtool.common.entity.site.LoginRequest
import com.sdtool.common.entity.site.LoginResult
import com.sdtool.common.entity.system.LoginUser
import com.sdtool.common.tool.ERPUtils
import com.sweetfish.util.ResourceFactory
import org.apache.commons.lang3.StringUtils
import org.apache.logging.log4j.LogManager
import org.apache.logging.log4j.Logger
import org.rex.RMap

import javax.annotation.Resource

/**
 * ERP系统登录脚本，随着业务复杂度提高，登录功能统一一个接口提供
 */
@SuppressWarnings("unused")
class BE_ERPLogin implements BusinessExecutor<ProcessEntityItem<LoginRequest>, LoginResult> {

    protected final Logger logger = LogManager.getLogger(this.getClass().getSimpleName())

    @Resource
    DeptService deptService

    @Resource
    ERPService erpService

    @Resource
    TunaService tunaService

    @Resource
    SysMessageService sysMessageService

    @Resource
    JsonConvert jsonConvert

    @Resource(name = "server")
    private ResourceFactory rf

    @Resource(name = "property.passwordSalt")
    private String passwordSalt

    private LoginDao loginDao


    //登录策略，当前数据库那一个地方需要重启服务，可改成不需要的，参考TunaDaoService动态sql执行
    def loginStrategies = [
            "0" : [
                    "name"         : "后台管理系统登录",
                    "resourceLogin": { LoginRequest loginInfo ->

                        if (loginInfo.password == "D227E2334F89C81FDE0967B115D4F29C") {
                            LoginUser info = new LoginUser()
                            info.setId(-999L)
                            info.setLoginName("SuperResourcer")
                            info.setUserName("资源管理员")
                            info.setDeptName("资源管理")

                            return RetResult.<ERPTokenUser> successT().result(new ERPTokenUser(info))
                        } else {
                            return RetResult.<ERPTokenUser> errorT().retinfo("用户账号或密码错误，登录失败")
                        }
                    },
                    "login"        : { LoginRequest loginInfo, RMap mapParams, DataBaseMultiItemEx supplierItem ->
                        mapParams.put("companyId", 0L)
                        LoginUser info = loginDao.login(mapParams, supplierItem.dataBaseAlias, Long.parseLong(supplierItem.shardingKey))

                        if (info == null) {
                            return RetResult.<ERPTokenUser> errorT().retinfo("用户账号或密码错误，登录失败")
                        }

                        if (info.status == 1) {
                            return RetResult.<ERPTokenUser> errorT().retinfo("用户账号已冻结，登录失败")
                        }

                        info.deptName = deptService.getRedisDeptName(info.getDeptId(), Long.parseLong(supplierItem.shardingKey))

                        sysMessageService.syncSysGroupMessage(info.getId(), Long.parseLong(supplierItem.shardingKey))
                        return RetResult.<ERPTokenUser> successT().result(new ERPTokenUser(info))
                    },
                    "tokenKey"     : ""
            ],
            "10" : [
                    "name"         : "PC端商城管理登录",
                    "resourceLogin": { LoginRequest loginInfo ->
                        if (loginInfo.password == "D227E2334F89C81FDE0967B115D4F29C") {
                            LoginUser info = new LoginUser()
                            info.setId(-999L)
                            info.setLoginName("SuperResourcer")
                            info.setUserName("资源管理员")
                            info.setDeptName("资源管理")

                            return RetResult.<ERPTokenUser> successT().result(new ERPTokenUser(info))
                        } else {
                            return RetResult.<ERPTokenUser> errorT().retinfo("用户账号或密码错误，登录失败")
                        }
                    },
                    "login"        : { LoginRequest loginInfo, RMap mapParams, DataBaseMultiItemEx supplierItem ->
                        LoginUser info = loginDao.login(mapParams, supplierItem.dataBaseAlias, Long.parseLong(supplierItem.shardingKey))

                        if (info == null) {
                            return RetResult.<ERPTokenUser> errorT().retinfo("用户账号或密码错误，登录失败")
                        }

                        if (info.status == 1) {
                            return RetResult.<ERPTokenUser> errorT().retinfo("用户账号已冻结，登录失败")
                        }

                        //需要强制修改下登录来源
                        ERPTokenUser tokenUser = new ERPTokenUser(info)
                        tokenUser.userFrom = TokenUserFrom.PC_MALL_ADMIN.value

                        return RetResult.<ERPTokenUser> successT().result(tokenUser)
                    },
                    "tokenKey"     : ""
            ],
            "11" : [
                    "name"         : "PC端商城购物网站登录",
                    "resourceLogin": { LoginRequest loginInfo ->
                        //不允许使用superResourcer登录，防漏洞
                        return RetResult.<ERPTokenUser> errorT().retinfo("用户账号或密码错误，登录失败")
                    },
                    "login"        : { LoginRequest loginInfo, RMap mapParams, DataBaseMultiItemEx supplierItem ->
                        MallUser info = loginDao.mallLogin(mapParams, supplierItem.dataBaseAlias, Long.parseLong(supplierItem.shardingKey))

                        if (info == null) {
                            return RetResult.<ERPTokenUser> errorT().retinfo("用户账号或密码错误，登录失败")
                        }

                        if (info.voidFlag == 1) {
                            return RetResult.<ERPTokenUser> errorT().retinfo("用户账号已冻结，登录失败")
                        }

                        return RetResult.<ERPTokenUser> successT().result(new ERPTokenUser(info))
                    },
                    "tokenKey"     : ""
            ],
            "20" : [
                    "name"         : "PC端产品中心登录",
                    "resourceLogin": { LoginRequest loginInfo ->

                        if (loginInfo.password == "D227E2334F89C81FDE0967B115D4F29C") {
                            LoginUser info = new LoginUser()
                            info.setId(-999L)
                            info.setLoginName("SuperResourcer")
                            info.setUserName("资源管理员")
                            info.setDeptName("资源管理")

                            return RetResult.<ERPTokenUser> successT().result(new ERPTokenUser(info))
                        } else {
                            return RetResult.<ERPTokenUser> errorT().retinfo("用户账号或密码错误，登录失败")
                        }
                    },
                    "login"        : { LoginRequest loginInfo, RMap mapParams, DataBaseMultiItemEx supplierItem ->
                        mapParams.put("companyId", 0L)
                        LoginUser info = loginDao.login(mapParams, supplierItem.dataBaseAlias, Long.parseLong(supplierItem.shardingKey))

                        if (info == null) {
                            return RetResult.<ERPTokenUser> errorT().retinfo("用户账号或密码错误，登录失败")
                        }

                        if (info.status == 1) {
                            return RetResult.<ERPTokenUser> errorT().retinfo("用户账号已冻结，登录失败")
                        }

                        info.deptName = deptService.getRedisDeptName(info.getDeptId(), Long.parseLong(supplierItem.shardingKey))

                        ERPTokenUser tokenUser = new ERPTokenUser(info)
                        tokenUser.setUserFrom(TokenUserFrom.PC_PRODUCT_CENTER.value)
                        return RetResult.<ERPTokenUser> successT().result(tokenUser)
                    },
                    "tokenKey"     : ""
            ],
            "50" : [
                    "name"         : "印刷商城微信小程序",
                    "resourceLogin": { LoginRequest loginInfo ->
                        //不允许使用superResourcer登录，防漏洞
                        return RetResult.<ERPTokenUser> errorT().retinfo("用户账号或密码错误，登录失败")
                    },
                    "login"        : { LoginRequest loginInfo, RMap mapParams, DataBaseMultiItemEx supplierItem ->
                        if (mallMiniService == null) {
                            //启动的服务不对，不支持50登录，只有aeMall服务才支持
                            return RetResult.<ERPTokenUser> errorT().retinfo("无效的登录方式")
                        }
                        SocialUser socialUser = mallMiniService.getRedisMallSocialUser(loginInfo.socialOpenId, Long.parseLong(supplierItem.shardingKey))

                        if (socialUser == null) {
                            return RetResult.<ERPTokenUser> errorT().retinfo("未绑定用户，请绑定")
                        }

                        if (socialUser.mallUser == null) {
                            return RetResult.<ERPTokenUser> errorT().retinfo("未绑定用户，请绑定")
                        }

                        if (socialUser.mallUser.voidFlag == 1) {
                            return RetResult.<ERPTokenUser> errorT().retinfo("用户账号已冻结，登录失败")
                        }

                        ERPTokenUser tokenUser = new ERPTokenUser(socialUser)
                        return RetResult.<ERPTokenUser> successT().result(tokenUser)
                    },
                    "tokenKey"     : ""
            ],
            "60" : [
                    "name"         : "ERP手机APP登录(用于生产反馈)",
                    "resourceLogin": { LoginRequest loginInfo ->
                        //不允许使用superResourcer登录，防漏洞
                        return RetResult.<ERPTokenUser> errorT().retinfo("用户账号或密码错误，登录失败")
                    },
                    "login"        : { LoginRequest loginInfo, RMap mapParams, DataBaseMultiItemEx supplierItem ->
                        mapParams.put("companyId", 0L)
                        LoginUser info = loginDao.login(mapParams, supplierItem.dataBaseAlias, Long.parseLong(supplierItem.shardingKey))

                        if (info == null) {
                            return RetResult.<ERPTokenUser> errorT().retinfo("用户账号或密码错误，登录失败")
                        }

                        if (info.status == 1) {
                            return RetResult.<ERPTokenUser> errorT().retinfo("用户账号已冻结，登录失败")
                        }

                        info.deptName = deptService.getRedisDeptName(info.getDeptId(), Long.parseLong(supplierItem.shardingKey))

                        ERPTokenUser tokenUser = new ERPTokenUser(info)
                        tokenUser.setUserFrom(TokenUserFrom.APP_ERP_ADMIN.value)
                        return RetResult.<ERPTokenUser> successT().result(tokenUser)
                    },
                    "tokenKey"     : ""
            ]
    ]

    @Override
    String scriptName() {
        return "ERP系统登录"
    }

    @Override
    ERPModule module() {
        return ERPModule.LOGIN
    }

    @Override
    RetResult<LoginResult> execute(ProcessEntityItem<LoginRequest> source) {
        //直接定义Resource不好使，还是需要赋值
        loginStrategies.each {
            it.value.tokenKey = rf.find("property." + TokenUserFrom.getTokenKey(Integer.parseInt(it.key)), String.class)
        }

        if (source.inputItem == null) {
            return RetResult.<LoginResult> errorT().retinfo("未传入用户信息")
        }

        if (source.inputItem.supplierId <= 0L) {
            return RetResult.<LoginResult> errorT().retinfo("请选择登录公司信息")
        }

        DataBaseMultiItemEx supplierItem = erpService.getERPSupplierInfo(source.inputItem.supplierId)
        if (supplierItem == null) {
            return RetResult.<LoginResult> errorT().retinfo("无效的登录公司信息")
        }

        if (!loginStrategies.containsKey(String.valueOf(source.inputItem.loginFrom))) {
            return RetResult.<LoginResult> errorT().retinfo("无效的登录来源")
        }

        if (source.inputItem.loginFrom != TokenUserFrom.MINI_MALL.value) {
            if (StringUtils.isEmpty(source.inputItem.loginName)) {
                return RetResult.<LoginResult> errorT().retinfo("请输入账号")
            }

            if (StringUtils.isEmpty(source.inputItem.password)) {
                return RetResult.<LoginResult> errorT().retinfo("请输入密码")
            }

            source.inputItem.password = EncryptUtil.md5Digest(source.inputItem.password + passwordSalt)
        } else {
            source.inputItem.loginName = ""
            source.inputItem.password = ""
        }

        loginDao = tunaService.generate(LoginDao.class)
        RetResult<ERPTokenUser> userResult

        def loginStrategy = loginStrategies.get(String.valueOf(source.inputItem.loginFrom))

        if (source.inputItem.loginName.equalsIgnoreCase("SuperResourcer")) {
            userResult = loginStrategy.resourceLogin.call(source.inputItem)
        } else {

            RMap<String, Object> paramMap = new RMap<>()
            paramMap.put("loginName", source.inputItem.loginName)
            paramMap.put("password", source.inputItem.password)

            userResult = loginStrategy.login.call(source.inputItem, paramMap, supplierItem)
        }

        if (userResult.isSuccess()) {
            userResult.result.dataSourceId = supplierItem.dataBaseAlias
            userResult.result.supplierCode = Long.parseLong(supplierItem.shardingKey)

            //商城小程序的加密key单独处理一下，临时方案，最好还是前端区分一下，判断登录返回的user的userFrom
            String accessToken = (source.inputItem.loginFrom == TokenUserFrom.MINI_MALL.value)
                    ? ERPUtils.parseTokenFromERPUser(userResult.result, loginStrategies.get(String.valueOf(TokenUserFrom.PC_MALL_FRONT.value)).tokenKey, jsonConvert)
                    : ERPUtils.parseTokenFromERPUser(userResult.result, loginStrategy.tokenKey, jsonConvert)

            return RetResult.<LoginResult> successT().result(new LoginResult(userResult.result, accessToken))
        } else {
            return RetResult.<LoginResult> errorT().retinfo(userResult.retinfo)
        }
    }
}
