import com.sdtool.common.api.BusinessExecutor
import com.sdtool.common.api.ERPService
import com.sdtool.common.api.NoSqlKeysService
import com.sdtool.common.api.SupplierInitService
import com.sdtool.common.datas.ERPModule
import com.sdtool.common.datas.RedisKeys
import com.sdtool.common.entity.base.DataBaseMultiItemEx
import com.sdtool.common.entity.base.ProcessERPClientItem
import com.sdtool.common.entity.base.ProcessStringItem
import com.sdtool.common.tool.CodeGenerate
import com.sdtool.common.tool.ERPUtils
import com.dySweetFishPlugin.redis.RedisService
import com.dySweetFishPlugin.sql.DBService
import com.dySweetFishPlugin.sql.TableIdService
import com.sweetfish.service.RetResult
import org.apache.commons.io.FileUtils
import org.apache.logging.log4j.LogManager
import org.apache.logging.log4j.Logger
import org.rex.DB
import org.rex.RMap
import org.rex.db.exception.DBException

import javax.annotation.Resource

@SuppressWarnings("unused")
class BE_System_Init_ERPClient implements BusinessExecutor<ProcessERPClientItem, ProcessStringItem> {

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

    @Resource
    private SupplierInitService supplierService

    @Resource
    private ERPService erpService

    @Resource
    private DBService dbService

    @Resource
    private RedisService redisService

    @Resource
    private NoSqlKeysService keysService

    @Resource
    private TableIdService tableIdService

    @Resource
    private CodeGenerate codeGenerate

    @Resource(name = "APP_HOME")
    private String appHome

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

    @Override
    String scriptName() {
        return "初始化SAAS商户"
    }

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

    void start(long supplierCode) {

    }

    RetResult<ProcessStringItem> execute(ProcessERPClientItem source) {
        DataBaseMultiItemEx dataItem = source.dataItem

        DataBaseMultiItemEx srcItem = erpService.getERPSupplierInfoByCode(dataItem.getItemCode())
        if (srcItem != null) {
            return RetResult.<ProcessStringItem> errorT().retinfo("重复的itemCode")
        }

        srcItem = erpService.getERPSupplierInfoBySharding(Long.parseLong(dataItem.getShardingKey()))
        if (srcItem != null) {
            return RetResult.<ProcessStringItem> errorT().retinfo("重复的shardingKey")
        }

//        dataItem.setMd5ParamDigest(codeGenerate.generateMD5Key());

        dataItem.itemType = 1
        dataItem.voidFlag = 0
        dataItem.dataSchema = dataItem.itemCode + "_" + dataItem.shardingKey

        //1、创建数据库
        dbService.update("create dataBase IF NOT EXISTS " + dataItem.dataSchema + " CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;")

        //2、sys_DataBaseMultiItem表中插入记录
        RMap dataParams = new RMap()
        dataParams.put("itemName", dataItem.itemName)
        dataParams.put("dataBaseAlias", dataItem.dataBaseAlias)
        dataParams.put("shardingKey", dataItem.shardingKey)
        dataParams.put("itemType", dataItem.itemType)
        dataParams.put("contactUrl", dataItem.contactUrl)
        dataParams.put("voidFlag", dataItem.voidFlag)
        dataParams.put("itemCode", dataItem.itemCode)
        dataParams.put("contactPerson", dataItem.contactPerson)
        dataParams.put("contactPhone", dataItem.contactPhone)
        dataParams.put("md5ParamDigest", dataItem.md5ParamDigest)

        //先不执行，免得启动的时候找脚本
        DB.update("insert into sys_DataBaseMultiItem " +
                "(itemName, dataBaseAlias, shardingKey, itemType, contactUrl, voidFlag, itemCode, contactPerson, contactPhone, md5ParamDigest) " +
                "values(" +
                "#{itemName}, #{dataBaseAlias}, #{shardingKey}, #{itemType}, #{contactUrl}, #{voidFlag}, #{itemCode}, #{contactPerson}, #{contactPhone}, #{md5ParamDigest})",
                dataParams)

        //需要上面的id,
        long idItem = dbService.getLong("select id from sys_DataBaseMultiItem where shardingKey = " + dataItem.shardingKey)

        //3、增加数据源，这个必须执行，否则下面执行sql无法带上数据源
        dbService.addDataSource(dataItem.dataBaseAlias,
                "com.mysql.jdbc.Driver",
                "jdbc:mysql://192.168.1.22:3306/" + dataItem.dataSchema + "?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&rewriteBatchedStatements=true",
                "dbadmin", "Admin@123")

        //4、创建表和视图
        String initSqlRoot = appHome + File.separator +
                "conf" + File.separator +
                "sqlInit" + File.separator +
                (("ERP".equalsIgnoreCase(sysRunMode)) ? "erp" : "mall")

        //获取脚本目录下的所有文件，并按照文件名排序
        File dir = new File(initSqlRoot)
        File[] scriptFiles = dir.listFiles().sort { file ->
            return Integer.parseInt(file.name.split("_")[1])
        }


        scriptFiles.each { file ->
            //如果有存储过程的语句，则需要单独处理，最好每一个存储过程一个sql，因为存储过程的sql包含有 ; 号，整个文件一起执行最好
            def fileContent = file.text
            // 替换${supplyCode}为1000
            def replacedContent = fileContent.replaceAll('\\$\\{supplyCode}', dataItem.shardingKey)

            try {
                def content = ERPUtils.replaceEscape(replacedContent)
                def sqlArray = content.split(";")
                sqlArray.each {sql ->
                    try {
                        dbService.update(dataItem.dataBaseAlias, sql)
                    } catch (DBException e1) {
                        logger.error(sql)
                        logger.error("执行初始化sql失败: " + e1.getMessage(), e1)
                    }

                }
                logger.info("初始化" + dataItem.itemName + "完成")
                //好像文件太大了直接批量执行不行：（
                //dbService.batchUpdate(dataItem.dataBaseAlias, content.split(";"))
            } catch (DBException e) {
                logger.error("执行初始化sql失败: " + e.getMessage(), e)
            }
        }

        //用于产品中心对接,此处将上面生成的itemCode与Md5ParamDigest更新进数据库
        String sql = "UPDATE tbconfigvalue" + dataItem.shardingKey + " SET configValue1 = '" + dataItem.itemCode + "', " +
                "configValue2 = '" + dataItem.md5ParamDigest + "' WHERE configKey = 'productCenterCallClientInfo';"
        dbService.update(dataItem.dataBaseAlias, sql)

        //5、拷贝脚本目录，1000是保留的，不论是mall还erp，都保留一个1000的目录，不然此脚本也不方便调用，其它的都从1000拷贝出去
        FileUtils.copyDirectory(
                new File(appHome + File.separator +
                        "conf" + File.separator +
                        "script" + File.separator +
                        "1000"),
                new File(appHome + File.separator +
                        "conf" + File.separator +
                        "script" + File.separator +
                        dataItem.shardingKey)
        )

        //6、分表分库写入到redis
        dataItem.id = idItem

        redisService.hset(keysService.getRedisKey(RedisKeys.KEY_SUPPLIER_PLATFORM), String.valueOf(idItem), dataItem)
        redisService.hset(keysService.getRedisKey(RedisKeys.KEY_SUPPLIER_SHARDING_KEY_PLATFORM), dataItem.shardingKey, dataItem)
        redisService.hset(keysService.getRedisKey(RedisKeys.KEY_SUPPLIER_ITEM_CODE_PLATFORM), dataItem.itemCode, dataItem)

        //7、id、code初始化
        tableIdService.initSupplierId(dataItem)
        tableIdService.initSupplierCode(dataItem)

        //8、调用初始化
        supplierService.addSupplier(dataItem)


        return RetResult.<ProcessStringItem> successT()
    }
}

