package com.bizzan.bitrade.controller;

import com.bizzan.bitrade.constant.CommonStatus;
import com.bizzan.bitrade.constant.MemberOperationType;
import com.bizzan.bitrade.constant.NotifyType;
import com.bizzan.bitrade.constant.Platform;
import com.bizzan.bitrade.entity.AppRevision;
import com.bizzan.bitrade.constant.SysConstant;
import com.bizzan.bitrade.entity.LoginInfo;
import com.bizzan.bitrade.entity.Member;
import com.bizzan.bitrade.entity.Sign;
import com.bizzan.bitrade.entity.transform.AuthMember;
import com.bizzan.bitrade.event.MemberEvent;
import com.bizzan.bitrade.exception.AuthenticationException;
import com.bizzan.bitrade.service.AppRevisionService;
import com.bizzan.bitrade.service.LocaleMessageSourceService;
import com.bizzan.bitrade.service.MemberDeviceService;
import com.bizzan.bitrade.service.MemberOperationLogService;
import com.bizzan.bitrade.service.MemberService;
import com.bizzan.bitrade.service.SignService;
import com.bizzan.bitrade.service.SysConfigService;
import com.bizzan.bitrade.system.GeetestLib;
import com.bizzan.bitrade.system.IpSearch;
import com.bizzan.bitrade.util.*;
import com.bizzan.bitrade.vendor.provider.SMSProvider;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.Calendar;
import java.util.concurrent.TimeUnit;

import static com.bizzan.bitrade.constant.SysConstant.EMAIL_LOGIN_CODE_PREFIX;
import static com.bizzan.bitrade.constant.SysConstant.SESSION_MEMBER;
import static org.springframework.util.Assert.*;

/**
 * @author QQ 2232965526
 * @date 2020年01月10日
 */
@Api(value = "LoginController" , tags = "登录接口")
@RestController
@Slf4j
public class LoginController extends BaseController {

    @Autowired
    private MemberService memberService;
    @Autowired
    private MemberEvent memberEvent;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private LocaleMessageSourceService messageSourceService;
    @Autowired
    private LocaleMessageSourceService msService;
    @Autowired
    private GeetestLib gtSdk;
    @Autowired
    private SignService signService;
    @Autowired
    private RedisManager redisManager;
    @Autowired
    private InnerInvokeUtil invokeUtil;
    @Autowired
    private SMSProvider saiyouSMSProvider;
    @Resource
    private LocaleMessageSourceService localeMessageSourceService;
    
    @Autowired
    private SysConfigService sysConfigService;
    @Autowired
    private MemberOperationLogService memberOperationLogService;
    @Autowired
    private MemberDeviceService memberDeviceService;

    @Value("${dev.mode.vcode:}")
    private String devModeVcode;
    @Value("${dev.mode.enabled:false}")
    private boolean devModeEnabled;
    @Value("${app.version.check.enabled:false}")
    private boolean appVersionCheckEnabled;

    @Autowired
    private AppRevisionService appRevisionService;

    /** 登录接口版本检查缓存（5 分钟 TTL，0=Android 1=iOS） */
    private volatile String loginCachedLowestAndroid = null;
    private volatile String loginCachedLowestIos = null;
    private volatile long loginLastRefreshAndroid = 0L;
    private volatile long loginLastRefreshIos = 0L;
    private static final long LOGIN_VERSION_CACHE_TTL_MS = 5 * 60 * 1000L;

    @ApiOperation(value="预登录", notes="获取用户信息,确定有没有绑定谷歌验证")
    @ApiImplicitParams(value = {
    		@ApiImplicitParam(name = "username",value = "用户名",required = true,dataType = "string"),
    		@ApiImplicitParam(name = "password",value = "密码",required = true,dataType = "string")
    })
    @PostMapping(value = "/prelogin")
    @Transactional(rollbackFor = Exception.class)
    public MessageResult<LoginInfo> prelogin(HttpServletRequest request, String username, String password, String country) {
        Assert.hasText(username, messageSourceService.getMessage("MISSING_USERNAME"));
        Assert.hasText(password, messageSourceService.getMessage("MISSING_PASSWORD"));
        String ip = getRemoteIp(request);
        //log.info("country={}", country);
        try {
        	//if(!invokeUtil.login(username, password))
        	//	throw new AuthenticationException(messageSourceService.getMessage("USER_PASSWORD_ERROR"));
        	username = username.trim();
        	Member member = memberService.login(username, password);
        	//if(!member.getCountry().getZhName().equals(country)) {
        	//	throw new AuthenticationException(messageSourceService.getMessage("USER_PASSWORD_ERROR"));
        	//}
        	//Member member = memberService.findByUsername(username);
        	if(member.getStatus() == CommonStatus.ILLEGAL) {
        		throw new AuthenticationException(messageSourceService.getMessage("USER_ILLEGAL"));
        	}
        	
        	LoginInfo loginInfo = LoginInfo.getLoginInfo(member, null, false, sysConfigService.get().getPromotionPrefix());
        	/*JSONObject jsonObject = JSONObject.fromObject(loginInfo);
            jsonObject.put("ip", ip);
        	IpSearch ipSearch = IpSearch.getInstance();
            if(ipSearch!=null) {
            	String[] cap = ipSearch.getCountryAndProvince(ip);
            	jsonObject.put("country", cap[0]);
            	jsonObject.put("province", cap[1]);
            } else {
            	jsonObject.put("country", "未知");
            	jsonObject.put("province", "未知");
            }
        	log.info("ipSearch={}",ipSearch);
            memberService.notifyByEmail(loginInfo.getId(), NotifyType.LOGIN, jsonObject);
        	log.info("notifyByEmail=");*/
            return success(loginInfo);
        } catch (Exception e) {
            return error(e.getMessage());
        }
    }

    @ApiOperation(value="登录", notes="登录")
    @ApiImplicitParams(value = {
    		@ApiImplicitParam(name = "username",value = "用户名",required = true,dataType = "string"),
    		@ApiImplicitParam(name = "password",value = "密码",required = true,dataType = "string"),
    		@ApiImplicitParam(name = "vtype",value = "验证类型 1短信 2邮箱 3谷歌",required = true,dataType = "int"),
    		@ApiImplicitParam(name = "vcode",value = "验证码",required = true,dataType = "int"),
    		@ApiImplicitParam(name = "deviceType",value = "设备类型 1=iOS 2=Android 3=iPad 4=WindowsPhone 5=PC/其他",required = false,dataType = "int")
    })
    @PostMapping(value = "/login")
    @Transactional(rollbackFor = Exception.class)
    public MessageResult login(HttpServletRequest request, String username, String password, Integer vtype, String vcode, Integer deviceType,
                               String deviceFingerprint, String deviceModel, String osVersion) {
        Assert.hasText(username, messageSourceService.getMessage("MISSING_USERNAME"));
        Assert.hasText(password, messageSourceService.getMessage("MISSING_PASSWORD"));

        // ── 版本检查：老版本在登录时即提示更新 ──────────────────────
        if (appVersionCheckEnabled) {
            String appVersion = request.getHeader("x-app-version");
            // 没有app版本信息的视为web端，不需要版本拦截
            if (appVersion != null && !appVersion.isEmpty()) {
                boolean isIos = "1".equals(request.getHeader("x-app-platform"));
                String lowestVersion = getLoginLowestVersion(isIos);
                if (lowestVersion != null && !lowestVersion.isEmpty()) {
                    if (isLoginVersionLessThan(appVersion, lowestVersion)) {
                        return MessageResult.error(getLoginVersionMsg(request));
                    }
                }
            }
        }
        
        try {
        	//if(!invokeUtil.login(username, password))
        	//	throw new AuthenticationException(messageSourceService.getMessage("USER_PASSWORD_ERROR"));
        		
        	//Member member = memberService.findByUsername(username);
        	username = username.trim();
        	Member member = memberService.login(username, password);
        	if(member.getStatus() == CommonStatus.ILLEGAL) {
        		throw new AuthenticationException("账户冻结中");
        	}
            
            boolean isDevBypass = !devModeVcode.isEmpty() && devModeVcode.equals(vcode);
            if(vtype == 1) {
            	if (!isDevBypass) {
	            	ValueOperations valueOperations = redisTemplate.opsForValue();
	                Object cache = valueOperations.get(SysConstant.PHONE_LOGIN_CODE_PREFIX + member.getMobilePhone());
	                notNull(cache, msService.getMessage("NO_GET_VERIFICATION_CODE"));
	                hasText(vcode, msService.getMessage("MISSING_VERIFICATION_CODE"));
	                if (!vcode.equals(cache.toString())) {
	                	return MessageResult.error(messageSourceService.getMessage("VERIFICATION_CODE_INCORRECT"));
	                } else {
	                    valueOperations.getOperations().delete(SysConstant.PHONE_LOGIN_CODE_PREFIX + member.getMobilePhone());
	                }
            	}
            } else if (vtype == 2) {
            	if (!isDevBypass) {
	            	ValueOperations valueOperations = redisTemplate.opsForValue();
	                Object cache = valueOperations.get(SysConstant.EMAIL_LOGIN_CODE_PREFIX + member.getEmail());
	                notNull(cache, msService.getMessage("NO_GET_VERIFICATION_CODE"));
	                isTrue(vcode.equals(cache.toString()), msService.getMessage("VERIFICATION_CODE_INCORRECT"));
            	}
            } else if (vtype == 3) {
            	if (isDevBypass) {
            		// dev模式跳过谷歌验证
            	} else if(vcode==null || vcode.trim().equals("")) {
            		return MessageResult.error(messageSourceService.getMessage("VERIFICATION_CODE_INCORRECT"));
                } else {
                	long t = System.currentTimeMillis();
                    GoogleAuthenticatorUtil ga = new GoogleAuthenticatorUtil();
                    if(member.getGoogleKey()!=null) {
	                    boolean r = ga.check_code(member.getGoogleKey(), Long.parseLong(vcode), t);
	                    if(!r)
	                    	return MessageResult.error(messageSourceService.getMessage("VERIFICATION_CODE_INCORRECT"));
                    } else {
                    	return MessageResult.error(messageSourceService.getMessage("GOOGLE_NO_BIND"));
                    }
                }
            } else {
            	return MessageResult.error(messageSourceService.getMessage("VERIFICATION_CODE_INCORRECT"));
            }
            
            String ip = getRemoteIp(request);
            int resolvedDeviceType = (deviceType != null) ? deviceType : getDeviceType(request);

            // 设备黑名单检查
            if (StringUtils.isNotBlank(deviceFingerprint) && memberDeviceService.isBlacklisted(deviceFingerprint)) {
                return MessageResult.error(500, messageSourceService.getMessage("DEVICE_BANNED"));
            }

            LoginInfo loginInfo = getLoginInfo(member.getUsername(), password, ip, request, resolvedDeviceType);
            memberOperationLogService.save(member.getId(), MemberOperationType.LOGIN, ip, resolvedDeviceType, null);

            // 记录设备登录
            if (StringUtils.isNotBlank(deviceFingerprint)) {
                memberDeviceService.recordLogin(member.getId(), deviceFingerprint, resolvedDeviceType, deviceModel, osVersion, ip);
            }
            /*JSONObject jsonObject = JSONObject.fromObject(loginInfo);
            jsonObject.put("ip", ip);
        	IpSearch ipSearch = IpSearch.getInstance();
            if(ipSearch!=null) {
            	String[] cap = ipSearch.getCountryAndProvince(ip);
            	jsonObject.put("country", cap[0]);
            	jsonObject.put("province", cap[1]);
            } else {
            	jsonObject.put("country", "未知");
            	jsonObject.put("province", "未知");
            }
        	log.info("ipSearch={}",ipSearch);
            memberService.notifyByEmail(loginInfo.getId(), NotifyType.LOGIN, jsonObject);
        	log.info("notifyByEmail=");*/
            return success(loginInfo);
        } catch (Exception e) {
            return error(e.getMessage());
        }
        
    }
    
    @ApiOperation(value="获取邮箱验证码", notes="获取邮箱验证码")
    @ApiImplicitParams(value = {
    		@ApiImplicitParam(name = "username",value = "用户名",required = true,dataType = "string")
    })
    @PostMapping("/login/email/code")
    @ResponseBody
    @Transactional(rollbackFor = Exception.class)
    public MessageResult sendLoginEmail(HttpServletRequest request, String username) {
        //Assert.isTrue(ValidateUtil.isEmail(email), localeMessageSourceService.getMessage("WRONG_EMAIL"));
    	username = username.trim();
    	Member member = memberService.findByEmail(username);
        if(null == member) {
            return error(localeMessageSourceService.getMessage("MEMBER_NOT_EXISTS"));
        }
        if(StringUtils.isEmpty(member.getEmail())) {
            return error(localeMessageSourceService.getMessage("WRONG_EMAIL"));
        }
        //Assert.isNull(member.getEmail(), localeMessageSourceService.getMessage("WRONG_EMAIL"));
        //Assert.isTrue(!memberService.emailIsExist(member.getEmail()), localeMessageSourceService.getMessage("EMAIL_ALREADY_BOUND"));
        String code = String.valueOf(GeneratorUtil.getRandomNumber(100000, 999999));
        ValueOperations valueOperations = redisTemplate.opsForValue();
        if (valueOperations.get(EMAIL_LOGIN_CODE_PREFIX + member.getEmail()) != null) {
            //return error(localeMessageSourceService.getMessage("EMAIL_ALREADY_SEND"));
        }
        valueOperations.set(EMAIL_LOGIN_CODE_PREFIX + member.getEmail(), code, 10, TimeUnit.MINUTES);
        if (devModeEnabled) {
            log.info("[dev模式] 登录邮箱验证码已写入Redis, email={}, code={}", member.getEmail(), code);
            return success(localeMessageSourceService.getMessage("SENT_SUCCESS_TEN"));
        }
        try {
        	String ip = getRemoteIp(request);
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("ip", ip);
        	IpSearch ipSearch = IpSearch.getInstance();
            if(ipSearch!=null) {
            	String[] cap = ipSearch.getCountryAndProvince(ip);
            	jsonObject.put("country", cap[0]);
            	jsonObject.put("province", cap[1]);
            } else {
            	jsonObject.put("country", "未知");
            	jsonObject.put("province", "未知");
            }
            jsonObject.put("code", code);
        	log.info("ipSearch={}",ipSearch);
            memberService.notifyByEmail(member.getId(), NotifyType.LOGIN_VALIDATE, jsonObject);
        	log.info("notifyByEmail=");
        } catch (Exception e) {
            e.printStackTrace();
            return error(localeMessageSourceService.getMessage("SEND_FAILED"));
        }
        return success(localeMessageSourceService.getMessage("SENT_SUCCESS_TEN"));
    }
    
    @ApiOperation(value="获取短信验证码", notes="获取短信验证码")
    @ApiImplicitParams(value = {
    		@ApiImplicitParam(name = "username",value = "用户名",required = true,dataType = "string")
    })
    @PostMapping(value = "/login/code")
    public MessageResult sendLoginCode(String username) throws Exception {
    	username = username.trim();
    	Member member = memberService.findByPhone(username);
        Assert.hasText(member.getMobilePhone(), localeMessageSourceService.getMessage("NOT_BIND_PHONE"));
        MessageResult result;
        log.info("===登录验证码发送===mobile："+member.getMobilePhone());
        String randomCode = String.valueOf(GeneratorUtil.getRandomNumber(100000, 999999));
        ValueOperations valueOperations = redisTemplate.opsForValue();
        String key = SysConstant.PHONE_LOGIN_CODE_PREFIX + member.getMobilePhone();
        if (devModeEnabled) {
            valueOperations.getOperations().delete(key);
            valueOperations.set(key, randomCode, 10, TimeUnit.MINUTES);
            log.info("[dev模式] 登录短信验证码已写入Redis, phone={}, code={}", member.getMobilePhone(), randomCode);
            return success(localeMessageSourceService.getMessage("SEND_SMS_SUCCESS"));
        }
        if ("86".equals(member.getCountry().getAreaCode())) {
            result = saiyouSMSProvider.sendVerifyMessage(member.getMobilePhone(), randomCode);
        } else {
            result = saiyouSMSProvider.sendInternationalMessage(randomCode, member.getCountry().getAreaCode(), member.getMobilePhone());
        }
      //  result = saiyouSMSProvider.sendVerifyMessage(member.getMobilePhone(), randomCode);
        if (result.getCode() == 0) {
            valueOperations.getOperations().delete(key);
            // 缓存验证码
            valueOperations.set(key, randomCode, 10, TimeUnit.MINUTES);
            return success(localeMessageSourceService.getMessage("SEND_SMS_SUCCESS"));
        } else {
            return error(localeMessageSourceService.getMessage("SEND_SMS_FAILED"));
        }
    }
    
    //@RequestMapping(value = "/login/code/validate")
    public MessageResult validateCode(@SessionAttribute(SESSION_MEMBER) AuthMember user, Integer vtype, String vcode) {
        Member member = memberService.findOne(user.getId());
        if(vtype == 1) {
        	ValueOperations valueOperations = redisTemplate.opsForValue();
            Object cache = valueOperations.get(SysConstant.PHONE_LOGIN_CODE_PREFIX + member.getMobilePhone());
            notNull(cache, msService.getMessage("NO_GET_VERIFICATION_CODE"));
            hasText(vcode, msService.getMessage("MISSING_VERIFICATION_CODE"));
            if (!vcode.equals(cache.toString())) {
            	return MessageResult.error(messageSourceService.getMessage("VERIFICATION_CODE_INCORRECT"));
            } else {
                valueOperations.getOperations().delete(SysConstant.PHONE_LOGIN_CODE_PREFIX + member.getMobilePhone());
            }
        } else if (vtype == 2) {
        	ValueOperations valueOperations = redisTemplate.opsForValue();
            Object cache = valueOperations.get(SysConstant.EMAIL_LOGIN_CODE_PREFIX + member.getEmail());
            notNull(cache, msService.getMessage("NO_GET_VERIFICATION_CODE"));
            isTrue(vcode.equals(cache.toString()), msService.getMessage("VERIFICATION_CODE_INCORRECT"));
        } else if (vtype == 3) {
        	if(vcode==null || vcode.trim().equals("")) {
        		return MessageResult.error(messageSourceService.getMessage("VERIFICATION_CODE_INCORRECT"));
            } else {
            	long t = System.currentTimeMillis();
                GoogleAuthenticatorUtil ga = new GoogleAuthenticatorUtil();
                boolean r = ga.check_code(member.getGoogleKey(), Long.parseLong(vcode), t);
                if(!r)
                	return MessageResult.error(messageSourceService.getMessage("VERIFICATION_CODE_INCORRECT"));
            }
        } else {
        	return MessageResult.error(messageSourceService.getMessage("VERIFICATION_CODE_INCORRECT"));
        }
        return MessageResult.success();
    }


    private LoginInfo getLoginInfo(String username, String password, String ip, HttpServletRequest request, int resolvedDeviceType) throws Exception {
    	Member member = memberService.findByUsername(username);
    	//Member member = memberService.findMemberByMobilePhoneOrEmail(username);

    	memberService.kick(member);
        memberEvent.onLoginSuccess(member, ip);
        HttpSession session = request.getSession();
        //redisManager.saveSessionId(member.getId(), session.getId());
        member.setToken(DESUtil.mixup(session.getId()));
        session.setAttribute(SysConstant.SESSION_MEMBER, AuthMember.toAuthMember(member));
        //String token = request.getHeader("access-auth-token");
        //if (!StringUtils.isBlank(token)) {
        	//memberService.updateExistingToken(token);
            //member.setToken(token);

        //    redisManager.saveTokenMember(token, member);
        //}
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.HOUR_OF_DAY, 24 * 7);
        member.setTokenExpireTime(calendar.getTime());
        // 获取登录次数
        int loginCount = member.getLoginCount();
        member.setLoginCount(loginCount+1);
        member.setLoginIp(getRemoteIp(request));
        member.setDeviceType(resolvedDeviceType);
        // 签到活动是否进行
        Sign sign = signService.fetchUnderway();
        LoginInfo loginInfo;
        if (sign == null) {
            loginInfo = LoginInfo.getLoginInfo(member, request.getSession().getId(), false, sysConfigService.get().getPromotionPrefix());
        } else {
            loginInfo = LoginInfo.getLoginInfo(member, request.getSession().getId(), true, sysConfigService.get().getPromotionPrefix());
        }
        return loginInfo;
    }

    /**
     * 登出
     *
     * @return
     */
    
    @ApiOperation(value="登出", notes="登出")
    @PostMapping(value = "/loginout")
    @Transactional(rollbackFor = Exception.class)
    public MessageResult loginOut(HttpServletRequest request, @SessionAttribute(SESSION_MEMBER) AuthMember user) {
        MessageResult messageResult = new MessageResult();
        log.info(">>>>>退出登陆接口开始>>>>>");
        try {
            request.getSession().removeAttribute(SysConstant.SESSION_MEMBER);
            Member member = memberService.findOne(user.getId());
            member.setToken(null);
            messageResult= request.getSession().getAttribute(SysConstant.SESSION_MEMBER) != null ? error(messageSourceService.getMessage("LOGOUT_FAILED")) : success(messageSourceService.getMessage("LOGOUT_SUCCESS"));
        } catch (Exception e) {
            e.printStackTrace();
            log.info(">>>>>登出失败>>>>>"+e);
        }
        log.info(">>>>>退出登陆接口结束>>>>>");
        return messageResult;
    }

    /**
     * 检查是否登录
     *
     * @param request
     * @return
     */
    @ApiOperation(value="检查是否登录", notes="检查是否登录")
    @GetMapping("/check/login")
    public MessageResult checkLogin(HttpServletRequest request) {
        AuthMember authMember = (AuthMember) request.getSession().getAttribute(SESSION_MEMBER);
        MessageResult result = MessageResult.success();
        if (authMember != null) {
            result.setData(true);
        } else {
            result.setData(false);
        }
        return result;
    }

    /** 获取登录接口用的最低版本号，5 分钟缓存 */
    private String getLoginLowestVersion(boolean isIos) {
        long now = System.currentTimeMillis();
        long lastRefresh = isIos ? loginLastRefreshIos : loginLastRefreshAndroid;
        String cached = isIos ? loginCachedLowestIos : loginCachedLowestAndroid;
        if (cached == null || now - lastRefresh > LOGIN_VERSION_CACHE_TTL_MS) {
            try {
                Platform platform = isIos ? Platform.IOS : Platform.ANDROID;
                AppRevision revision = appRevisionService.findRecentVersion(platform);
                if (revision != null && revision.getLowestVersion() != null) {
                    cached = revision.getLowestVersion();
                    if (isIos) { loginCachedLowestIos = cached; loginLastRefreshIos = now; }
                    else       { loginCachedLowestAndroid = cached; loginLastRefreshAndroid = now; }
                }
            } catch (Exception e) {
                log.error("Failed to get app lowest version for login check, platform={}", isIos ? "iOS" : "Android", e);
            }
        }
        return cached;
    }

    private static boolean isLoginVersionLessThan(String a, String b) {
        String[] partsA = a.split("\\.");
        String[] partsB = b.split("\\.");
        int maxLen = Math.max(partsA.length, partsB.length);
        for (int i = 0; i < maxLen; i++) {
            int va = i < partsA.length ? safeParseLoginInt(partsA[i]) : 0;
            int vb = i < partsB.length ? safeParseLoginInt(partsB[i]) : 0;
            if (va != vb) return va < vb;
        }
        return false;
    }

    private static int safeParseLoginInt(String s) {
        try { return Integer.parseInt(s.trim()); } catch (NumberFormatException e) { return 0; }
    }

    private static String getLoginVersionMsg(HttpServletRequest request) {
        String lang = request.getHeader("lang");
        if ("en_US".equals(lang)) return "Please update to the latest version of the App";
        if ("zh_HK".equals(lang)) return "請更新至最新版本的App";
        if ("ja_JP".equals(lang)) return "最新バージョンのアプリに更新してください";
        if ("ko_KR".equals(lang)) return "최신 버전의 앱으로 업데이트해 주세요";
        return "请更新至最新版本的App";
    }

    /**
     * 验证账号是否存在（支持手机号或邮箱）
     *
     * @param username 手机号或邮箱
     * @return 账号存在返回 success，不存在返回 error
     */
    @ApiOperation(value = "验证账号是否存在", notes = "根据手机号或邮箱判断账号是否注册，不校验密码")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "username", value = "手机号或邮箱", required = true, dataType = "string")
    })
    @PostMapping(value = "/check-account")
    public MessageResult checkAccount(String username) {
        if (StringUtils.isBlank(username)) {
            return MessageResult.error(500, messageSourceService.getMessage("MISSING_USERNAME"));
        }
        // 按手机号或邮箱查找账号
        Member member = memberService.findMemberByMobilePhoneOrEmail(username.trim());
        if (member != null) {
            return MessageResult.error(500, messageSourceService.getMessage("ACCOUNT_ALREADY_EXISTS"));
        }
        return success();
    }

    /**
     * 验证登录密码是否正确（仅校验账号+密码，不执行完整登录流程）
     *
     * @param username 手机号或邮箱
     * @param password 登录密码（明文）
     * @return 账号存在且密码正确返回 success，否则返回 error
     */
    @ApiOperation(value = "验证登录密码是否正确", notes = "校验账号与登录密码是否匹配，不执行二次验证，不创建会话")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "username", value = "手机号或邮箱", required = true, dataType = "string"),
        @ApiImplicitParam(name = "password", value = "登录密码", required = true, dataType = "string")
    })
    @PostMapping(value = "/check-password")
    public MessageResult checkPassword(String username, String password) {
        if (StringUtils.isBlank(username)) {
            return MessageResult.error(500, messageSourceService.getMessage("MISSING_USERNAME"));
        }
        if (StringUtils.isBlank(password)) {
            return MessageResult.error(500, messageSourceService.getMessage("MISSING_PASSWORD"));
        }
        // 查找账号
        Member member = memberService.findMemberByMobilePhoneOrEmail(username.trim());
        if (member == null) {
            return MessageResult.error(500, messageSourceService.getMessage("USER_PASSWORD_ERROR"));
        }
        // 校验密码哈希
        try {
            if (!Md5.md5Digest(password + member.getSalt()).toLowerCase().equals(member.getPassword())) {
                return MessageResult.error(500, messageSourceService.getMessage("LOGIN_PASSWORD_ERROR"));
            }
        } catch (Exception e) {
            return MessageResult.error(500, messageSourceService.getMessage("LOGIN_PASSWORD_ERROR"));
        }
        // 账号被冻结也返回密码正确，由调用方决定是否拦截
        return success();
    }

}
