package com.ytpm.handle;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.ytpm.agent.enums.UserStatusEnum;
import com.ytpm.app.enums.LoginType;
import com.ytpm.app.model.YtDyzLoginRecord;
import com.ytpm.app.model.YtDyzUser;
import com.ytpm.app.param.LoginParam;
import com.ytpm.app.view.WxDefaultConfig;
import com.ytpm.general.RepMessage;
import com.ytpm.general.Result;
import com.ytpm.util.IPUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * <p>登陆模板</p>
 * 兼容多登陆模式及风控校验
 * <p>需重写方法：<br>
 * 1.登陆参数校验 validateParams
 * 2.根据设备及渠道ID查询用户 queryUserByDeviceAndDitch
 * 3.获取登陆默认配置 getLoginConfig
 * 4.根据登陆参数获取系统用户 queryDyzUserByParam
 * 5.用户新注册逻辑 registryUser
 * 6.已注册用户处理逻辑 deadWithUserCrud
 * 7.登陆记录保存 saveLoginRecord
 * 8.远程调用风控 remoteCheckLoginRisk
 * 9.远程调用风控 remoteCheckRegRisk
 * </p>
 *
 * <p>回调方法：<br>
 * 1.用户注册时回调 beforeRegistryUser<br>
 * 2.用户登陆时回调 beforeDeadWithUserCrud
 * </p>
 *
 * <p>可选重写方法：<br>
 * 1.第三方登陆调用处理及参数传递 setThirdPartyLoginInfo <br>
 * 2.登陆成功后调用风控服务校验 ytRiskValidate
 * 3.登陆用户信息配置额外信息 setExtInfo
 * </p>
 *
 * @author lih
 * @date 2025/9/4
 */
@Slf4j
public abstract class AbstractLoginService {


    @Value("${risk.config.banned.tips}")
    private String tips;

    @Value("${spring.application.name:}")
    private String applicationName;

    protected abstract LoginType getLoginType();

    /**
     * 登陆逻辑处理
     * @param loginParam 登陆参数
     * @param request request
     * @return YtDyzUser
     */
    public final YtDyzUser loginHandle(LoginParam loginParam, HttpServletRequest request) {
        loginParam.setLoginIp(IPUtil.getClientIp(request));
        // 获取默认配置
        WxDefaultConfig defaultConfig = getLoginConfig(loginParam.getAppType());
        if (Objects.isNull(defaultConfig)) {
            throw new CommonException(StrUtil.format("{}登录失败，未找到相应配置！", getLoginType().getTypeName()));
        }
        loginParam.setAppId(defaultConfig.getPlatformAppId());
        // 参数校验
        validateParams(loginParam, request);
        // 获取第三方登陆信息 如微信授权码、微信登陆后授权信息
        Map<String, Object> paramMap = setThirdPartyLoginInfo(loginParam, defaultConfig, request);
        YtDyzUser ytDyzUser;
        if (getLoginType() == LoginType.VISITOR) {
            // 游客模式
            paramMap.put("defaultConfig", defaultConfig);
            ytDyzUser = visitorLoginHandle(loginParam, paramMap);
        } else {
            ytDyzUser = clientLoginHandle(loginParam, paramMap);
        }
        // 配置额外信息
        setExtInfo(ytDyzUser, paramMap);
        // 添加用户登录记录
        addLoginRecord(loginParam,ytDyzUser);
        // 调用风控服务校验默认风控配置
        ytRiskValidate(ytDyzUser, paramMap);
        // 游客登陆 校验通过 更新用户状态为正常
        if (getLoginType() == LoginType.VISITOR) {
            updateUserStatus(ytDyzUser, UserStatusEnum.NORMAL, null);
        }
        return ytDyzUser;
    }

    protected abstract void updateUserStatus(YtDyzUser ytDyzUser, UserStatusEnum statusEnum, String reason);

    /**
     * 登陆参数校验
     */
    protected abstract void validateParams(LoginParam loginParam, HttpServletRequest request);

    /**
     * 微信端/IOS端登陆
     */
    private YtDyzUser clientLoginHandle(LoginParam loginParam, Map<String, Object> paramMap) {
        YtDyzUser ytDyzUser;
        List<YtDyzUser> ytDyzUsers = queryDyzUserByParam(loginParam, paramMap);
        if (CollectionUtils.isEmpty(ytDyzUsers)) {
            beforeRegistryUser(loginParam, paramMap);
            ytDyzUser = new YtDyzUser();
            registryUser(loginParam, ytDyzUser, paramMap);
        } else {
            ytDyzUser = ytDyzUsers.get(0);
            beforeDeadWithUserCrud(loginParam, ytDyzUser, paramMap);
            deadWithUserCrud(loginParam, ytDyzUser, paramMap);
        }
        ytDyzUser.setLoginType(LoginType.WX);
        return ytDyzUser;
    }

    /**
     * 游客模式登录
     */
    private YtDyzUser visitorLoginHandle(LoginParam loginParam, Map<String, Object> paramMap) {
        // 唯一性判断
        YtDyzUser ytDyzUser = queryUserByDeviceAndDitch(loginParam.getDeviceId(), loginParam.getDitchId());
        if(ytDyzUser == null) {
            log.warn(StrUtil.format("visitor register[ deviceId:{}, ditchId: {}]",
                    loginParam.getDeviceId(), loginParam.getDitchId()));
            beforeRegistryUser(loginParam, paramMap);
            ytDyzUser = new YtDyzUser();
            ytDyzUser = registryUser(loginParam, ytDyzUser, paramMap);
        } else {
            log.warn(StrUtil.format("visitor login[ deviceId:{}, ditchId: {}]",
                    loginParam.getDeviceId(), loginParam.getDitchId()));
            //当前渠道已有用户,校验用户是否处于风控中 & 更新用户信息
            beforeDeadWithUserCrud(loginParam, ytDyzUser, paramMap);
            //如果当前登录是本日第一次登录则登录天数+1
            //202550916 游客登陆不记录登陆信息
            deadWithUserCrud(loginParam, ytDyzUser, paramMap);
        }
        // 保存游客广告信息
        WxDefaultConfig defaultConfig = (WxDefaultConfig) paramMap.get("defaultConfig");
        saveVisitorAdRecord(ytDyzUser, loginParam, defaultConfig);
        ytDyzUser.setLoginType(LoginType.VISITOR);
        return ytDyzUser;
    }

    // 游客登陆时保存传递记录
    protected void saveVisitorAdRecord(YtDyzUser ytDyzUser, LoginParam loginParam, WxDefaultConfig defaultConfig) {

    }


    /**
     * 根据设备及渠道ID查询用户
     */
    protected abstract YtDyzUser queryUserByDeviceAndDitch(String deviceId, Long ditchId);


    /**
     * 第三方登陆调用处理及参数传递
     */
    protected Map<String, Object> setThirdPartyLoginInfo(LoginParam loginParam, WxDefaultConfig defaultConfig,
                                                         HttpServletRequest request) {
        Map<String, Object> map = new HashMap<>();
        return map;
    }


    /**
     * 获取登陆默认配置
     */
    protected abstract WxDefaultConfig getLoginConfig(Integer appType);

    /**
     * 根据登陆配置信息 查询系统用户记录
     * @param loginParam 登陆参数
     * @param thirdPartyLoginInfo 第三方登陆西悉尼
     */
    protected abstract List<YtDyzUser> queryDyzUserByParam(LoginParam loginParam, Map<String, Object> thirdPartyLoginInfo);


    // 注册用户处理器回调
    protected void beforeRegistryUser(LoginParam loginParam, Map<String, Object> paramMap){

    }

    // 用户注册逻辑
    protected abstract YtDyzUser registryUser(LoginParam loginParam,YtDyzUser user,  Map<String, Object> paramMap);

    // 已注册用户处理前回调
    protected void beforeDeadWithUserCrud(LoginParam loginParam, YtDyzUser ytDyzUser, Map<String, Object> paramMap){
        //当前渠道已有用户,校验用户是否处于风控中 & 更新用户信息
        if(ytDyzUser != null && !ytDyzUser.getUserStatus().equals(UserStatusEnum.NORMAL.getCode())
                && !ytDyzUser.getUserStatus().equals(UserStatusEnum.VISITOR_LOCK.getCode())){
            throw new CommonException(getTipsMsg());
        }
    }

    private String getTipsMsg(){
        String[] split = tips.split(",");
        return split[RandomUtil.randomInt(split.length)];
    }


    // 已注册用户处理逻辑
    protected abstract void deadWithUserCrud(LoginParam loginParam, YtDyzUser old, Map<String, Object> paramMap);

    private void addLoginRecord(LoginParam param, YtDyzUser old) {
        YtDyzLoginRecord loginRecord = new YtDyzLoginRecord();
        loginRecord.setRecordId(IdUtil.fastSimpleUUID());
        loginRecord.setUserId(old.getUserId());
        loginRecord.setLoginTime(new Date());
        loginRecord.setDeviceBrand(param.getBrand());
        loginRecord.setDeviceModel(param.getModel());
        loginRecord.setLoginIp(param.getLoginIp());
        loginRecord.setOperator(param.getIpOperator());
        loginRecord.setIpAddr(param.getIpLocation());
        loginRecord.setPhoneJson(param.getPhoneJson());
        loginRecord.setLoginType(old.getLoginType().toString());
        saveLoginRecord(loginRecord);
    }

    /**
     * 保存登陆记录实现
     */
    protected abstract void saveLoginRecord(YtDyzLoginRecord loginRecord);


    /**
     * 调用风控服务校验默认风控配置
     */
    protected void ytRiskValidate(YtDyzUser ytDyzUser, Map<String, Object> paramMap) {
        Result<?> result = remoteCheckLoginRisk(ytDyzUser);
        if (result == null) {
            throw new CommonException("feign invoke Fail!");
        }
        if (result.getCode() != 200) {
            String errorMessage = result.getMessage();
            if (ytDyzUser.getLoginType() == LoginType.VISITOR && RepMessage.RISK_VISITOR_LOWER_VALUE.equals(errorMessage)) {
                WxDefaultConfig defaultConfig = (WxDefaultConfig) paramMap.get("defaultConfig");
                throw new CommonException(StrUtil.emptyToDefault(defaultConfig.getLowValueTip(), errorMessage));
            }
            throw new CommonException(errorMessage);
        }
    }

    /**
     * 配置相关信息
     *
     * @param ytDyzUser
     * @param paramMap
     */
    protected void setExtInfo(YtDyzUser ytDyzUser, Map<String, Object> paramMap) {
        ytDyzUser.setServiceName(applicationName);
    }

    /**
     * 远程调用校验用户风控，需设置风控编码[riskCode]，并重写该方法
     * @param ytDyzUser 当前用户
     */
    protected abstract Result<?> remoteCheckLoginRisk(YtDyzUser ytDyzUser);

    /**
     * 远程调用校验注册用户
     * @param user 参数
     */
    protected abstract Result<?> remoteCheckRegRisk(YtDyzUser user);
}
