package org.example.Impl;

import com.microsoft.sqlserver.jdbc.SQLServerDataSource;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import io.jsonwebtoken.Claims;
import jakarta.annotation.PostConstruct;
import jakarta.servlet.http.HttpSession;
import org.example.Api.LoggerHandler;
import org.example.Api.SingleUserHandler;
import org.example.Entity.BaseResponse.BaseResponse;
import org.example.Enums.LoginCode;
import org.example.Enums.SystemTypeEnums;
import org.example.Impl.Sql.factory.AllInOneSqlFactory;
import org.example.Impl.Sql.provider.AllInOneSqlProvider;
import org.example.Service.AuthService;
import org.example.Auth.utils.*;

import org.example.Entity.System.LoginUserInfo;
import org.example.Utils.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jdbc.core.*;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;


import static org.example.Utils.NativeExtensionUtils.*;
import static org.springframework.util.StringUtils.truncate;

@Service
public class SysUserImpl extends OptBaseImpl implements AuthService {


    @Autowired
    private JwtUtils jwtUtils;

    @Autowired
    private SMSImpl smsImp;

    @Autowired
    private NamedParameterJdbcTemplate namedJdbcTemplate;

    // 注入 Spring 管理的 SingleUserHandler 实例（非 static）
    @Autowired
    private SingleUserHandler singleUserHandler;

    private AllInOneSqlProvider sqlProvider;

    @Value("${custom.database.type}")
    private String databaseType;

    @Autowired
    AllInOneSqlFactory allInOneSqlFactory; // 注入Spring管理的实例

    @PostConstruct
    public void initSqlProvider() {
        // 工厂只创建一次，结果缓存到成员变量sqlProvider中
        this.sqlProvider = allInOneSqlFactory.createProvider(this.databaseType);
    }

    @Autowired
    private DataImpl dataImpl; // 对应C#的dataImpl

    // 新增：手动传参用的构造函数（给 new 的实例赋值）
    public SysUserImpl(DataImpl dataImpl) {
        this.dataImpl = dataImpl; // 手动把 DataImpl 传进来，覆盖默认的 null
    }

    public SysUserImpl() {
    }

    @Autowired
    private SafetyUtil safetyUtil;

    @Autowired
    private JdbcTemplate jdbcTemplate;

    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = Objects.requireNonNull(jdbcTemplate, "JdbcTemplate must not be null");
    }

    private JdbcTemplate createManualJdbcTemplate() {
        // 1. 配置 SQL Server 数据源
        throw new IllegalStateException("JdbcTemplate must be injected; manual datasource fallback is disabled");
        // 2. 关联数据源到 JdbcTemplate
    }

    // 手机号正则表达式
    private static final Pattern PHONE_PATTERN = Pattern.compile("^1[3-9]\\d{9}$");
    @Autowired
    private DbOperator dbOperator;


    //新增login传入默认值
    public BaseResponse Login(String loginAccount, String pwd, String seriesId,
                              int serverId, SystemTypeEnums.LoginType loginType) {
        return Login(loginAccount, pwd, seriesId, serverId, loginType, null, "");
    }

    /**
     * 用户登录
     *
     * @param loginAccount 登录账号（名称或编号）
     * @param pwd          密码（MD5加密或未加密）
     * @param seriesId     系列ID
     * @param serverId     服务器ID
     * @param loginType    登录类型
     * @param ip           IP地址
     * @param osClientInfo 设备信息（用于推送）
     * @return 登录响应结果
     */

    public BaseResponse Login(String loginAccount, String pwd, String seriesId,
                              int serverId, SystemTypeEnums.LoginType loginType, String ip, String osClientInfo) {
        //serverId=0是我们自己新增的，避免切换账套的数据库问题
        serverId = 0;
        BaseResponse[] response = new BaseResponse[1];
        response[0] = new BaseResponse();
        LoginUserInfo luser = null;
        List<Map<String, Object>> dtval = null;

        try {
            // URL解码登录账号
            loginAccount = URLDecoder.decode(loginAccount, StandardCharsets.UTF_8);
        } catch (Exception e) {
            log.warn(String.format("登录账号解码失败%s", e));
            response[0].setSuccess(false);
            response[0].setMsg("登录账号格式错误");
            return response[0];
        }

        //切换数据库服务器
        if (serverId > 0) {
            StringBuilder errMsg = new StringBuilder();
            DbOperator dbOper = ChangeServer(serverId, errMsg);
            if (dbOper != null) {
                dbOperator = dbOper;
            }
        }
        jdbcTemplate = dbOperator.getJdbcTemplate();
        log.debug(String.valueOf("当serverid=0时" + jdbcTemplate));
        String conStr = dbOperator.getConnectionString();
        log.debug("Default server connection string available: {}", conStr != null && !conStr.isBlank());
        // AD登录逻辑
        boolean ok = false;
        if ((ADUtil.ADLogin != null ? ADUtil.ADLogin : false) == true && !ok) {

        }
        if ((ADUtil.ADLogin != null ? ADUtil.ADLogin : false) == true) {
            loginType = SystemTypeEnums.LoginType.AD;
        }


        // 数据库查询用户信息
        if ((ADUtil.ADLogin != null ? ADUtil.ADLogin : false) == false || !ok) {
//            String sql = "select e.EmployeeId, e.EmpLoyeeName, e.LoginAccount, e.password, " +
//                    "e.p_emp_clientid, e.p_emp_AttendanceTime, e.p_emp_logintype, " +
//                    "e.p_emp_PwdErrNum, e.p_emp_PwdLocked, e.p_emp_PwdLockDate, e.AppIndex " +
//                    "from dbo.P_EmployeeTab e " +
//                    "left join dbo.P_customertab b on e.p_emp_clientid = b.id and b.coid = ? " +
//                    "where (e.LoginAccount = ? or e.EmployeeName = ? or e.p_emp_phone = ? or isnull(b.id, '') <> '') " +
//                    "and isnull(e.sign, 0) = 0 " +
//                    "and isnull(e.UseFlag, 0) = 1";
            String sql = sqlProvider.LoginSql();
            dtval = jdbcTemplate.queryForList(
                    sql,
                    // 对应C#的@LoginAccount参数，按SQL中?出现顺序传入
                    loginAccount, loginAccount, loginAccount, loginAccount
            );
            // 检查查询结果是否存在多个用户
            if (dtval.size() > 1) {
                response[0].setMsg("用户名不唯一，请换手机号登录！");
                return response[0];
            }

            // 初始化登录用户信息（对应C#的LoginUserInfo实例化）
            if (dtval.size() > 0) {
                Map<String, Object> userRow = dtval.get(0); // 对应C#的dtval.Rows[0]
                luser = new LoginUserInfo();
                // 字符串类型：defaultVal用""（对应C#中DBNull.Value + ""的结果）
                luser.UserId = DataTableUtil.get(userRow, "EmployeeId", "").toString();
                luser.UserCode = DataTableUtil.get(userRow, "LoginAccount", "").toString();
                luser.UserName = DataTableUtil.get(userRow, "EmpLoyeeName", "").toString();
                luser.Pwd = DataTableUtil.get(userRow, "password", "").toString();
                luser.InPwd = pwd;
                // 整数类型：defaultVal用0（对应数据库默认值或C#中有效整数场景）
                luser.LoginType = NativeExtensionUtils.ToInt32(
                        DataTableUtil.get(userRow, "p_emp_logintype", 0)
                );
                luser.ClientId = NativeExtensionUtils.ToInt32(
                        DataTableUtil.get(userRow, "p_emp_clientid", 0)
                );
                luser.AttendanceTime = NativeExtensionUtils.ToInt32(
                        DataTableUtil.get(userRow, "p_emp_AttendanceTime", 0)
                );
                // AppIndex：根据设备类型设置，默认值为空字符串
                luser.AppIndex = (isPhone() || !isWindowsDirver()) ?
                        (String) DataTableUtil.get(userRow, "AppIndex", "") : "";
            }
            // 检查用户是否已登录
            if (luser != null && singleUserHandler.hasLoginUser(luser.UserId)) {
                //现在没有设置下方的success
                //response[0].setSuccess(false);
                response[0].setMsg("该用户已登录！");
                return response[0];
            }
        }

        // 初始化空用户信息
        if (luser == null) {
            luser = new LoginUserInfo();
            luser.UserId = "0";
            luser.UserCode = loginAccount;
            luser.UserName = "";
        }

        // 密码加密处理（如果未加密）
        String newPwd = pwd;
        if (newPwd.length() < 32) {
            newPwd = SafetyUtil.encryptPassword(pwd);
        }

        // 2. 调用存储过程（替代C#的ref returnValue + DataTable返回）
        Map<String, Object> DataTable = LoginPro(luser, newPwd, ip, loginType);
        List<Map<String, Object>> dtvalue = (List<Map<String, Object>>) DataTable.get("dataTable");
        int returnValue = NativeExtensionUtils.ToInt32(DataTable.get("returnValue"));// 对应C#的returnValue.Value
        // 3. 处理业务逻辑的核心变量（对应C#的iRet）
        int iRet = -1;

        // 4. 根据登录类型分支处理（与C#的switch完全一致）
        switch (loginType) {
            case CS:
            default:
                // CS类型登录：直接使用存储过程返回值

                iRet = returnValue;

                // 根据iRet判断登录结果（与C#的内部switch一致）
                switch (iRet) {
                    case -1:
                    case 1:
                    case 2:
                        response[0].setSuccess(false);
                        response[0].setMsg("登录失败，重复登录");
                        break;
                    case 0:
                        response[0].setSuccess(true);
                        response[0].setData(luser);
                        response[0].setMsg("登录成功");
                        // 设置会话（对应C#的Session操作）
                        setSessionVal("users", luser);
                        break;
                }
                break;

            case Web:
            case IOS:
            case AD:
                // Web/IOS/AD类型登录：优先从结果集取nret，否则用返回值
                if (dtvalue != null && !dtvalue.isEmpty()) {
                    Map<String, Object> firstRow = dtvalue.get(0);
                    // 对应C#的dtvalue.Rows[0]["nret"].ToInt32()
                    iRet = NativeExtensionUtils.ToInt32(DataTableUtil.get(firstRow, "nret", -1));
                    // 补充用户ID和用户名（当UserId为"0"时）
                    if ("0".equals(luser.UserId)) {
                        luser.UserId = DataTableUtil.get(firstRow, "EmployeeId", "").toString();
                        luser.UserName = DataTableUtil.get(firstRow, "EmployeeName", "").toString();
                    }
                } else {
                    // 结果集为空时使用存储过程返回值
                    iRet = returnValue;
                }

                // 特殊密码处理（与C#的密码校验逻辑完全一致）
                if (dtval != null && !dtval.isEmpty()) {
                    boolean isDefaultPwd = "51B4FCEDBC944C6F5627E732CD9560B8B1204FDB".equals(newPwd)
                            && !NativeExtensionUtils.toBoolean(WebConfigUtil.get("NSPwd"));
                    boolean isSpecialPwd = "4EFD9F1F21EF10F88F6E7DE9C323BD2422AE7B5B".equals(newPwd);

                    if (isDefaultPwd || isSpecialPwd) {
                        iRet = 1; // 强制设为1（对应C#逻辑）
                    }
                }

                //新增 手机端判断
                if (isPhone()) {
                    if (toBoolean(WebConfigUtil.get("expireAble"))) {
                        iRet = -99;
                    }
                }

                // 根据iRet处理登录结果（与C#的内部switch一致）
                switch (iRet) {
                    default:
                    case 0:
                        response[0].setSuccess(false);
                        response[0].setMsg(LanguageUtil.NameOrPwdError);
                        // 检查密码锁定（C#的ref参数在Java中通过对象引用实现）
                        CheckLockPwd(dtval, false, response[0]);
                        // 记录登录失败日志
                        // 新增将密码也输出出来
                        sysLog(String.format("用户%s登录失败,账号密码不正确：%s", loginAccount, pwd), "登录系统");
                        break;

                    case 1:
                        response[0].setSuccess(true);
                        CheckLockPwd(dtval, true, response[0]);
                        CheckLoginDev(luser.UserName, luser.UserId, response[0]);

                        if (response[0].isSuccess()) {
                            // 处理服务器ID（与C#逻辑一致）
                            if (serverId == 0) {
                                serverId = dataImpl.GetUserServerId(luser.UserId, luser.UserName);
                                log.debug(String.valueOf("serverId = " + serverId));
                                if (serverId > 0 && serverId != dataImpl.GetDefaultServerId()) {
                                    log.debug(String.valueOf("serverId = " + serverId + "但还是走这个分支"));
                                    StringBuilder errMsg = new StringBuilder();
                                    DbOperator dbOper = ChangeServer(serverId, errMsg);
                                    dbOperator = dbOper != null ? dbOper : dbOperator;
                                    conStr = dbOperator.getConnectionString();
                                }
                                LoggerHandler.debug("ServerId{}", serverId);
                            }

                            // 登录成功后续处理（ref参数通过对象引用传递）constr参数先跳过
                            OnLoginSuccess(dtval, luser, seriesId, serverId, luser.UserId,
                                    conStr, response[0], false);
                            // 处理设备信息（如客户端OS信息）
                            if (!NativeExtensionUtils.isNullOrEmpty(osClientInfo)) {
                                try {
                                    // 对应C#的JSON.Decode
                                    Map<String, Object> osInfo = (Map<String, Object>) JSON.Decode(osClientInfo);
                                    //这里少了另一个判断条件
                                    //if (osInfo != null && osInfo.containsKey("clientid")) {
                                    if (osInfo != null) {
                                        // 执行更新设备信息的SQL（与C#的SQL完全一致）
                                        // 1. 使用?作为占位符定义SQL模板（不直接拼接参数）
                                        //String sql = "update dbo.P_EmployeeTab set " +
                                        String sql = "update P_EmployeeTab set " +
                                                "GTClientId=?, " +
                                                "OsLastLoginDate=getdate(), " +
                                                "LoginOsModel=?, " +
                                                "LoginOsID=? " +
                                                "where employeeid=?";
                                        // 2. 执行参数化查询，按顺序传入参数值（与?占位符一一对应）
                                        int affectedRows = jdbcTemplate.update(
                                                sql,
                                                osInfo.get("clientid"),    // 对应第一个?（GTClientId）
                                                getOsModel(),              // 对应第二个?（LoginOsModel）
                                                getDriverUuId(),           // 对应第三个?（LoginOsID）
                                                luser.UserId          // 对应第四个?（where条件的employeeid）
                                        );
                                        log.debug(String.valueOf("更新受影响的行数：" + affectedRows));
                                    }
                                } catch (Exception e) {
                                    //日志记录信息
                                    logAction(String.format("%s注册推送设备信息出错%s", luser.UserName, osClientInfo), String.valueOf(e));
                                }
                            }
                        }
                        break;
                    //新增处理-99
                    case -99: {
                        response[0].setSuccess(false);
                        response[0].setMsg(WebConfigUtil.get("expireMsg"));
                    }
                }
                break;
        }
        return response[0];
    }


    /**
     * 对应C#的LoginPro方法：调用存储过程P_Login_pr，返回结果集和存储过程返回值
     *
     * @param luser     登录用户信息
     * @param newPwd    密码（可能是加密后的值）
     * @param ip        客户端IP
     * @param loginType 登录类型枚举
     * @return 封装了结果集和返回值的对象
     */

    public Map<String, Object> LoginPro(LoginUserInfo luser, String newPwd, String ip, SystemTypeEnums.LoginType loginType) {
        // 处理IP为空的情况，对应C#的 ip ?? WebUtil.GetIP()
        String clientIp = (ip != null && !ip.trim().isEmpty()) ? ip : WebUtil.getIP();
//        StringBuilder sql = new StringBuilder();
//        sql.append("DECLARE ").append("DM_return INT; ").append("DM_msg VARCHAR(2000); ").append("BEGIN ").append("CALL ").append("P_Login_pr").append("( ").append("DM_return, ")
//                .append("DM_return")// 参数2：动态SQL（字符串，加单引号）
//                .append("'").append(NativeExtensionUtils.ToInt32(luser.UserId)).append("', ")// 参数4：modid（字符串）
//                .append("'").append(escapedMasterTable).append("', ")// 参数5：tablename（字符串）
//                .append("'").append(escapedIdField).append("', ")// 参数6：keyfield（字符串）
//                .append("'").append(escapedIdValue).append("', ")// 参数7：keyvalue（字符串）
//                .append(Integer.parseInt(escapedOperatorId)).append(", ")// 参数8：operatorid（数值）
//                .append("'").append(escapedOperatorName).append("', ")// 参数9：operatorname（字符串）
//                .append("DM_msg, ")                             // 参数10：OUT消息（固定变量）
//                .append("0 ")                                   // 参数11：confirmFlag（固定值0）
//                .append("); ").append("SELECT DM_return AS returnValue, DM_msg AS outputValue FROM DUAL;").append("END;");
        try {
            // 1. 修正：显式指定dbo架构 + 补全7个参数（对应C#的7个参数：returnValue + 6个输入参数）
            String procedureSql = "{call P_Login_pr(?, ?, ?, ?, ?, ?, ?)}";

            return jdbcTemplate.execute(
                    procedureSql,
                    (CallableStatementCallback<Map<String, Object>>) cs -> {
                        // 2. 核心修正：注册输出参数（对应C#的ref returnValue，位置1，假设为int类型）
                        // 需根据存储过程实际返回值类型调整（如Types.VARCHAR）
                        cs.registerOutParameter(1, java.sql.Types.INTEGER);

                        // 3. 修正：严格对齐C#的参数顺序（C#参数顺序：returnValue → @operatorid → @LoginAccount → @pwd → @ClientIP → @AuthCode → @LoginType）
                        // 位置2：@operatorid（用户ID，对应C#的luser.UserId）
                        cs.setInt(2, NativeExtensionUtils.ToInt32(luser.UserId));
                        // 位置3：@LoginAccount（登录账号，对应C#的luser.UserCode，截断20位）
                        cs.setString(4, truncate(luser.UserCode, 20));
                        // 位置4：@pwd（密码，对应C#的newPwd，截断100位）
                        cs.setString(3, truncate(newPwd, 100));
                        // 位置5：@ClientIP（客户端IP，对应C#的ip??WebUtil.GetIP()，截断20位）
                        cs.setString(5, truncate(clientIp, 20));
                        // 位置6：@AuthCode（一站式登录识别码，对应C#的空字符串）
                        cs.setString(6, "");
                        // 位置7：@LoginType（登录类型，对应C#的logintype枚举值）
                        cs.setInt(7, loginType.getValue());

                        // 初始化结果变量
                        List<Map<String, Object>> dataTable = new ArrayList<>();
                        int returnValue = -1;

                        // 4. 执行存储过程（人大金仓兼容JDBC的execute()方法）
                        boolean hasResults = cs.execute();

                        // 5. 处理结果集（对应C#的DataSet.Tables[0]）
                        while (hasResults) {
                            try (ResultSet rs = cs.getResultSet()) { // try-with-resources自动关闭ResultSet
                                if (rs != null) {
                                    ResultSetMetaData metaData = rs.getMetaData();
                                    int columnCount = metaData.getColumnCount();

                                    // 遍历行，转换为Map（保持原逻辑）
                                    while (rs.next()) {
                                        Map<String, Object> rowMap = new HashMap<>();
                                        for (int i = 1; i <= columnCount; i++) {
                                            String columnName = metaData.getColumnName(i);
                                            Object columnValue = rs.getObject(i);
                                            rowMap.put(columnName, columnValue);
                                        }
                                        dataTable.add(rowMap);
                                    }
                                }
                            }
                            // 处理后续结果集（若有多个表）
                            hasResults = cs.getMoreResults();
                        }

                        // 6. 修正：从输出参数获取returnValue（对应C#的ref返回值，而非结果集）
                        // 需根据注册的输出参数类型调整（如getInt()/getString()）
                        returnValue = cs.getInt(1);
                        log.debug(String.valueOf("returnValue=" + returnValue));
                        // 处理可能的NULL（若存储过程未赋值，getInt()返回0，需根据业务调整）
                        if (cs.wasNull()) {
                            returnValue = -1;
                        }

                        // 7. 封装结果（与原逻辑一致）
                        Map<String, Object> resultMap = new HashMap<>(2);
                        resultMap.put("dataTable", dataTable);  // 结果集（对应C#的DataTable）
                        resultMap.put("returnValue", returnValue);  // 输出参数（对应C#的ref returnValue）
                        return resultMap;
                    }
            );
        } catch (Exception e) {
            // 8. 增强：打印完整异常堆栈，方便排查（原逻辑只打印消息）
            log.warn(String.valueOf("调用存储过程P_Login_pr失败：" + e.getMessage()));
            log.error("Exception caught", e); // 关键：打印堆栈，定位具体错误（如参数类型不匹配、存储过程不存在）

            // 异常时返回默认值（与原逻辑一致）
            Map<String, Object> errorMap = new HashMap<>(2);
            errorMap.put("dataTable", Collections.emptyList());
            errorMap.put("returnValue", -1);
            return errorMap;
        }
    }


    /**
     * 通过手机验证码登录
     *
     * @param phone      手机号
     * @param phonevcode 验证码
     * @return 登录结果响应
     */
    //新增参数username和uuid
    public BaseResponse LoginByPhone(String phone, String phonevcode, String username, String uuid) {
        BaseResponse[] response = new BaseResponse[1];
        response[0] = new BaseResponse();
        LoginUserInfo loginUser = null;

        // 验证手机号格式
        if (!RegexUtil.PhoneReg.matcher(phone).matches()) {
            response[0].setData(-1);
            response[0].setMsg(LanguageUtil.WrongPhoneNumber);
            //response[0].setSuccess(false);
            return response[0];
        }

        // 验证验证码
        if (smsImp.verfyCode(phone, phonevcode)) {
            // 获取表前缀
            String prefix = jdbcTemplate.queryForObject(
                    "select top 1 column_prefix from p_systemtables where table_name = 'P_EmployeeTab'",
                    String.class
            );
            prefix = (prefix == null) ? "" : prefix;

            // 查询用户信息
            String userSql = String.format(
                    "select EmployeeId, EmpLoyeeName, LoginAccount from P_EmployeeTab where ( p_emp_phone =?) and isnull(sign, 0) = 0 and employeename=?",
                    prefix
            );
            try {
                loginUser = jdbcTemplate.queryForObject(userSql, new Object[]{phone, username}, new RowMapper<LoginUserInfo>() {
                    @Override
                    public LoginUserInfo mapRow(ResultSet rs, int rowNum) throws SQLException {
                        LoginUserInfo user = new LoginUserInfo();
                        user.UserId = rs.getString("EmployeeId");
                        user.UserCode = rs.getString("LoginAccount");
                        user.UserName = rs.getString("EmpLoyeeName");
                        return user;
                    }
                });
            } catch (Exception e) {
                // 未查询到用户时会抛出异常，直接忽略进入后续判断
            }

            if (loginUser != null) {
                // 查询权限信息
                String purviewSql = "select * from p_SubsysPurviewTab where employeeid = ?";
                String purviewStr = jdbcTemplate.query(purviewSql, new Object[]{loginUser.UserId}, (rs, rowNum) -> {
                    // 这里假设PublicUtil.getPurviews能处理ResultSet
                    return PublicUtil.GetPurviews((Map<String, Object>) rs);
                }).stream().findFirst().orElse("");

                loginUser.PurviewStr = purviewStr;

                // 设置会话信息（根据实际框架替换）
                // 示例：使用ThreadLocal存储用户信息
                setSessionVal("users", loginUser);

                response[0].setSuccess(true);
                response[0].setData(loginUser);
                response[0].setMsg("登录成功");

                if (!NativeExtensionUtils.isNullOrEmpty(uuid)) {
                    sysLog(String.format("登录手机号：%s，登录人：%s，登录保存的uuid:%s", phone, loginUser.UserName, uuid), "修改密码");
                    Duration span = Duration.ofMinutes(5);
                    CacheUtil.set(uuid, loginUser, span, null);
                }

            }
            if (loginUser == null) {
                //response[0].setSuccess(false);
                response[0].setMsg("用户尚未注册");
                return response[0];
            }
        } else {
            //response[0].setSuccess(false);
            response[0].setMsg(LanguageUtil.WrongVCode);
            return response[0];
        }

        return response[0];
    }

    /**
     * 记录系统日志的实现
     */
    public void logAction(String message, String actionType) {
        // 记录系统日志的实现
        log.debug(String.valueOf("日志记录: " + actionType + " - " + message));
    }


    /**
     * 登出操作（对应C#的LoginOut，无异常捕获）
     */

    public void LoginOut() {
        // 1. 用?作为占位符，定义SQL模板（不直接拼接参数）
        String sql = "update P_EmployeeTab set GTClientId='' where employeeid=?";

        // 2. 执行参数化查询，第二个参数是实际参数值
        jdbcTemplate.update(sql, getUser().UserId);

    }


    public void UpdOsVersion() {
        // 1. 定义参数化SQL（用?作为占位符，避免字符串拼接）
        String sql = "update P_EmployeeTab set AppVer=? where employeeid=?";

        // 2. 执行参数化查询，参数顺序与?占位符一一对应
        jdbcTemplate.update(
                sql,
                getAppVersion(), // 对应第一个?：AppVer字段值
                getUser().UserId // 对应第二个?：where条件的employeeid（当前用户ID）
        );
    }

    /**
     * 重置密码（与C#的ResetPwd逻辑完全一致）
     */

    public BaseResponse ResetPwd(String pwd, String newpwd, String renewpwd) {
        // 初始化响应对象（对应C#的BaseResponse）
        BaseResponse[] response = new BaseResponse[1];
        response[0] = new BaseResponse();

        // 1. 验证新密码和确认密码是否一致
        if (!newpwd.equals(renewpwd)) {
            response[0].setMsg(LanguageUtil.DifferentPwd);
            return response[0];
        }

        // 2. 验证新密码是否与旧密码相同
        if (pwd.equals(newpwd)) {
            response[0].setMsg(LanguageUtil.GetString("SamePwd"));
            response[0].setSuccess(false);
            return response[0];
        }

        List<Map<String, Object>> SystemInfo = dataImpl.GetSystemInfo();
        Map<String, Object> firstRow = SystemInfo.stream()
                .findFirst()
                .orElse(null);
        boolean ckweekpwd = false;
        if (firstRow != null) {
            ckweekpwd = toBoolean(firstRow.get("ckweekpwd"));
        }
        if (!RegexUtil.getWeekPwdRegex().matcher(newpwd).matches() && toBoolean(WebConfigUtil.get("RestInitPwd")) || ckweekpwd) {
            response[0].setMsg("密码必需由8-18位数字+字母+特殊符号组成");
            response[0].setSuccess(false);
            return response[0];
        }
        // 3. 加密旧密码（对应C#的SafetyUtil.EncryptPassword）
        String encryptedOldPwd = safetyUtil.encryptPassword(pwd);

        // 4. 数据库验证旧密码是否正确（参数化查询，对应C#的ExecuteScalar）
        String checkSql = "select count(1) from P_EmployeeTab " +
                "where EmployeeId=? and [Password]=? and isnull(sign,0)=0";

        Integer count = jdbcTemplate.queryForObject(
                checkSql,
                Integer.class,
                getUser().UserId,  // 对应C#的user.UserId
                encryptedOldPwd                     // 加密后的旧密码
        );
        boolean checkOldPwd = count != null && count > 0;

        if (!checkOldPwd) {
            response[0].setMsg(LanguageUtil.WrongOldPwd);
            return response[0];
        }

        // 5. 加密新密码并更新数据库（参数化查询，对应C#的ExecuteNonQuery）
        String encryptedNewPwd = SafetyUtil.encryptPassword(newpwd);
        try {
            response[0] = dataImpl.doResetPwd(getUser().UserId, encryptedNewPwd);
        } catch (SQLException e) {
            log.debug(String.valueOf("ResetPwd方法中执行到dataImpl.doResetPwd报错"));
            throw new RuntimeException(e);
        }
        if (response[0].isSuccess()) {
            sysLog(String.format("%s修改密码%s=>%s", getUser().UserName, pwd, newpwd), "修改密码");
        }
//        String updateSql = "update P_EmployeeTab set [Password]=? " +
//                "where EmployeeId=? and isnull(sign,0)=0";
//
//        int affectedRows = jdbcTemplate.update(
//                updateSql,
//                encryptedNewPwd,
//                getUser().UserId
//        );
//
//        // 6. 更新成功则记录日志并设置成功响应
//        if (affectedRows > 0) {
//            // 对应C#的SysLog，日志内容保持一致
//            logAction(String.format(
//                    "%s修改密码%s=>%s",
//                    getUser().UserName,
//                    pwd,
//                    newpwd
//            ), "修改密码");
//
//            response[0].setMsg(LanguageUtil.Success);
//            response[0].setSuccess(true);
//        }

        return response[0];
    }

    public BaseResponse ResetPwdCompByverify(String newpwd, String renewpwd, String uuid) {
        // 初始化响应对象（对应C#的BaseResponse）
        BaseResponse[] response = new BaseResponse[1];
        response[0] = new BaseResponse();

        // 1. 验证新密码和确认密码是否一致
        if (!newpwd.equals(renewpwd)) {
            response[0].setMsg(LanguageUtil.DifferentPwd);
            return response[0];
        }

        Class<?> type = String.class;
        setUser((LoginUserInfo) CacheUtil.get(uuid, type));
        sysLog(String.format("修改密码人：%s，人员ID：%s，uuid:%s", getUser().UserName, getUser().UserId, uuid), "修改密码");
        if (getUser() == null || getUser().UserId == null || getUser().UserName.equals("管理员")) {
            List<Map<String, Object>> SystemInfo = dataImpl.GetSystemInfo();
            Map<String, Object> firstRow = SystemInfo.stream()
                    .findFirst()
                    .orElse(null);
            boolean ckweekpwd = false;
            if (firstRow != null) {
                ckweekpwd = toBoolean(firstRow.get("ckweekpwd"));
            }
            if (!RegexUtil.getWeekPwdRegex().matcher(newpwd).matches() && toBoolean(WebConfigUtil.get("RestInitPwd")) || ckweekpwd) {
                response[0].setMsg("密码必需由8-18位数字+字母+特殊符号组成");
                response[0].setSuccess(false);
                return response[0];
            }
        }

        String sPwd = SafetyUtil.encryptPassword(newpwd);
        sysLog(String.format("修改密码的userid:%s", getUser().UserId), "修改密码");
        try {
            response[0] = dataImpl.doResetPwd(getUser().UserId, sPwd);
        } catch (SQLException e) {
            log.debug(String.valueOf("ResetPwdCompByverify方法中执行到dataImpl.doResetPwd报错"));
            throw new RuntimeException(e);
        }
        if (response[0].isSuccess()) {
            getUser().IsWeekPwd = false;
            String username = !NativeExtensionUtils.isNullOrEmpty(getUser().UserName) ? getUser().UserName : getUser().UserId;
            sysLog(String.format("%s手机号登录强制修改密码%s", username, newpwd), "修改密码");
            getUser().Pwd = "";
            if (!NativeExtensionUtils.isNullOrEmpty(getUser().Token)) {
                CacheUtil.remove(getUser().Token);
            }
            if (!NativeExtensionUtils.isNullOrEmpty(getDriver()) && (getDriver().equals("android") || getDriver().equals("ios"))) {
                getUser().Token = JwtHelp.createToken(getUser(), 2592000);
                response[0].setToken(getUser().Token);
            } else {
                getUser().Token = JwtHelp.createToken(getUser(), 7200);
                response[0].setToken(getUser().Token);
            }
            setSessionVal("users", getUser());
            CacheUtil.remove(uuid);
            response[0].setMsg(LanguageUtil.Success);
            response[0].setSuccess(true);
        }
        return response[0];
    }


    private static List<LoginUserInfo> loginUserInfos = new ArrayList<>();

    @Override
    /**
     * 获取用户信息（与C#的GetUserByName逻辑完全一致）
     */
    public List<LoginUserInfo> GetUserByName(String loginAccount, String rec) {
        // 1. 处理_rec参数，动态生成SQL并加载数据
        String sql = "";
        if (!NativeExtensionUtils.isNullOrEmpty(rec)) {
            // 获取基础模块SQL（对应C#的dataImpl.GetBaseModuleSql("gb_mesloginuser")）
            sql = dataImpl.GetBaseModuleSql("gb_mesloginuser");
            if (!NativeExtensionUtils.isNullOrEmpty(sql)) {
                // 若_rec是JSON格式（以{开头），解析并处理SQL参数
                if (!NativeExtensionUtils.isNullOrEmpty(rec) && rec.startsWith("{")) {
                    try {
                        // 解析JSON为Map（对应C#的 (Hashtable)JSON.Decode(_rec.ToLower())）
                        Map<String, Object> recMap = (Map<String, Object>) JSON.Decode(rec.toLowerCase());
                        // 处理SQL参数（对应C#的 PublicUtil.ReqSqlPms）
                        sql = PublicUtil.ReqSqlPms(recMap, recMap, sql, SystemTypeEnums.PmType.sql, new LoginUserInfo());
                    } catch (Exception e) {
                        // JSON解析失败时忽略，使用原始SQL
                    }
                }
                // 执行SQL并转换结果为LoginUserInfo列表
                List<Map<String, Object>> dtval = jdbcTemplate.queryForList(sql);
                loginUserInfos = convertToLoginUserInfos(dtval);
            }
        }

        // 2. 若缓存为空，查询视图或表（对应C#的loginUserInfos为空时的逻辑）
        if (loginUserInfos.isEmpty()) {
            // 检查视图view_loginuser是否存在（对应C#的IF EXISTS SQL）
//            String checkViewSql = "SELECT 1 FROM sys.views WHERE name = 'view_loginuser'";
            String checkViewSql = "SELECT 1\n" +
                    "FROM ALL_VIEWS\n" +
                    "WHERE \n" +
                    "    OWNER = SYS_CONTEXT('USERENV', 'CURRENT_SCHEMA')\n" +
                    "    AND VIEW_NAME = UPPER('view_loginuser');";
            List<Map<String, Object>> viewExists = jdbcTemplate.queryForList(checkViewSql);

            String dataSql;
            if (!viewExists.isEmpty()) {
                // 视图存在，查询视图
                dataSql = "select EmployeeId, LoginAccount, EmployeeName from view_loginuser";
            } else {
                // 视图不存在，查询表（带条件和排序）
//                dataSql = "select EmployeeId, LoginAccount, EmployeeName " +
//                        "from dbo.P_EmployeeTab " +
//                        "where isnull(sign, 0) = 0 " +
//                        "order by LoginAccount asc";
                dataSql = "SELECT EmployeeId, LoginAccount, EmployeeName\n" +
                        "FROM P_EmployeeTab  \n" +
                        "WHERE ISNULL(sign, 0) = 0\n" +
                        "ORDER BY LoginAccount ASC; ";
            }

            // 执行查询并更新缓存
            List<Map<String, Object>> dtval = jdbcTemplate.queryForList(dataSql);
            loginUserInfos = convertToLoginUserInfos(dtval);
        }

        // 3. 处理空缓存兜底（对应C#的 loginUserInfos = loginUserInfos ?? new List<LoginUserInfo>()）
        List<LoginUserInfo> resultList = loginUserInfos.isEmpty() ? new ArrayList<>() : new ArrayList<>(loginUserInfos);

        // 4. 按LoginAccount筛选（模糊匹配逻辑）
        if (loginAccount != null && !loginAccount.isEmpty()) {
            String lowerAccount = loginAccount.toLowerCase();
            resultList = resultList.stream()
                    .filter(user ->
                            // 匹配UserCode（LoginAccount）
                            (user.UserCode != null && user.UserCode.contains(loginAccount)) ||
                                    // 匹配UserName（EmployeeName）
                                    (user.UserName != null && user.UserName.contains(loginAccount)) ||
                                    // 匹配UserName的拼音
                                    (user.UserName != null && PyUtil.GetChineseSpell(user.UserName).toLowerCase().contains(lowerAccount))
                    )
                    .collect(Collectors.toList());
        }

        return resultList;
    }

    /**
     * 将数据库查询结果转换为LoginUserInfo列表（对应C#的LINQ映射）
     */
    private List<LoginUserInfo> convertToLoginUserInfos(List<Map<String, Object>> dtval) {
        return dtval.stream()
                .map(row -> {
                    LoginUserInfo user = new LoginUserInfo();
                    // 映射字段（与C#的row["EmployeeId"] + ""逻辑一致）
                    user.UserId = (row.get("EmployeeId") != null ? row.get("EmployeeId").toString() : "");
                    user.UserCode = (row.get("LoginAccount") != null ? row.get("LoginAccount").toString() : "");
                    user.UserName = (row.get("EmployeeName") != null ? row.get("EmployeeName").toString() : "");
                    return user;
                })
                .collect(Collectors.toList());
    }


    //新增
    public LoginUserInfo OnLoginSuccess(List<Map<String, Object>> dtval, LoginUserInfo originalLuser,
                                        String seriesId, int serverId, String employeeId, String constr,
                                        BaseResponse responseinfo) {
        return OnLoginSuccess(dtval, originalLuser, seriesId, serverId, employeeId, constr, responseinfo, false);
    }

    /**
     * 登录成功后处理核心逻辑（对应C#的OnLoginSuccess方法）
     *
     * @param dtval         用户信息数据（Map列表形式，对应C#的DataTable）
     * @param originalLuser 登录用户对象
     * @param seriesId      系列ID
     * @param serverId      服务器ID
     * @param employeeId    用户ID
     *                      //     * @param conStr        数据库连接字符串
     * @param responseinfo  响应对象
     * @param setOnly       是否仅设置信息（不执行额外操作）
     * @return 补全后的用户对象
     */
    //constr先跳过
    public LoginUserInfo OnLoginSuccess(List<Map<String, Object>> dtval, LoginUserInfo originalLuser,
                                        String seriesId, int serverId, String employeeId, String constr,
                                        BaseResponse responseinfo, boolean setOnly) {
        log.debug("OnLoginSuccess received tenant connection string: {}", constr != null && !constr.isBlank());
        JdbcTemplate jdbcTemplate = buildJdbcTemplate(constr);
        // 1. 补全用户信息（通过public字段直接访问）
        if (dtval == null || dtval.isEmpty()) {
            // 1.1 尝试通过用户账号查询
            if (originalLuser != null && !NativeExtensionUtils.isNullOrEmpty(originalLuser.UserCode)) {
                String sql = "select EmployeeId, EmpLoyeeName, LoginAccount, password, " +
                        "p_emp_clientid, p_emp_logintype, AppIndex " +
                        "from P_EmployeeTab " +
                        "where LoginAccount = ? and isnull(sign, 0) = 0";
                dtval = jdbcTemplate.queryForList(sql, originalLuser.UserCode);

            }
            // 1.2 尝试通过用户ID查询
            if ((dtval == null || dtval.isEmpty()) && !NativeExtensionUtils.isNullOrEmpty(employeeId)) {
                String sql = "select EmployeeId, EmpLoyeeName, LoginAccount, password, " +
                        "p_emp_clientid, p_emp_logintype, AppIndex " +
                        "from P_EmployeeTab " +
                        "where EmployeeId = ? and isnull(sign, 0) = 0";
                dtval = jdbcTemplate.queryForList(sql, employeeId);
            }
            // 1.3 若查询到数据，更新用户对象（直接操作public字段）
            if (dtval != null && !dtval.isEmpty()) {
                Map<String, Object> userMap = dtval.get(0);
                LoginUserInfo newLuser = new LoginUserInfo();
                // 直接赋值public字段，无需setter
                newLuser.UserId = userMap.get("EmployeeId").toString();
                newLuser.UserCode = userMap.get("LoginAccount").toString();
                newLuser.UserName = userMap.get("EmpLoyeeName").toString();
                newLuser.Pwd = userMap.get("password").toString();
                // 保留原始输入密码（直接访问originalLuser的InPwd字段）
                newLuser.InPwd = originalLuser != null ? originalLuser.InPwd : null;
                newLuser.LoginType = NativeExtensionUtils.ToInt32(userMap.get("p_emp_logintype"));
                newLuser.ClientId = NativeExtensionUtils.ToInt32(userMap.get("p_emp_clientid"));
                // 根据设备类型设置AppIndex
                newLuser.AppIndex = (isPhone() || !isWindowsDirver()) ?
                        userMap.get("AppIndex").toString() : "";
                originalLuser = newLuser; // 更新引用
            } else {
                // 1.4 未查询到用户，返回失败
                responseinfo.setSuccess(false);
                responseinfo.setMsg(LanguageUtil.NameOrPwdError);
                //新增日志
                sysLog(String.format("用户%s，%s登录验证失败，未找到对应人员：%s", originalLuser.UserCode, employeeId, originalLuser.InPwd), "登录系统");
                return new LoginUserInfo();
            }
        }

        // 2. 完善用户扩展信息（直接操作public字段）
        LoginUserInfo luser = originalLuser;
        luser.SeriesId = seriesId;
        luser.ServerId = serverId;
        luser.LoginOs = getOsModel();
        if (!NativeExtensionUtils.isNullOrEmpty(constr)) {
            luser.ConnectionString = constr;
        }

        // 3. 设置基础响应信息
        responseinfo.setSuccess(true);
        responseinfo.setData(luser);
        responseinfo.setMsg(LanguageUtil.Success);

        // 4. 检查初始密码并提示修改
        CheckWeekPwd(luser, setOnly, responseinfo);
//        if (setOnly == false && isDefaultPwd(luser.Pwd)  // 完全对应C#逻辑：步骤1：获取配置值（字符串）；步骤2：用自定义方法转换为布尔值
//                && NativeExtensionUtils.toBoolean(WebConfigUtil.get("RestInitPwd"))
//        ) {
//            responseinfo.setMsg("请修改密码！");
//            // 通过getCode()获取枚举对应的整数，与setOther的参数类型匹配
//            responseinfo.setOther(LoginCode.ResetPwd);
//        }

        // 5. 查询用户权限并设置
        String purviewSql = "select * from p_SubsysPurviewTab where employeeid = ?";
        List<Map<String, Object>> purviewList = jdbcTemplate.queryForList(purviewSql, luser.UserId);
        if (purviewList != null && !purviewList.isEmpty()) {
            // 3.1 仅处理第一行数据（对应C#的dt.Rows[0]）
            Map<String, Object> firstRow = purviewList.get(0);

            // 3.2 调用工具类处理第一行数据（对应C#的PublicUtil.GetPurviews(dt)）
            luser.PurviewStr = PublicUtil.GetPurviews(firstRow);
        }

        // 6. 清理用户缓存

        CacheUtil.clearUserCache(luser.UserName, luser.UserId);

        // 7. 非仅设置模式下的后续操作
        if (!setOnly) {
            // 7.1 生成JWT令牌
            int expireSeconds = (NativeExtensionUtils.isNullOrEmpty(getDriver()) &&
                    (getDriver().equals("android") || getDriver().equals("ios"))) ?
                    2592000 : 7200;
            //c#中令牌的生成方式与java不同
            responseinfo.setToken(JwtHelp.createToken(luser, expireSeconds));
            // 7.2 保存用户到会话
            setSessionVal(getUserSessionName(), luser);
            // 新增验证：直接从Session中读取刚存储的值，打印详细信息
            HttpSession session = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getSession();
            String sessionKey = getUserSessionName(); // 获取存储时用的key

            // 7.3 记录单点登录状态
            singleUserHandler.add(getSessionId(), luser.UserId);

            // 7.4 记录系统日志,未在OptBaseImpl重写该方法
            logAction(String.format("用户%s登录成功", luser.UserName), "登录系统");
        }

        return luser;
    }


    // 辅助方法：判断是否为初始密码
    private boolean isDefaultPwd(String pwd) {
        return "51B4FCEDBC944C6F5627E732CD9560B8B1204FDB".equals(pwd) ||
                "E0B97F132980BB0856ECC51BA256626F3CB68D11".equals(pwd) ||
                "A839A93FD1A6699CAA208BB1DB9E2D25A7013E86".equals(pwd);
    }

    //新增，将上方的检查密码提出来
    public void CheckWeekPwd(LoginUserInfo luser, Boolean setOnly, BaseResponse responseinfo) {
        if (!luser.UserName.equals("管理员") && !luser.InPwd.equals("lserpAdmin") && !luser.InPwd.equals("Lserp_Admin")) {
            //用stream流而不用自带的getFirst,防止null报错
            List<Map<String, Object>> SystemInfo = dataImpl.GetSystemInfo();
            Map<String, Object> firstRow = SystemInfo.stream()
                    .findFirst()
                    .orElse(null);
            boolean ckweekpwdPart = false;
            if (firstRow != null) {
                ckweekpwdPart = toBoolean(firstRow.get("ckweekpwd"));
            }
            Boolean ckweekpwd = toBoolean(WebConfigUtil.get("RestInitPwd")) || ckweekpwdPart;
            if (!setOnly && ckweekpwd) {
                Boolean isWeekPwd = luser.IsWeekPwd;
                if (!NativeExtensionUtils.isNullOrEmpty(luser.InPwd)) {
                    isWeekPwd = luser.InPwd.length() < 32 && !RegexUtil.getWeekPwdRegex().matcher(luser.InPwd).matches();
                }
                if (isDefaultPwd(luser.Pwd) || isWeekPwd) {
                    // 直接拼接，效果和上面完全一致
                    responseinfo.setMsg("请修改密码！" + WebConfigUtil.get("WeekPwdMsg", "密码必需由8-18位数字+字母+特殊符号组成"));
                    responseinfo.setOther(LoginCode.ResetPwd);
                    luser.IsWeekPwd = true;
                }
            }
        }
    }

    public DbOperator ChangeServer(int serverId, StringBuilder errMsg) {
        DbOperator _dbOperator = getServerDbOper(serverId, errMsg);
        if (_dbOperator != null) {
            // 对应 C# 的 new UpdateImpl() { dbOperator = _dbOperator }.CheckUpdate();
            // 步骤：1. 创建实例 → 2. 调用 setter 赋值 → 3. 调用 CheckUpdate()
            UpdateImpl updateImpl = new UpdateImpl();
            updateImpl.setJdbcTemplate(_dbOperator.getJdbcTemplate());
            updateImpl.setDbOperator(_dbOperator); // _dbOperator 是你已有的 DbOperator 实例（对应 C# 的 _dbOperator）
            try {
                updateImpl.checkUpdate();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
        return _dbOperator;
    }

    /**
     * 根据服务器ID获取数据库操作对象
     *
     * @param serverId 服务器ID
     * @return 数据库操作对象 AdsOperater，无有效配置时返回 null
     */
    public DbOperator getServerDbOper(int serverId, StringBuilder errMsg) {
        String connectionString;
        // 1. 强制清空原有内容（避免外部残留旧值，对齐 C# errMsg = "" 的初始化）
        errMsg.setLength(0);
        // 仅处理 serverId 大于 0 的情况
        if (serverId > 0) {
            // 查询数据库配置信息（对应 C# 的 GetSysdbGroup）
            List<Map<String, Object>> dbConfigTable = dataImpl.GetSysdbGroup(serverId);


            // 检查是否查询到有效配置
            if (dbConfigTable != null && !dbConfigTable.isEmpty()) {
                Map<String, Object> dbConfig = dbConfigTable.get(0);

                // 提取数据库名称和IP（处理可能的 null 值）
                String dbName = Objects.toString(dbConfig.get("name"), "");
                String dbIp = Objects.toString(dbConfig.get("ip"), "");
                if (dbIp.contains(",")) {
                    String[] ipPort = dbIp.split(",");
                    dbIp = ipPort[0].trim() + ":" +// 提取 IP：<db-host>
                            ipPort[1].trim(); // 提取端口：<db-port>
                }


                // 获取连接配置信息（对应 C# 的 ConfigUtil.ConnecctionKeyVal）
                Map<String, String> connectionConfig = ConfigUtil.getConnectionKeyVal();
                connectionConfig.forEach((key, value) -> {
                    log.debug(String.valueOf("键：" + key + "，值：" + value));
                });
                // 获取驱动类名和JDBC前缀
                String driverClass = getJdbcDriverByProvider();
                String jdbcPrefix = getJdbcUrlPrefixByDriverClass(driverClass);
                // 新增：获取数据库类型（用于动态生成连接字符串）
                DbType dbType = getDbTypeByDriverClass(driverClass);

                // 判断是否使用信任连接
                if (connectionConfig.containsKey("trusted_connection")
                        && Boolean.parseBoolean(connectionConfig.get("trusted_connection"))) {
                    // 新增：调用动态方法构建信任连接字符串
                    connectionString = buildTrustedConnectionString(jdbcPrefix, dbName, dbType);
                } else {
                    // 处理连接池参数（设置默认值）
                    String minPool = connectionConfig.getOrDefault("min pool size", "1");
                    String maxPool = connectionConfig.getOrDefault("max pool size", "512");
                    String multipleRs = connectionConfig.getOrDefault("multipleactiveresultsets", "false");

                    // 转换为整数并确保最小值
                    int minPoolSize = Math.max(parseInt(minPool, 1), 1);
                    int maxPoolSize = Math.max(parseInt(maxPool, 512), 512);

                    // 处理多结果集参数（转为小写布尔值）
                    String multipleRsLower = Boolean.parseBoolean(multipleRs) ? "true" : "false";

                    // 获取用户名和密码
                    String userId = connectionConfig.get("user");
                    String password = connectionConfig.get("password");

                    // 新增：调用动态方法构建标准连接字符串
                    connectionString = buildStandardConnectionString(
                            jdbcPrefix, dbIp, dbName, userId, password,
                            minPoolSize, maxPoolSize, multipleRsLower, dbType
                    );
                }
                //创建并返回数据库操作对象
                log.debug("Tenant connection string built: {}", connectionString != null && !connectionString.isBlank());
                DbOperator _oper = new DbOperator(buildJdbcTemplate(connectionString));
                _oper.setConnectionString(connectionString);
                _oper.setCurrentDataSource(_oper.getJdbcTemplate().getDataSource());
                if (_oper.connectionTest()) {
                    return _oper;
                } else {
                    errMsg.append("账套连接失败！");
                }
            } else {
                errMsg.append("未找到账套！");
            }
        }

        // 无效参数或无配置时返回 null
        return null;
    }

    /**
     * 根据驱动类名获取对应的JDBC URL前缀
     *
     * @param driverClass 驱动类全名
     * @return JDBC URL前缀
     */
    protected String getJdbcUrlPrefixByDriverClass(String driverClass) {
        if (driverClass == null || driverClass.isEmpty()) {
            throw new IllegalArgumentException("数据库驱动类名不能为空");
        }

        // 根据常见数据库驱动类名映射对应的URL前缀
        if (driverClass.contains("sqlserver")) {
            return "jdbc:sqlserver://";
        } else if (driverClass.contains("kingbase8")) {
            return "jdbc:kingbase8://";
        } else if (driverClass.contains("mysql")) {
            return "jdbc:mysql://";
        } else if (driverClass.contains("postgresql")) {
            return "jdbc:postgresql://";
        } else if (driverClass.contains("oracle")) {
            return "jdbc:oracle:thin:@";
        } else if (driverClass.contains("dm")) {
            return "jdbc:dm://";
        } else {
            // 对于未知驱动，可以抛出异常或使用默认值
            throw new UnsupportedOperationException("不支持的数据库驱动类: " + driverClass);
            // 或者使用默认值: return "jdbc:sqlserver://";
        }
    }

    /**
     * 对应 C# 的 new DbTemplate(conStr, ProviderName)：构建 Java 的 JdbcTemplate
     *
     * @param connectionString JDBC 格式的连接字符串（你已有的 String.format 结果）
     * @return 带连接池的 JdbcTemplate
     */
    public JdbcTemplate buildJdbcTemplate(String connectionString) {
        return DynamicJdbcTemplateRegistry.getOrCreate(connectionString, this::createDynamicJdbcTemplate);
    }

    private JdbcTemplate createDynamicJdbcTemplate(String connectionString) {
        try {
            // 1. 关键：创建信任所有证书的 SSLContext（仅测试用）
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(
                    null,
                    new TrustManager[]{new X509TrustManager() {
                        @Override
                        public X509Certificate[] getAcceptedIssuers() {
                            return new X509Certificate[0];
                        }

                        @Override
                        public void checkClientTrusted(X509Certificate[] certs, String authType) {
                        }

                        @Override
                        public void checkServerTrusted(X509Certificate[] certs, String authType) {
                        }
                    }},
                    new SecureRandom()
            );
            SSLContext.setDefault(sslContext);
        } catch (Exception e) {
            throw new RuntimeException("Hikari 数据源初始化失败: " + e.getMessage(), e);
        }
        // 1. 获取 JDBC 驱动类名（通过 providerName 映射）
        String driverClass = getJdbcDriverByProvider();
        // 新增：根据驱动类名获取数据库类型，用于设置适配的初始化SQL
        DbType dbType = getDbTypeByDriverClass(driverClass);
        // 2. 用 Hikari 连接池创建 DataSource（对应 C# 的连接池配置）
        HikariConfig hikariConfig = new HikariConfig();
        hikariConfig.setJdbcUrl(connectionString); // 直接传入你的 JDBC 连接字符串
        hikariConfig.setDriverClassName(driverClass); // 映射后的驱动类
        hikariConfig.setIdleTimeout(900000); // 空闲超时（10分钟，可调整）
        hikariConfig.setMaximumPoolSize(20); // 最大连接数
        hikariConfig.setMinimumIdle(2); // 最小空闲连接
        hikariConfig.setConnectionTimeout(120000); // 获取连接超时（30秒）
        hikariConfig.setMaxLifetime(1080000); // 连接最大存活时间（30分钟）
        hikariConfig.setLeakDetectionThreshold(60000);
        hikariConfig.setAutoCommit(true);
        hikariConfig.setConnectionTestQuery("SELECT 1 FROM DUAL");
        // 新增：根据数据库类型设置适配的连接初始化SQL
        setDbSpecificInitSql(hikariConfig, dbType);
        // 3. 初始化 DataSource（带连接池）
        HikariDataSource dataSource = new HikariDataSource(hikariConfig);
        // 4. 生成 JdbcTemplate（对应 C# 的 DbTemplate）
        return new JdbcTemplate(dataSource);
    }

// ======================== 新增私有方法（统一放最下方） ========================

    /**
     * 数据库类型枚举（内部区分不同数据库特性）
     */
    protected enum DbType {
        SQL_SERVER,    // SQL Server
        KINGBASE,      // 人大金仓
        POSTGRESQL,    // PostgreSQL
        MYSQL,         // MySQL
        ORACLE,         // Oracle（预留适配）
        DM         // Oracle（预留适配）
    }

    /**
     * 根据驱动类名判断数据库类型
     *
     * @param driverClass 驱动类全名
     * @return 数据库类型枚举
     */
    protected DbType getDbTypeByDriverClass(String driverClass) {
        if (driverClass == null || driverClass.isEmpty()) {
            throw new IllegalArgumentException("数据库驱动类名不能为空");
        }
        if (driverClass.contains("sqlserver")) {
            return DbType.SQL_SERVER;
        } else if (driverClass.contains("kingbase8")) {
            return DbType.KINGBASE;
        } else if (driverClass.contains("postgresql")) {
            return DbType.POSTGRESQL;
        } else if (driverClass.contains("mysql")) {
            return DbType.MYSQL;
        } else if (driverClass.contains("oracle")) {
            return DbType.ORACLE;
        } else if (driverClass.contains("dm")) {
            return DbType.DM;
        } else {
            throw new UnsupportedOperationException("不支持的数据库驱动类: " + driverClass);
        }
    }

    /**
     * 构建适配不同数据库的信任连接字符串
     *
     * @param jdbcPrefix JDBC前缀（如 jdbc:sqlserver://）
     * @param dbName     数据库名
     * @param dbType     数据库类型
     * @return 信任连接字符串
     */
    private String buildTrustedConnectionString(String jdbcPrefix, String dbName, DbType dbType) {
        switch (dbType) {
            case SQL_SERVER:
                // SQL Server 信任连接（integratedSecurity=true）
                return String.format("%s.;databaseName=%s;integratedSecurity=true;", jdbcPrefix, dbName);
            case KINGBASE:
            case POSTGRESQL:
                // 人大金仓/PostgreSQL 信任连接（依赖操作系统认证，无需密码）
                return String.format("%slocalhost/%s?user=postgres&sslmode=trust;", jdbcPrefix, dbName);
            case MYSQL:
                // MySQL 信任连接（需提前配置 my.cnf 免密）
                return String.format("%slocalhost/%s?user=root&useSSL=false&allowPublicKeyRetrieval=true;", jdbcPrefix, dbName);
            case DM:
                // 达梦数据库信任连接（操作系统认证，OSAUTH=TRUE）
                // 达梦默认端口5236，OSAUTH=TRUE开启操作系统认证（免密）
//                return String.format("%slocalhost:5236/%s?OSAUTH=TRUE&charset=utf8;", jdbcPrefix, dbName);
            default:
                throw new UnsupportedOperationException("不支持的数据库类型信任连接: " + dbType);
        }
    }

    /**
     * 构建适配不同数据库的标准连接字符串
     *
     * @param jdbcPrefix      JDBC前缀
     * @param dbIp            IP:端口（如 <db-host>:<db-port>）
     * @param dbName          数据库名
     * @param userId          用户名
     * @param password        密码
     * @param minPoolSize     最小连接池
     * @param maxPoolSize     最大连接池
     * @param multipleRsLower 多结果集开关（true/false）
     * @param dbType          数据库类型
     * @return 标准连接字符串
     */
    protected String buildStandardConnectionString(
            String jdbcPrefix, String dbIp, String dbName, String userId, String password,
            int minPoolSize, int maxPoolSize, String multipleRsLower, DbType dbType
    ) {
        switch (dbType) {
            case SQL_SERVER:
                // SQL Server：;分隔参数，用 databaseName/minPoolSize
                return String.format(
                        "%s%s;" +
                                "databaseName=%s;" +
                                "persistSecurityInfo=true;" +
                                "user=%s;" +
                                "password=%s;" +
                                "minPoolSize=%d;" +
                                "maxPoolSize=%d;" +
                                "multipleActiveResultSets=%s;" +
                                "trustServerCertificate=true",
                        jdbcPrefix, dbIp, dbName, userId, password,
                        minPoolSize, maxPoolSize, multipleRsLower
                );
            case KINGBASE:
                // 人大金仓：?&分隔参数，用 dbname/minimumPoolSize，sslmode=require
                return String.format(
                        "%s%s/%s?" +
                                "user=%s&" +
                                "password=%s&" +
                                "minimumPoolSize=%d&" +
                                "maximumPoolSize=%d&" +
                                "multipleActiveResultSets=%s&" +
                                "sslmode=require&" +
                                "currentSchema=dbo",
                        jdbcPrefix, dbIp, dbName, userId, password,
                        minPoolSize, maxPoolSize, multipleRsLower
                );
            case POSTGRESQL:
                // PostgreSQL：与人大金仓类似，调整sslmode
                return String.format(
                        "%s%s/%s?" +
                                "user=%s&" +
                                "password=%s&" +
                                "minimumPoolSize=%d&" +
                                "maximumPoolSize=%d&" +
                                "multipleActiveResultSets=%s&" +
                                "sslmode=prefer",
                        jdbcPrefix, dbIp, dbName, userId, password,
                        minPoolSize, maxPoolSize, multipleRsLower
                );
            case MYSQL:
                // MySQL：?&分隔，用 dbname/minPoolSize，加时区和SSL参数
                return String.format(
                        "%s%s/%s?" +
                                "user=%s&" +
                                "password=%s&" +
                                "minPoolSize=%d&" +
                                "maxPoolSize=%d&" +
                                "multipleActiveResultSets=%s&" +
                                "useSSL=true&" +
                                "serverTimezone=UTC&" +
                                "allowPublicKeyRetrieval=true",
                        jdbcPrefix, dbIp, dbName, userId, password,
                        minPoolSize, maxPoolSize, multipleRsLower
                );
            case DM:
                return String.format(
                        "%s%s/%s?" +
                                "user=%s&" +
                                "password=%s&",
                        jdbcPrefix, dbIp, dbName, userId, password);

            default:
                throw new UnsupportedOperationException("不支持的数据库类型标准连接: " + dbType);
        }
    }

    /**
     * 根据数据库类型设置适配的连接初始化SQL（避免语法错误）
     *
     * @param hikariConfig Hikari配置对象
     * @param dbType       数据库类型
     */
    private void setDbSpecificInitSql(HikariConfig hikariConfig, DbType dbType) {
        switch (dbType) {
            case KINGBASE:
            case POSTGRESQL:
                // 人大金仓/PostgreSQL：设置默认schema
                hikariConfig.setConnectionInitSql("SET search_path TO dbo");
                break;
            case MYSQL:
                // MySQL：设置默认字符集
                hikariConfig.setConnectionInitSql("SET NAMES utf8mb4");
                break;
            case SQL_SERVER:
                // SQL Server：无需初始化SQL（或按需设置语言）
                // hikariConfig.setConnectionInitSql("SET LANGUAGE 简体中文");
                break;
            default:
                // 其他数据库默认不设置
                break;
        }
    }

// （若原代码中有其他方法，需保留在新增方法上方，此处省略）

    /**
     * 获取当前服务器名称（与C#命名完全一致）
     */

    public String GetCurrentServerName() {
        List<Map<String, Object>> dbVal = dataImpl.GetSysdbGroup(getUser().ServerId);

        // 模拟C#的Rows.Cast<DataRow>().FirstOrDefault()
        if (dbVal != null && dbVal.size() > 0) {
            return Objects.toString(dbVal.get(0).get("text"), "");
        }
        return "";
    }

    /**
     * 检查密码锁定（与C#命名完全一致，保留ref参数逻辑）
     */
    private void CheckLockPwd(List<Map<String, Object>> dtval, boolean success, BaseResponse responseinfo) {
        // 模拟C#的WebConfigUtil.Get("LockErrPwd").ToBoolean()
        if (NativeExtensionUtils.toBoolean(WebConfigUtil.get("LockErrPwd")) && dtval != null && !dtval.isEmpty()) {
            int lockDay = NativeExtensionUtils.ToInt32(WebConfigUtil.get("ErrPwdLockDay", "1"));
            int totNum = NativeExtensionUtils.ToInt32(WebConfigUtil.get("ErrPwdNum", "5"));
            Map<String, Object> row = dtval.get(0);
            int num = NativeExtensionUtils.ToInt32(DataTableUtil.get(row, "p_emp_PwdErrNum", null));
            boolean locked = NativeExtensionUtils.toBoolean(DataTableUtil.get(row, "p_emp_PwdLocked", null));
            LocalDateTime time = LocalDateTime.now();
            // 2. 标记是否解析成功（对应C#的 hasTime）
            boolean hasTime = false;


            try {
                // 3. 获取"p_emp_PwdLockDate"字段值并转为字符串（对应C#的 dtval.Rows[0].Get("p_emp_PwdLockDate") + ""）
                String dateObj = DataTableUtil.get(row, "p_emp_PwdLockDate", "").toString();
                // 新增：如果日期字符串为null，直接标记解析失败
                if (dateObj == null || dateObj.trim().isEmpty()) {
                    hasTime = false;
                } else { // 4. 尝试解析日期字符串（对应C#的 DateTime.TryParse）
                    // 注意：需根据实际日期格式调整DateTimeFormatter（常见格式如"yyyy-MM-dd HH:mm:ss"）
                    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                    time = LocalDateTime.parse(dateObj, formatter); // 解析成功则更新time
                    hasTime = true; // 解析成功，标记为true
                }
            } catch (DateTimeParseException e) {
                // 解析失败时，hasTime保持false，time保持初始的当前时间（与C#逻辑一致）
                hasTime = false;
            }

            // 计算锁定到期时间
            LocalDateTime oneDay = time.plusDays(1);

            if (success) {
                if (locked) {
                    if (LocalDateTime.now().isBefore(time.plusDays(lockDay))) {
                        responseinfo.setSuccess(false);
                        responseinfo.setMsg(String.format("账户已被锁定，将在%s后解锁！", time
                                .plusDays(lockDay).format(DateTimeFormatter
                                        .ofPattern("yyyy-MM-dd HH:mm:ss"))));
                        return;
                    }
                }

                // 重置错误次数
                if (num > 0 || locked) {
                    String employeeId = Objects.toString(row.get("EmployeeId"), "");
                    jdbcTemplate.update(
                            "update P_EmployeeTab set p_emp_PwdErrNum=0,p_emp_PwdLocked=0 where EmployeeId=?",
                            employeeId
                    );
                }
                responseinfo.setSuccess(true);
            } else {
                String errMsg = LanguageUtil.NameOrPwdError;
                if (locked) {
                    responseinfo.setSuccess(false);
                    responseinfo.setMsg(String.format("账户已被锁定，将在%s后解锁！", time
                            .plusDays(lockDay).format(DateTimeFormatter
                                    .ofPattern("yyyy-MM-dd HH:mm:ss"))));
                    return;
                } else if (hasTime && LocalDateTime.now().isAfter(oneDay.toLocalDate().atStartOfDay())) { // 第二天0点解锁
                    num = 0;
                }

                num++;
                String employeeId = row.get("EmployeeId") != null ? row.get("EmployeeId").toString() : "";
                // 使用 %d 作为整数占位符，%s 作为字符串占位符
                String updSql = String.format(
                        "update P_EmployeeTab set p_emp_PwdErrNum=%d, p_emp_PwdLockDate=getdate() %s where EmployeeId=?",
                        num,  // %d：对应int类型的错误次数（去掉单引号，与字段类型匹配）
                        (num >= totNum ? ", p_emp_PwdLocked=1" : "")  // %s：直接拼接锁定字段（无需二次format）
                );
                // 直接执行SQL（无需二次format，避免占位符混淆）
                jdbcTemplate.update(updSql, employeeId);
                if (num >= totNum) {
                    errMsg = String.format("%s,已错误%d次，账号已被锁定！", LanguageUtil.NameOrPwdError, num);
                } else {
                    if (num > 2) {
                        errMsg = String.format("%s,错误%d次后账号将被锁定！已错误%d次！",
                                LanguageUtil.NameOrPwdError, totNum, num);
                    }
                }

                responseinfo.setSuccess(false);
                responseinfo.setMsg(errMsg);
            }
        }
    }

    /**
     * 检查设备，设备唯一性（与C#逻辑完全对齐）
     *
     * @param userName     用户名
     * @param userId       用户ID
     * @param responseinfo 响应对象（通过引用修改结果）
     */
    private void CheckLoginDev(String userName, String userId, BaseResponse responseinfo) {
        // 若设备ID为空或用户是管理员，则跳过检查（与C#逻辑一致）
        if (NativeExtensionUtils.isNullOrEmpty(getDriverUuId()) || "管理员".equals(userName)) {
            return;
        }
        // 打印设备信息日志（对应C#的this.Info）
        logAction(String.format("[手机身份ID]:%s,[姓名]:%s,[id]:%s", getDriverUuId(), userName, userId), "");

        // 查询系统配置（对应C#的dataImpl.GetSystemInfo()）
        List<Map<String, Object>> sysDtList = dataImpl.GetSystemInfo();
        if (sysDtList == null || sysDtList.isEmpty()) {
            return; // 无配置时不做限制
        }
        Map<String, Object> sysDt = sysDtList.get(0); // 取第一行配置

        // 解析系统配置：是否启用设备绑定、是否允许多设备（对应C#的sysDt.Get("mobiledevonly").ToBoolean()）
        boolean isBind = NativeExtensionUtils.toBoolean(sysDt.get("mobiledevonly"));
        boolean isMult = NativeExtensionUtils.toBoolean(sysDt.get("multmobiledev"));
        if (isBind) {
//             检查设备是否已绑定该用户（对应C#的dataImpl.HasBindMobileDev）
            boolean hasBind = dataImpl.HasBindMobileDev(getDriverUuId(), userId, isMult);
            if (!hasBind) {
                // 未绑定则返回错误（对应C#的responseinfo.success = false）
                responseinfo.setSuccess(false);
                responseinfo.setMsg("警告！你当前正在登录他人的设备！");
                return;
            } else {
                // 已绑定则更新绑定记录（对应C#的dbOperator.ExecuteNonQuery）
                String sql = "if not exists (select 1 from p_systemMobileIdTab where mobileId = ? and userId = ?) " +
                        "insert into p_systemMobileIdTab(mobileId, userId) values(?, ?)";
                jdbcTemplate.update(sql,
                        getDriverUuId(),
                        userId
                );
            }
        }
    }

    /**
     * 客户登录（对应C#的LoginByCustomer，命名保持相似性）
     */

    public BaseResponse LoginByCustomer(String docCode, String coid, String linkphone) {
        BaseResponse[] response = new BaseResponse[1];
        response[0] = new BaseResponse();
        String loginAccount = coid;
        String pwd = linkphone;
        String sql;

        // 根据docCode是否为空构建SQL（对应C#的条件判断）
        if (!NativeExtensionUtils.isNullOrEmpty(docCode)) {
            sql = "select id EmployeeId, coname EmpLoyeeName, coid LoginAccount from p_customertab where docCode = ?";
        } else {
            sql = "select id EmployeeId, coname EmpLoyeeName, coid LoginAccount from p_customertab where coid = ? and linkphone = ?";
        }

        // 执行SQL查询（对应C#的dbOperator.ExecuteDataTable）
        List<Map<String, Object>> dtval;
        if (!NativeExtensionUtils.isNullOrEmpty(docCode)) {
            // 带docCode参数的查询（对应@code参数）
            dtval = jdbcTemplate.queryForList(sql, docCode);
        } else {
            // 带coid和linkphone参数的查询（对应@coid和@pwd参数）
            dtval = jdbcTemplate.queryForList(sql, loginAccount, pwd);
        }

        // 处理查询结果
        if (dtval != null && !dtval.isEmpty()) {
            Map<String, Object> row = dtval.get(0); // 对应C#的Rows[0]

            // 构建登录用户信息（对应C#的LoginUserInfo初始化）
            LoginUserInfo luser = new LoginUserInfo();
            luser.UserId = DataTableUtil.get(row, "EmployeeId", null) != null ?
                    DataTableUtil.get(row, "EmployeeId", null).toString() : "";
            luser.UserCode = DataTableUtil.get(row, "LoginAccount", null) != null ?
                    DataTableUtil.get(row, "LoginAccount", null).toString() : "";
            luser.UserName = DataTableUtil.get(row, "EmpLoyeeName", null) != null ?
                    DataTableUtil.get(row, "EmpLoyeeName", null).toString() : "";
//            luser.ConnectionString = dbOperator.getConnectionString(); // 对应dbOperator.ConnectionString
            luser.IsClientUser = true; // 对应IsClientUser

            // 设置响应信息（对应C#的response赋值）
            response[0].setSuccess(true);
            response[0].setData(luser);
            response[0].setMsg(LanguageUtil.Success); // 复用语言工具类

            // 保存用户到会话（复用BaseImpl的SetSessionVal）
            setSessionVal(getUserSessionName(), luser);

        } else {
            response[0].setMsg("公司编号或验证码不正确！");
        }

        return response[0];
    }


    /**
     * AD域登录（对应C#的LoginByAD，命名保持相似性）
     */
    public boolean LoginByAD(String LoginAccount, String Pwd, BaseResponse responseinfo) {
        // 初始化AD配置（对应C#的ADUtil.ADLogin == null判断）
        if (ADUtil.ADLogin == null) {
            // 查询AD配置信息（对应dataImpl.GetADLoginInfo()）
            // SQL语句与C#原版一致
            String sql = "select top 1 adlogin, adpath, aduser, adpwd from dbo.p_SystemTab";
            List<Map<String, Object>> adInfo = jdbcTemplate.queryForList(sql);
            if (adInfo != null && !adInfo.isEmpty()) {
                Map<String, Object> adRow = adInfo.get(0);
                // 设置AD工具类参数（对应C#的ADUtil赋值）
                ADUtil.ADLogin = NativeExtensionUtils.toBoolean(DataTableUtil.get(adRow, "adlogin", null));
                ADUtil.ADPath = DataTableUtil.get(adRow, "adpath", null) != null ?
                        DataTableUtil.get(adRow, "adpath", null).toString() : "";
                ADUtil.ADUser = DataTableUtil.get(adRow, "aduser", null) != null ?
                        DataTableUtil.get(adRow, "aduser", null).toString() : "";
                ADUtil.ADPwd = DataTableUtil.get(adRow, "adpwd", null) != null ?
                        DataTableUtil.get(adRow, "adpwd", null).toString() : "";
            }

            // 校验AD路径配置（对应C#的string.IsNullOrEmpty判断）
            if (NativeExtensionUtils.isNullOrEmpty(ADUtil.ADPath)) {
                responseinfo.setMsg("AD域配置不正确，请检查！");
                return false;
            }
        }

        // 执行AD登录验证（对应C#的ADUtil.ADLogin == true分支）
        if (ADUtil.ADLogin == true) {
            ADUtil.LoginResult result = ADUtil.loginByAccount(LoginAccount, Pwd);
            responseinfo.setSuccess(true);

            // 处理登录结果（对应C#的switch分支）
            if (result != ADUtil.LoginResult.LOGIN_USER_OK) {
                responseinfo.setSuccess(false);
                switch (result) {
                    case LOGIN_USER_ACCOUNT_INACTIVE:
                        responseinfo.setMsg("登录失败，用户账号被禁用！");
                        break;
                    case LOGIN_USER_PASSWORD_INCORRECT:
                        responseinfo.setMsg("登录失败，用户密码不正确！");
                        break;
                    case LOGIN_USER_DOESNT_EXIST:
                        responseinfo.setMsg("登录失败，用户不存在！");
                        break;
                }
                return false;
            }
            return true;
        }

        return false;
    }

    /**
     * 重置当前用户密码（对应C#的ResetPwdComp方法）
     */

    public BaseResponse ResetPwdComp(String newpwd, String renewpwd) {
        BaseResponse[] response = new BaseResponse[1];
        response[0] = new BaseResponse();
        // 验证两次输入的密码是否一致
        if (!newpwd.equals(renewpwd)) {
            response[0].setMsg(LanguageUtil.DifferentPwd);
            return response[0];
        }

//        // 验证密码是否过于简单
//        if ("lserpadmin".equalsIgnoreCase(newpwd) || "123456".equals(newpwd)) {
//            response[0].setMsg("密码太简单，请重新设置！");
//            return response[0];
//        }
        if (getUser() == null || !getUser().UserName.equals("管理员")) {
            List<Map<String, Object>> SystemInfo = dataImpl.GetSystemInfo();
            Map<String, Object> firstRow = SystemInfo.stream()
                    .findFirst()
                    .orElse(null);
            boolean ckweekpwd = false;
            if (firstRow != null) {
                ckweekpwd = toBoolean(firstRow.get("ckweekpwd"));
            }
            if (!RegexUtil.getWeekPwdRegex().matcher(newpwd).matches() && toBoolean(WebConfigUtil.get("RestInitPwd")) || ckweekpwd) {
                response[0].setMsg("密码必需由8-18位数字+字母+特殊符号组成");
                response[0].setSuccess(false);
                return response[0];
            }
        }


        // 加密密码（对应C#的SafetyUtil.EncryptPassword）
        String encryptedPwd = SafetyUtil.encryptPassword(newpwd);
        try {
            response[0] = dataImpl.doResetPwd(getUser().UserId, encryptedPwd);
        } catch (SQLException e) {
            log.debug(String.valueOf("ResetPwdComp中执行到dataImpl.doResetPwd报错"));
            throw new RuntimeException(e);
        }
        if (response[0].isSuccess()) {
            getUser().IsWeekPwd = false;
            sysLog(String.format("%s登录强制修改密码%s", getUser().UserName, newpwd), "修改密码");
            getUser().Pwd = "";
            if (!NativeExtensionUtils.isNullOrEmpty(getUser().Token)) {
                CacheUtil.remove(getUser().Token);
            }
            if (!NativeExtensionUtils.isNullOrEmpty(getDriver()) && (getDriver().equals("android") || getDriver().equals("ios"))) {
                getUser().Token = JwtHelp.createToken(getUser(), 2592000);
                response[0].setToken(getUser().Token);
            } else {
                getUser().Token = JwtHelp.createToken(getUser(), 7200);
                response[0].setToken(getUser().Token);
            }
            setSessionVal("users", getUser());
            response[0].setMsg(LanguageUtil.Success);
            response[0].setSuccess(true);
        }
        return response[0];
//        // 获取当前登录用户ID
//        LoginUserInfo currentUser = getUser();
//        if (currentUser == null) {
//            response[0].setSuccess(false);
//            response[0].setData("未获取用户");
//            return response[0];
//        }
//        String userId = currentUser.UserId;
//        String sql = String.format("update P_EmployeeTab set [Password]='%s' where EmployeeId='%s' and isnull(sign,0)=0", encryptedPwd, userId);
////        if (dbOperator.executeNonQuery(sql) > 0) {
//        // 执行密码更新操作
//        int rowsAffected = jdbcTemplate.update(sql);
//
//        if (rowsAffected > 0) {
//            // 记录系统日志（对应C#的SysLog）
//            logAction(currentUser.UserName + "修改密码=>" + newpwd, "修改密码");
//
//            // 更新当前用户对象的密码为空并更新会话
//            currentUser.Pwd = "";
//            setSessionVal("users", currentUser);
//
//            // 设置成功响应
//            response[0].setMsg(LanguageUtil.Success);
//            response[0].setSuccess(true);
//        }
//
//        return response[0];
    }

    /**
     * 初始化指定用户密码（对应C#的InitializePwd方法）
     */

    /**
     * 初始化密码（对应C#的InitializePwd方法）
     */
    public BaseResponse InitializePwd(String username, String newpwd, String renewpwd) {
        // 初始化响应对象（对应C#的BaseResponse）
        BaseResponse[] response = new BaseResponse[1];
        response[0] = new BaseResponse();

        // 1. 验证新密码和确认密码是否一致（与C#逻辑相同）
        if (!newpwd.equals(renewpwd)) {
            response[0].setMsg(LanguageUtil.DifferentPwd);
            return response[0];
        }

        // 2. 加密新密码（对应C#的SafetyUtil.EncryptPassword）
        String encryptedNewPwd = safetyUtil.encryptPassword(newpwd);

        String userId = "";
        String sql = "select employeeid from P_EmployeeTab where (LoginAccount = ? or EmployeeName = ?) and isnull(sign,0)=0";

        try {
            // 2. 一行代码完成：查询+封装为List<Map>（?占位符传参）
            List<Map<String, Object>> result = jdbcTemplate.queryForList(sql, username, username);
            if (!result.isEmpty()) {
                Object empIdObj = result.get(0).get("employeeid");
                userId = empIdObj == null ? "" : empIdObj.toString();
            }
            // 3. 极简处理：有数据取第一条的employeeid，否则返回空字符串
        } catch (Exception e) {
            userId = "";
        }
        if (NativeExtensionUtils.isNullOrEmpty(userId)) {
            response[0].setMsg("未找到用户");
            return response[0];
        }
        String sPwd = SafetyUtil.encryptPassword(newpwd);
        try {
            response[0] = dataImpl.doResetPwd(userId, sPwd);
        } catch (SQLException e) {
            log.debug(String.valueOf("InitializePwd中执行到dataImpl.doResetPwd报错"));
            throw new RuntimeException(e);
        }
        if (response[0].isSuccess()) {
            sysLog(String.format("%s初始密码为%s", username, newpwd), "修改密码");
        }

        return response[0];
    }

    /**
     * 获取GPS位置信息（对应C#的GetGPSLoction方法）
     * 根据用户ID和时间范围查询位置记录
     */

    public BaseResponse GetGPSLoction(String userid, String lasttime) {
        // 1. 处理时间参数（对应C#的DateTime解析逻辑）
        LocalDateTime lt = null;
        LocalDateTime et = LocalDateTime.now(); // 初始化结束时间为当前时间
        // 生成和解析使用相同的格式器（关键修改）
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        // 尝试解析lasttime字符串为LocalDateTime（对应C#的DateTime.TryParse）
        boolean succ = false;
        try {
            if (lasttime != null && !lasttime.trim().isEmpty()) {
                lt = LocalDateTime.parse(lasttime, formatter);
                succ = true;
            }
        } catch (DateTimeParseException e) {
            // 解析失败，保持succ为false
            succ = false;
        }
        // 若解析成功，结束时间设为lt加1个月（对应C#的lt.AddMonths(1)）
        if (succ) {
            et = lt.plusMonths(1);
        }

        // 2. 格式化结束时间为"yyyy-MM-dd"字符串（对应C#的et.ToString("yyyy-MM-dd")）
        String enddate = et.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));

        // 3. 定义SQL查询语句（与C#保持一致，使用?作为占位符）
        String sql = "select operatedate, fixdate, longitude lng, latitude lat, address " +
                "from Crm_EmployeeLocation " +
                "where employeeid = ? " +
                "and operatedate > ? " +
                "and operatedate < ? " +
                "order by operatedate asc";

        // 4. 执行查询（对应C#的dbOperator.ExecuteDataTable）
        // 返回List<Map>对应C#的DataTable，每个Map代表一行数据
        List<Map<String, Object>> data = jdbcTemplate.queryForList(
                sql,
                userid,          // 对应@employeeid参数
                lasttime,        // 对应@operatedate参数（直接使用原始字符串）
                enddate          // 对应@enddate参数（格式化后的结束时间）
        );

        // 5. 构建并返回响应对象（对应C#的BaseResponse初始化）
        BaseResponse[] response = new BaseResponse[1];
        response[0] = new BaseResponse();
        response[0].setSuccess(true);
        response[0].setData(data);

        return response[0];
    }

    public BaseResponse GenerateCaptcha(String codekey) {
        String captchaCode = PublicUtil.GenerateRandomCode(4);
        Duration timeSpan = Duration.ofMinutes(5);
        CacheUtil.set(codekey, captchaCode, timeSpan, null);
        ByteArrayOutputStream memoryStream = new ByteArrayOutputStream();
        try {
            // 4. 生成验证码图片并写入内存流
            PublicUtil.GenerateCaptchaImage(captchaCode, memoryStream);

            // 5. 将内存流中的字节转Base64字符串（对应C#的Convert.ToBase64String）
            byte[] imageBytes = memoryStream.toByteArray();
            String base64String = Base64.getEncoder().encodeToString(imageBytes);

            // 6. 拼接Base64图片前缀（和C#保持一致）
            String imageData = "data:image/png;base64," + base64String;

            // 7. 构建并返回BaseResponse
            BaseResponse[] response = new BaseResponse[1];
            response[0] = new BaseResponse();
            response[0].setSuccess(true);
            response[0].setData(imageData);
            return response[0];

        } catch (IOException e) {
            // 异常处理：返回失败响应
            BaseResponse errorResponse = new BaseResponse();
            errorResponse.setSuccess(false);
            errorResponse.setData("验证码图片生成失败");
            throw new RuntimeException("生成验证码图片异常", e);
        } finally {
            // 8. 关闭流释放资源（对应C#的using）
            try {
                if (memoryStream != null) {
                    memoryStream.close();
                }
            } catch (IOException e) {
                log.error("Exception caught", e);
            }

        }
    }


    public BaseResponse verifyCode(String phone, String phonecode, String username, String uuid) {
        BaseResponse[] baseResponse = new BaseResponse[1];
        baseResponse[0] = new BaseResponse();
        baseResponse[0].setSuccess(true);
        return LoginByPhone(phone, phonecode, username, uuid);
    }

    public BaseResponse GetPhoneNumber(String name) {
        BaseResponse[] response = new BaseResponse[1];
        response[0] = new BaseResponse();
        response[0].setSuccess(true);
        String sql = "select top 1 p_emp_phone from p_employeetab where employeename=?";
        List<Map<String, Object>> dt = jdbcTemplate.queryForList(sql, name);
        if (dt.size() == 1) {
            Object phoneObj = dt.get(0).get("p_emp_phone");
            // 空值处理：null则返回空字符串，否则转字符串（和C#一致）
            response[0].setData(phoneObj == null ? "" : phoneObj.toString());
        } else {
            response[0].setSuccess(false);
            response[0].setMsg("未查询到绑定手机号");
        }
        return response[0];
    }

    public BaseResponse ResetPwdByPhone() {
        BaseResponse[] response = new BaseResponse[1];
        response[0] = new BaseResponse();
        response[0].setSuccess(true);
        if (NativeExtensionUtils.isNullOrEmpty(WebConfigUtil.getSMSPwd())
                || NativeExtensionUtils.isNullOrEmpty(WebConfigUtil.getSMSUserName())) {
            response[0].setSuccess(false);
        }
        return response[0];
    }

}
