package com.zhongshu.card.server.core.service.org;

import com.github.microservice.auth.client.constant.AuthConstant;
import com.github.microservice.auth.client.content.ResultState;
import com.github.microservice.auth.client.model.LoginTokenModel;
import com.github.microservice.auth.client.model.UserAuthLoginModel;
import com.github.microservice.auth.client.model.UserTokenModel;
import com.github.microservice.auth.client.service.UserService;
import com.github.microservice.auth.security.helper.AuthHelper;
import com.github.microservice.auth.security.model.AuthDetails;
import com.github.microservice.auth.security.type.AuthType;
import com.github.microservice.components.data.mongo.mongo.helper.DBHelper;
import com.github.microservice.core.util.net.IPUtil;
import com.zhongshu.card.client.model.login.LoginBusModel;
import com.zhongshu.card.client.model.login.LoginCommonModel;
import com.zhongshu.card.client.model.org.*;
import com.zhongshu.card.client.model.setting.PlatFormLoginConfig;
import com.zhongshu.card.client.model.wechat.PhoneModel;
import com.zhongshu.card.client.model.wechat.WechatPhoneNumber;
import com.github.microservice.net.ResultContent;
import com.zhongshu.card.client.type.LoginFromType;
import com.zhongshu.card.client.type.OrganizationState;
import com.zhongshu.card.client.type.UserState;
import com.zhongshu.card.client.type.setting.SettingType;
import com.zhongshu.card.server.core.dao.org.*;
import com.zhongshu.card.server.core.domain.org.*;
import com.zhongshu.card.server.core.service.base.RedisService;
import com.zhongshu.card.server.core.service.setting.PlatFormConfigInfoService;
import com.zhongshu.card.server.core.service.user.RoleServiceImpl;
import com.zhongshu.card.server.core.service.user.UserAccountServiceImpl;
import com.zhongshu.card.server.core.util.AesUtils;
import com.zhongshu.card.server.core.util.CommonUtil;
import com.zhongshu.card.server.core.util.wx.WechatCUtil;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StopWatch;

import java.util.*;

/**
 * @author TRX
 * @date 2024/6/4
 */
@Slf4j
@Service
public class IndexService {

    @Autowired
    private UserCountDao userCountDao;

    @Autowired
    UserService userService;

    @Autowired
    private AuthHelper authHelper;

    @Autowired
    private HttpServletRequest request;

    @Autowired
    RedisService redisService;

    @Value("${oAuth.clientId}")
    private String clientId;

    @Value("${oAuth.clientSecret}")
    private String clientSecret;

    @Autowired
    UserLoginRecordDao userLoginRecordDao;

    @Autowired
    UserLoginFailRecordDao userLoginFailRecordDao;

    @Autowired
    DBHelper dbHelper;

    @Autowired
    OrganizationUserDao organizationUserDao;

    @Autowired
    private OrganizationDao organizationDao;

    @Autowired
    WechatCUtil wechatCUtil;

    @Autowired
    UserAccountServiceImpl userAccountService;

    @Autowired
    private RoleServiceImpl roleServiceImpl;

    @Autowired
    OrganizationServiceImpl organizationService;

    @Autowired
    PlatFormConfigInfoService platFormConfigInfoService;

    /**
     * 物联网登录
     *
     * @param param
     * @return
     */
    public ResultContent<LoginCommonModel> iotLogin(LoginParam param) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start("1");

        String phone = param.getLoginValue();
        UserAccount userAccount = userCountDao.findTopByLoginName(phone);
        UserCountModel userCountModel = userAccountService.toModel(userAccount);

        UserAuthLoginModel userAuthLoginModel = new UserAuthLoginModel();
        BeanUtils.copyProperties(param, userAuthLoginModel);
        // 登录
        ResultContent<LoginTokenModel> resultContent = commonLogin(userAuthLoginModel);
        if (resultContent.isFailed()) {
            return ResultContent.buildFail(resultContent.getMsg());
        }
        Organization organization = organizationDao.findTopByAuthType(AuthType.Platform);
        if (ObjectUtils.isEmpty(organization)) {
            return ResultContent.buildFail(String.format("平台未初始化，请联系管理员"));
        }

        OrganizationUser organizationUser = organizationUserDao.findTopByOrganizationAndUser(organization, userAccount);
        if (ObjectUtils.isEmpty(organizationUser)) {
            return ResultContent.buildFail("用户不是超管用户，登录失败");
        }

        LoginCommonModel commonModel = new LoginCommonModel();
        LoginTokenModel loginTokenModel = resultContent.getContent();
        com.zhongshu.card.server.core.util.BeanUtils.copyProperties(loginTokenModel, commonModel);
        stopWatch.stop();

        stopWatch.start("2");

        commonModel.setUserInfo(userCountModel);
        // 平台信息
        commonModel.setPlatformOid(organization.getOid());
        commonModel.setPlatformInfo(organizationService.toSimpleModel(organization));
        stopWatch.stop();

        stopWatch.start("3");
        // 用户所有的权限
        Set<String> auth = roleServiceImpl.getUserAllAuths(userAccount.getUserId());
        commonModel.setAuths(auth);
        stopWatch.stop();
        log.info(stopWatch.prettyPrint());

        return ResultContent.buildSuccess(commonModel);
    }

    /**
     * 商户小程序登录
     *
     * @param param
     * @return
     */
    public ResultContent<LoginBusModel> busLogin(LoginParam param) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start("1");

        UserAuthLoginModel userAuthLoginModel = new UserAuthLoginModel();
        BeanUtils.copyProperties(param, userAuthLoginModel);
        // 登录
        ResultContent<LoginTokenModel> resultContent = commonLogin(userAuthLoginModel);
        if (resultContent.isFailed()) {
            return ResultContent.buildFail(resultContent.getMsg());
        }

        String phone = param.getLoginValue();
        UserAccount userAccount = userCountDao.findTopByLoginName(phone);
        UserCountModel userCountModel = userAccountService.toModel(userAccount);

        // 用户加入的商户列表
        List<UserJoinBusOrgModel> busModels = organizationService.getUserAboutShopList(userAccount.getUserId());
        if (ObjectUtils.isEmpty(busModels)) {
            return ResultContent.buildFail("用户未关联商户，登录失败");
        }

        LoginBusModel commonModel = new LoginBusModel();
        LoginTokenModel loginTokenModel = resultContent.getContent();
        com.zhongshu.card.server.core.util.BeanUtils.copyProperties(loginTokenModel, commonModel);
        stopWatch.stop();
        commonModel.setBusList(busModels);

        stopWatch.start("2");
        commonModel.setUserInfo(userCountModel);
        stopWatch.stop();

        stopWatch.start("3");
        // 用户所有的权限
//        Set<String> auth = roleServiceImpl.getUserAllAuths(userAccount.getUserId());
//        commonModel.setAuths(auth);
        stopWatch.stop();
        log.info(stopWatch.prettyPrint());
        return ResultContent.buildSuccess(commonModel);
    }

    /**
     * 通用用户登录（返回所有权限数据）
     *
     * @param param
     * @return
     */
    public ResultContent<LoginCommonModel> commonAllLogin(LoginParam param) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start("1");

        String phone = param.getLoginValue();
        UserAuthLoginModel userAuthLoginModel = new UserAuthLoginModel();
        BeanUtils.copyProperties(param, userAuthLoginModel);
        // 登录
        ResultContent<LoginTokenModel> resultContent = commonLogin(userAuthLoginModel);
        if (resultContent.isFailed()) {
            return ResultContent.buildFail(resultContent.getMsg());
        }
        Organization organization = organizationDao.findTopByAuthType(AuthType.Platform);
        if (ObjectUtils.isEmpty(organization)) {
            return ResultContent.buildFail(String.format("平台未初始化，请联系管理员"));
        }

        LoginCommonModel commonModel = new LoginCommonModel();
        LoginTokenModel loginTokenModel = resultContent.getContent();
        com.zhongshu.card.server.core.util.BeanUtils.copyProperties(loginTokenModel, commonModel);
        stopWatch.stop();

        stopWatch.start("2");

        UserAccount userAccount = userCountDao.findTopByLoginName(phone);
        UserCountModel userCountModel = userAccountService.toModel(userAccount);
        commonModel.setUserInfo(userCountModel);

        // 平台信息
        commonModel.setPlatformOid(organization.getOid());
        commonModel.setPlatformInfo(organizationService.toSimpleModel(organization));
        stopWatch.stop();

        stopWatch.start("3");
        // 用户所有的权限
        Set<String> auth = roleServiceImpl.getUserAllAuths(userAccount.getUserId());
        String aesStr = AesUtils.encryptAuth(auth);
        commonModel.setAuths(auth);
        commonModel.setPermiss(aesStr);
        stopWatch.stop();
        log.info(stopWatch.prettyPrint());

        return ResultContent.buildSuccess(commonModel);
    }


    /**
     * 登录 只验证 用户名 和密码
     *
     * @param param
     * @return
     */
    public ResultContent login(LoginParam param) {
        String phone = param.getLoginValue();

        LoginFromType loginFromType = param.getLoginFromType();
        // 验证用户是否加入该类型机构
        if (loginFromType != null) {
            UserAccount userAccount = userCountDao.findTopByLoginName(phone);
            if (ObjectUtils.isEmpty(userAccount)) {
                return ResultContent.buildFail("用户名或密码错误.");
            }
            String userId = userAccount.getUserId();
            if (loginFromType == LoginFromType.Shop) {
                // 登录商家端
                List<Organization> shopOrgs = organizationService.getUserAllOrgs(userId, AuthType.BusinessMain);
                if (ObjectUtils.isEmpty(shopOrgs)) {
                    return ResultContent.buildFail("该用户未加入任何商户,登录失败");
                }
            }
        }

        // 验证用户名密码
        UserAuthLoginModel userAuthLoginModel = new UserAuthLoginModel();
        BeanUtils.copyProperties(param, userAuthLoginModel);
        ResultContent resultContent = commonLogin(userAuthLoginModel);

        if (resultContent.isFailed()) {
            return resultContent;
        }
        return resultContent;
    }

    /**
     * 微信普通用户登录
     *
     * @param param
     * @return
     */
    public ResultContent wxUserLogin(LoginParam param) {
        return login(param);
    }

    /**
     * 平台端用户登录
     *
     * @param param
     * @return
     */
    public ResultContent loginPlatform(LoginParam param) {
        String phone = param.getLoginValue();
        UserAuthLoginModel userAuthLoginModel = new UserAuthLoginModel();
        BeanUtils.copyProperties(param, userAuthLoginModel);
        ResultContent<LoginTokenModel> resultContent = commonLogin(userAuthLoginModel);
        if (resultContent.isFailed()) {
            return resultContent;
        }
        Organization organization = organizationDao.findTopByAuthType(AuthType.Platform);
        if (ObjectUtils.isEmpty(organization)) {
            return ResultContent.buildFail(String.format("平台未初始化，请联系管理员"));
        }
        if (organization.getState() == OrganizationState.Locked || organization.getState() == OrganizationState.Frozen) {
            return ResultContent.buildFail(String.format("平台已被锁定，不能登录"));
        }
        UserAccount userAccount = userCountDao.findTopByLoginName(phone);
        OrganizationUser organizationUser = organizationUserDao.findTopByOrganizationAndUser(organization, userAccount);
        if (ObjectUtils.isEmpty(organizationUser)) {
            return ResultContent.buildFail(String.format("该用户不属于平台端用户：%s", phone));
        }
        LoginTokenModel loginTokenModel = resultContent.getContent();
        LoginPlatformTokenModel tokenModel = new LoginPlatformTokenModel();
        com.zhongshu.card.server.core.util.BeanUtils.copyProperties(loginTokenModel, tokenModel);

        tokenModel.setPlatformOid(organization.getOid());

        OrganizationUserModel userModel = userAccountService.toOrgUserModel(organizationUser);
        tokenModel.setUserInfo(userModel);

        return ResultContent.buildSuccess(tokenModel);
    }

    /**
     * 登录--验证用户名和密码 + 是否在指定的机构
     *
     * @param param
     * @return
     */
    public ResultContent loginToOid(LoginParam param) {
        String phone = param.getLoginValue();
        UserAuthLoginModel userAuthLoginModel = new UserAuthLoginModel();
        BeanUtils.copyProperties(param, userAuthLoginModel);
        ResultContent<LoginTokenModel> resultContent = commonLogin(userAuthLoginModel);
        if (resultContent.isFailed()) {
            return resultContent;
        }
        // web 端的登录用户数据验证
        UserAccount userAccount = userCountDao.findTopByLoginName(phone);
        Organization organization = organizationDao.findTopByOid(param.getOid());
        if (ObjectUtils.isEmpty(organization)) {
            return ResultContent.buildFail(String.format("oid不存在：%s", param.getOid()));
        }
        OrganizationUser organizationUser = organizationUserDao.findTopByOrganizationAndUserAndState(organization, userAccount, UserState.Normal);
        if (ObjectUtils.isEmpty(organizationUser)) {
            String msg = String.format("用户不属于该机构：%s", organization.getName());
            if (param.getLoginFromType() == LoginFromType.Platform) {
                msg = String.format("用户不属于平台端用户，登录失败：%s", organization.getName());
            } else if (param.getLoginFromType() == LoginFromType.School) {
                msg = String.format("用户不属于学校端用户，登录失败：%s", organization.getName());
            } else if (param.getLoginFromType() == LoginFromType.Shop) {
                msg = String.format("用户不属于商户端用户，登录失败：%s", organization.getName());
            }
            return ResultContent.buildFail(msg);
        }
        LoginTokenModel loginTokenModel = resultContent.getContent();
        LoginPlatformTokenModel tokenModel = new LoginPlatformTokenModel();
        com.zhongshu.card.server.core.util.BeanUtils.copyProperties(loginTokenModel, tokenModel);
        tokenModel.setPlatformOid(organization.getOid());

        // 查询用户信息
        OrganizationUserModel userModel = userAccountService.toOrgUserModel(organizationUser);
        tokenModel.setUserInfo(userModel);

        // 得到用户在企业的权限列表
        ResultContent<Set<String>> authContent = roleServiceImpl.getOrganizationAuth(organization.getOid(), userModel.getUserId());
        if (authContent.isSuccess()) {
            tokenModel.setAuths(authContent.getContent());
        }
        return ResultContent.buildSuccess(tokenModel);
    }

    /**
     * 验证令牌是否有效
     *
     * @param
     * @return
     */
    public ResultContent<Boolean> verificationToken() {
        boolean b = false;
        AuthDetails authDetails = authHelper.getCurrentUser();
        if (ObjectUtils.isNotEmpty(authDetails)) {
            b = true;
        }
        return ResultContent.buildSuccess(b);
    }

    /**
     * 通用登录 只验证用户名和密码
     *
     * @param userAuthLoginModel
     * @return
     */
    public ResultContent<LoginTokenModel> commonLogin(UserAuthLoginModel userAuthLoginModel) {
        // 登录名
        String phone = userAuthLoginModel.getLoginValue();

        userAuthLoginModel.setDeviceIp(IPUtil.getRemoteIp(request));
        userAuthLoginModel.setClientId(clientId);
        userAuthLoginModel.setClientSecret(clientSecret);
        userAuthLoginModel.setDeviceUserAgent(request.getHeader("user-agent"));
        if (userAuthLoginModel.getAccessTokenTimeOut() == null) {
            userAuthLoginModel.setAccessTokenTimeOut(259200l);
        }
        if (userAuthLoginModel.getRefreshTokenTimeOut() == null) {
            userAuthLoginModel.setRefreshTokenTimeOut(31536000L);
        }
        // 登录失败信息过期时间
        Long lockTime = 2 * 24L * 60 * 60 * 1000L;
        // 错误次数
        int maxFail = 3;
        Object config = platFormConfigInfoService.getInfo(SettingType.LoginConfig);
        if (ObjectUtils.isNotEmpty(config)) {
            PlatFormLoginConfig loginConfig = (PlatFormLoginConfig) config;
            Integer lockMinute = loginConfig.getLockMinute();
            if (lockMinute != null) {
                lockTime = lockMinute * 60 * 60 * 1000L;
            }
            if (loginConfig.getMaxLoginFail() != null) {
                maxFail = loginConfig.getMaxLoginFail();
            }
        }

        com.github.microservice.auth.client.content.ResultContent<LoginTokenModel> resultContent = userService.login(userAuthLoginModel);
        if (resultContent.getState() == com.github.microservice.auth.client.content.ResultState.Success) {
            UserAccount userAccount = userCountDao.findTopByLoginName(phone);
            if (ObjectUtils.isEmpty(userAccount)) {
                return ResultContent.buildFail("用户名或密码错误");
            }

            long number = userLoginFailRecordDao.countByUserName(userAccount.getLoginName());
            if (number > maxFail) {
                return ResultContent.buildFail(String.format("登录失败超过%d次,请稍后再试", maxFail));
            }

            // 判断用户状态
            if (userAccount.getState() == UserState.Locked) {
                return ResultContent.buildFail(String.format("该账号已被%s，不能登录", userAccount.getState().getRemark()));
            }

            if (userAccount.getIsDelete() != null && userAccount.getIsDelete()) {
                return ResultContent.buildFail("用户已被注销，登录失败");
            }

            // 记录已登录过
            userAccount.setIsLogined(Boolean.TRUE);
            userCountDao.save(userAccount);

            // 用户登录日志
            UserLoginRecord record = new UserLoginRecord();
            record.setPhone(userAccount.getPhone());
            record.setUid(userAccount.getUserId());
            record.setUserName(userAccount.getName());
            record.setTTL(new Date(this.dbHelper.getTime() + 90 * 24L * 60 * 60 * 1000L));
            userLoginRecordDao.save(record);

            // 删除失败记录
            userLoginFailRecordDao.deleteByUserName(phone);
            return ResultContent.buildSuccess(resultContent.getContent());
        } else {
            // 记录登录失败信息
            userLoginFailRecordDao.save(UserLoginFailRecord.builder().userName(phone).ttl(new Date(dbHelper.getTime() + lockTime)).build());
            String msg = resultContent.getMsg();
            if (StringUtils.isEmpty(msg)) {
                msg = "账号或密码不正确.";
            }
            return ResultContent.buildFail(msg);
        }
    }

    /**
     * 刷新token
     *
     * @param refreshToken
     * @return
     */
    public ResultContent<UserTokenModel> refreshToken(String refreshToken) {
        UserTokenModel model = new UserTokenModel();
        com.github.microservice.auth.client.content.ResultContent<UserTokenModel> resultContent = userService.refreshToken(refreshToken);
        if (resultContent.getState() == ResultState.Success) {
            model = resultContent.getContent();
        } else {
            return ResultContent.buildFail(resultContent.getMsg());
        }
        return ResultContent.buildSuccess(model);
    }

    /**
     * 退出登录
     *
     * @param
     * @return
     */
    public ResultContent loginOut() {
        com.github.microservice.auth.client.content.ResultContent<Long> resultContent = userService.logoutFromToken(authHelper.getUserToken());
        if (resultContent.getState() == ResultState.Success) {
        } else {
            return ResultContent.buildFail(resultContent.getMsg());
        }
        return ResultContent.buildSuccess();
    }

    /**
     * 得到电话号码
     *
     * @param param
     * @return
     */
    public ResultContent<PhoneModel> getPhoneNum(GetPhoneModel param) {
        try {
            String code = param.getCode();
            String iv = param.getIv();
            WechatPhoneNumber phoneNumber = wechatCUtil.getPhoneNumber(code);
            String phone = "";
            if (Objects.nonNull(phoneNumber) && Objects.nonNull(phoneNumber.getPurePhoneNumber())) {
                phone = phoneNumber.getPurePhoneNumber();
            }
            if (StringUtils.isNotEmpty(phone)) {
                //保存到redis
                redisService.setValueSecond(CommonUtil.getIvKey(phone, iv), iv, 600);
                return ResultContent.buildSuccess(PhoneModel.builder().phone(phone).build());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ResultContent.buildFail("网络异常，请稍后再试");
    }

}
