package com.qmth.sop.business.exec;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.qmth.sop.business.entity.TDFormWidgetMetadata;
import com.qmth.sop.business.entity.TFCustomFlow;
import com.qmth.sop.business.service.TBSopInfoService;
import com.qmth.sop.business.service.TDFormWidgetMetadataService;
import com.qmth.sop.business.service.TFCustomFlowService;
import com.qmth.sop.common.contant.SystemConstant;
import com.qmth.sop.common.enums.ExceptionResultEnum;
import com.qmth.sop.common.enums.TFCustomTypeEnum;
import com.qmth.sop.common.enums.WidgetCodeEnum;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.StringJoiner;

/**
 * @Description: MySQL数据库执行语句
 * @Param:
 * @return:
 * @Author: wangliang
 * @Date: 2022/11/14
 */
@Component
public class MySQLExec {
    private final static Logger log = LoggerFactory.getLogger(MySQLExec.class);

    @Value("${db.host}")
    String host;

    @Value("${db.port}")
    String port;

    @Value("${db.name}")
    String databaseName;

    @Value("${db.username}")
    String username;

    @Value("${db.password}")
    String password;

    @Resource
    TDFormWidgetMetadataService tdFormWidgetMetadataService;

    @Resource
    TFCustomFlowService tfCustomFlowService;

    @Resource
    TBSopInfoService tbSopInfoService;

    /**
     * 执行动态创建sop字段表
     *
     * @param fileName
     * @param type
     * @param version
     * @throws Exception
     */
    public void execCreateSopDynamicTable(String fileName, TFCustomTypeEnum type, Integer version) throws Exception {
        Optional.ofNullable(fileName).orElseThrow(() -> ExceptionResultEnum.ERROR.exception("文件名不能为空"));
        Optional.ofNullable(type).orElseThrow(() -> ExceptionResultEnum.ERROR.exception("流程类型不能为空"));

        TFCustomFlow tfCustomFlow = tfCustomFlowService.getOne(new QueryWrapper<TFCustomFlow>().lambda().eq(TFCustomFlow::getType, type).eq(TFCustomFlow::getVersion, version));
        Optional.ofNullable(tfCustomFlow).orElseThrow(() -> ExceptionResultEnum.FLOW_CUSTOM_NO_DATA.exception());

        String tableName = type.getTableName() + "_" + tfCustomFlow.getVersion();
        int count = tbSopInfoService.selectSopDynamicExist(databaseName, tableName);
        if (count == 0) {
            InputStream inputStream = MySQLExec.class.getClassLoader().getResourceAsStream(fileName);
            Optional.ofNullable(inputStream).orElseThrow(() -> ExceptionResultEnum.ERROR.exception(fileName + "未找到"));
            File file = SystemConstant.getFileTempVar(".sql");
            FileUtils.copyInputStreamToFile(inputStream, file);

            ByteArrayOutputStream ou = new ByteArrayOutputStream();
            IOUtils.copy(new FileInputStream(file), ou);
            String string = new String(ou.toByteArray(), StandardCharsets.UTF_8);

            if (Objects.nonNull(string)) {
                List<TDFormWidgetMetadata> tdFormWidgetMetadataList = tdFormWidgetMetadataService.list(new QueryWrapper<TDFormWidgetMetadata>().lambda().eq(TDFormWidgetMetadata::getType, type).eq(TDFormWidgetMetadata::getVersion, version));
                StringJoiner stringJoiner = new StringJoiner(",\r\n");
                for (TDFormWidgetMetadata t : tdFormWidgetMetadataList) {
                    if (t.getCode() == WidgetCodeEnum.TABLE || t.getCode() == WidgetCodeEnum.FILE || t.getCode() == WidgetCodeEnum.DEVICE_IN_TABLE || t.getCode() == WidgetCodeEnum.DEVICE_OUT_TABLE) {
                        stringJoiner.add("`" + t.getFieldId() + "`" + " mediumtext CHARACTER SET utf8mb4 COMMENT '" + t.getFieldTitle() + "'");
                    } else if (t.getCode() == WidgetCodeEnum.TEXTAREA) {
                        stringJoiner.add("`" + t.getFieldId() + "`" + " varchar(500) DEFAULT NULL COMMENT '" + t.getFieldTitle() + "'");
                    } else if (t.getCode() == WidgetCodeEnum.NUMBER) {
                        stringJoiner.add("`" + t.getFieldId() + "`" + " int DEFAULT NULL COMMENT '" + t.getFieldTitle() + "'");
                    } else {
                        stringJoiner.add("`" + t.getFieldId() + "`" + " varchar(100) DEFAULT NULL COMMENT '" + t.getFieldTitle() + "'");
                    }
                }
                string = string.replaceAll("\\#\\{dynamicTable\\}", "`" + tableName + "`");
                string = string.replaceAll("\\#\\{dynamicFields\\}", stringJoiner.toString());
                IOUtils.write(string.getBytes(StandardCharsets.UTF_8), new FileOutputStream(file));

                String cmdarray[] = {"mysql -h" + this.host + " -P" + this.port + " -u" + this.username + " -p" + this.password + " " + this.databaseName, "source " + file.getAbsolutePath()};
                Runtime runtime = Runtime.getRuntime();
                Process process = null;
                try {
                    process = runtime.exec(cmdarray[0]);//cmd之后执行数组的第一个条件进入数据库
                    //执行了第一条命令以后已经登录到mysql了
                    Process finalProcess = process;
                    new Thread(() -> {
                        OutputStream os = finalProcess.getOutputStream();
                        OutputStreamWriter writer = new OutputStreamWriter(os);
                        try {
                            IOUtils.write(cmdarray[1], writer);
                        } catch (IOException e) {
                            e.printStackTrace();
                        } finally {
                            try {
                                if (Objects.nonNull(writer)) {
                                    writer.close();
                                }
                                if (Objects.nonNull(os)) {
                                    os.close();
                                }
                            } catch (Exception e) {
                                log.error(SystemConstant.LOG_ERROR, e);
                            }
                        }
                    }).start();
                } catch (Exception e) {
                    log.error(SystemConstant.LOG_ERROR, e);
                } finally {
                    if (process.waitFor() == 0 && Objects.nonNull(file)) {
                        if (Objects.nonNull(file)) {
                            file.delete();
                        }
                    }
                }
            }
        }
    }
}