package com.qiaoba.module.tenant.handler;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.StrUtil;
import cn.hutool.db.DbUtil;
import cn.hutool.db.sql.SqlExecutor;
import com.qiaoba.module.tenant.utils.MenuUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.jdbc.ScriptRunner;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.FileReader;
import java.nio.charset.Charset;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;

/**
 * MysqlHandler
 *
 * @author ailanyin
 * @version 1.0
 * @since 2023/6/5 16:28
 */
@Component
@Slf4j
@RequiredArgsConstructor
public class MysqlDataHandler implements DataHandler {

    /**
     * 角色-超管ID
     */
    private static final ThreadLocal<Long> ROLE_SUPER_ADMIN_ID = new ThreadLocal<>();

    /**
     * 用户-超管ID
     */
    private static final ThreadLocal<Long> USER_SUPER_ADMIN_ID = new ThreadLocal<>();

    @Override
    public boolean handle(Connection conn, String tenantId, Boolean needCreateTables) {

        try {
            // 手动提交
            conn.setAutoCommit(false);
            // 创建表
            if (needCreateTables) {
                initTables(conn);
            }
            // 处理 sys_config
            handleSysConfig(conn, tenantId);
            // 处理 sys_post
            handleSysPost(conn, tenantId);
            // 处理 sys_role
            handleSysRole(conn, tenantId);
            // 处理 sys_user
            handleSysUser(conn, tenantId);
            // 处理 sys_user_role
            bindUserAndRole(conn, tenantId);
            // 处理 sys_menu
            MenuUtil.handleMenu(conn, tenantId);
            // 处理 sys_role_menu
            bindRoleAndMenu(conn, tenantId);
            conn.commit();
            return true;
        } catch (Exception e) {
            try {
                conn.rollback();
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
            e.printStackTrace();
        } finally {
            DbUtil.close(conn);
            ROLE_SUPER_ADMIN_ID.remove();
            USER_SUPER_ADMIN_ID.remove();
        }
        return false;
    }

    private void initTables(Connection conn) throws Exception {
        ClassPathResource resource = new ClassPathResource("MySQL/table/base_tables");
        File file = resource.getFile();
        FileReader reader = new FileReader(file);
        ScriptRunner scriptRunner = new ScriptRunner(conn);
        scriptRunner.setSendFullScript(true);
        scriptRunner.runScript(reader);
        reader.close();
    }

    private void handleSysConfig(Connection conn, String tenantId) throws Exception {
        handleSql(conn, tenantId, "MySQL/data/sys_config_data");
    }

    private void handleSql(Connection conn, String tenantId, String fileName) throws Exception {
        ClassPathResource resource = new ClassPathResource(fileName);
        List<String> lines = FileUtil.readLines(resource.getFile(), Charset.defaultCharset());
        StringBuilder sb = new StringBuilder();
        for (String line : lines) {
            if (StrUtil.isNotBlank(line)) {
                Snowflake snowflake = new Snowflake();
                line = StrUtil.format(line, snowflake.nextId(), tenantId);
                sb.append(line);
            }
        }
        if (StrUtil.isNotBlank(sb.toString())) {
            SqlExecutor.execute(conn, sb.toString());
        }
    }

    private void handleSysPost(Connection conn, String tenantId) throws Exception {
        handleSql(conn, tenantId, "MySQL/data/sys_post_data");
    }

    private void handleSysRole(Connection conn, String tenantId) throws Exception {
        handleUserOrRole(conn, tenantId, "MySQL/data/sys_role_data", true);
    }

    private void handleUserOrRole(Connection conn, String tenantId, String fileName, Boolean isRole) throws Exception {
        ClassPathResource resource = new ClassPathResource(fileName);
        List<String> lines = FileUtil.readLines(resource.getFile(), Charset.defaultCharset());
        StringBuilder sb = new StringBuilder();
        long superAdminId = new Snowflake().nextId();
        if (isRole) {
            ROLE_SUPER_ADMIN_ID.set(superAdminId);
        } else {
            USER_SUPER_ADMIN_ID.set(superAdminId);
        }
        for (int i = 0; i < lines.size(); i++) {
            String line = lines.get(i);
            if (StrUtil.isBlank(line)) {
                continue;
            }
            if (i == 0) {
                // 第1行是超管
                line = StrUtil.format(line, superAdminId, tenantId);
            } else {
                Snowflake snowflake = new Snowflake();
                line = StrUtil.format(line, snowflake.nextId(), tenantId);
            }
            sb.append(line);
        }
        if (StrUtil.isNotBlank(sb.toString())) {
            SqlExecutor.execute(conn, sb.toString());
        }
    }

    private void handleSysUser(Connection conn, String tenantId) throws Exception {
        handleUserOrRole(conn, tenantId, "MySQL/data/sys_user_data", false);
    }

    private void bindUserAndRole(Connection conn, String tenantId) throws Exception {
        // user_id role_id tenant_id
        String sql = StrUtil.format("INSERT INTO `sys_user_role` VALUES ({}, {}, {});",
                USER_SUPER_ADMIN_ID.get(),
                ROLE_SUPER_ADMIN_ID.get(), tenantId);
        SqlExecutor.execute(conn, sql);
    }

    private void bindRoleAndMenu(Connection conn, String tenantId) throws Exception {
        String sql = "INSERT INTO `sys_role_menu` VALUES ({}, {}, {});";
        StringBuilder sb = new StringBuilder();
        List<String> menuIds = MenuUtil.getAllMenuIdsByTenantId(conn, tenantId);
        for (String menuId : menuIds) {
            sb.append(StrUtil.format(sql, ROLE_SUPER_ADMIN_ID.get(), menuId, tenantId));
        }
        if (StrUtil.isNotBlank(sb.toString())) {
            SqlExecutor.execute(conn, sb.toString());
        }
    }
}
