package com.starry.admin.modules.weichat.service;

import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.starry.admin.common.exception.ServiceException;
import com.starry.admin.common.oss.service.IOssFileService;
import com.starry.admin.modules.clerk.module.entity.PlayClerkUserInfoEntity;
import com.starry.admin.modules.clerk.module.enums.ClerkRoleStatus;
import com.starry.admin.modules.clerk.module.enums.ListingStatus;
import com.starry.admin.modules.clerk.module.enums.OnboardingStatus;
import com.starry.admin.modules.clerk.service.IPlayClerkLevelInfoService;
import com.starry.admin.modules.clerk.service.IPlayClerkUserInfoService;
import com.starry.admin.modules.custom.module.entity.PlayCustomUserInfoEntity;
import com.starry.admin.modules.custom.service.IPlayCustomLevelInfoService;
import com.starry.admin.modules.custom.service.IPlayCustomUserInfoService;
import com.starry.admin.utils.SecurityUtils;
import com.starry.common.utils.ConvertUtil;
import com.starry.common.utils.IdUtils;
import java.io.InputStream;
import java.util.Date;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.bean.WxOAuth2UserInfo;
import me.chanjar.weixin.common.bean.oauth2.WxOAuth2AccessToken;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import org.springframework.stereotype.Service;

/**
 * 微信授权
 *
 * @author admin
 */
@Slf4j
@Service
public class WxOauthService {

    @Resource
    private WxCustomMpService wxCustomMpService;

    @Resource
    private IPlayCustomUserInfoService customUserInfoService;

    @Resource
    private IPlayClerkUserInfoService clerkUserInfoService;

    @Resource
    private IPlayClerkLevelInfoService playClerkLevelInfoService;

    @Resource
    private IPlayCustomLevelInfoService playCustomLevelInfoService;
    @Resource
    IOssFileService ossFileService;

    /**
     * 微信用户登录 如果用户不存在，初始化用户并登录
     *
     * @param code 微信授权code
     * @return String 用户ID
     * @author admin
     * @since 2024/4/15 11:01
     **/
    public String clerkUserLogin(String code) {
        WxOAuth2AccessToken token = getWxOAuth2AccessToken(code);
        log.info("token = " + token);
        String openId = getOpenId(token);
        log.info("openId = " + openId);
        WxOAuth2UserInfo userInfo = getWxOAuth2UserInfo(token);
        PlayClerkUserInfoEntity item = clerkUserInfoService.selectByOpenid(openId);
        if (item == null) {
            PlayClerkUserInfoEntity entity = ConvertUtil.entityToVo(userInfo, PlayClerkUserInfoEntity.class);
            entity.setAvatar(generateAvatar(userInfo.getHeadImgUrl()));
            entity.setWeiChatAvatar(entity.getAvatar());
            entity.setId(IdUtils.getUuid());
            entity.setLevelId(playClerkLevelInfoService.getDefaultLevel().getId());
            entity.setClerkState(ClerkRoleStatus.NON_CLERK.getCode());
            entity.setOnboardingState(OnboardingStatus.ACTIVE.getCode());
            entity.setListingState(ListingStatus.LISTED.getCode());
            clerkUserInfoService.create(entity);
            return entity.getId();
        }

        if (Boolean.TRUE.equals(item.getDeleted())) {
            clerkUserInfoService.update(null, Wrappers.lambdaUpdate(PlayClerkUserInfoEntity.class)
                    .eq(PlayClerkUserInfoEntity::getId, item.getId())
                    .set(PlayClerkUserInfoEntity::getDeleted, Boolean.FALSE)
                    .set(StrUtil.isBlank(item.getOnboardingState()), PlayClerkUserInfoEntity::getOnboardingState,
                            OnboardingStatus.ACTIVE.getCode())
                    .set(StrUtil.isBlank(item.getListingState()), PlayClerkUserInfoEntity::getListingState,
                            ListingStatus.LISTED.getCode())
                    .set(StrUtil.isBlank(item.getClerkState()), PlayClerkUserInfoEntity::getClerkState,
                            ClerkRoleStatus.NON_CLERK.getCode())
                    .set(PlayClerkUserInfoEntity::getToken, "empty")
                    .set(PlayClerkUserInfoEntity::getOnlineState, "0"));
            item.setDeleted(false);
            if (StrUtil.isBlank(item.getOnboardingState())) {
                item.setOnboardingState(OnboardingStatus.ACTIVE.getCode());
            }
            if (StrUtil.isBlank(item.getListingState())) {
                item.setListingState(ListingStatus.LISTED.getCode());
            }
            if (StrUtil.isBlank(item.getClerkState())) {
                item.setClerkState(ClerkRoleStatus.NON_CLERK.getCode());
            }
            item.setToken("empty");
            item.setOnlineState("0");
        }

        if (StrUtil.isEmpty(item.getAvatar())) {
            clerkUserInfoService.update(Wrappers.lambdaUpdate(PlayClerkUserInfoEntity.class)
                    .eq(PlayClerkUserInfoEntity::getId, item.getId())
                    .set(PlayClerkUserInfoEntity::getAvatar, generateAvatar(userInfo.getHeadImgUrl())));
        }
        clerkUserInfoService.ensureClerkSessionIsValid(item);
        return item.getId();
    }

    private String generateAvatar(String imageUrl) {
        InputStream inputStream = HttpRequest.get(imageUrl).execute().bodyStream();
        String fileAddress = ossFileService.upload(inputStream, SecurityUtils.getTenantId(),
                "image");
        return fileAddress;
    }

    public void clerkUserLogout(PlayClerkUserInfoEntity entity) {
        entity.setToken("empty");
        clerkUserInfoService.update(entity);
    }

    public void customUserLogout(PlayCustomUserInfoEntity entity) {
        entity.setToken("empty");
        customUserInfoService.update(entity);
    }

    public String customUserLogin(String code) {
        WxOAuth2AccessToken token = getWxOAuth2AccessToken(code);
        String openId = getOpenId(token);
        WxOAuth2UserInfo userInfo = getWxOAuth2UserInfo(token);
        log.info("微信登录返回用户信息：" + JSONObject.toJSONString(userInfo));
        PlayCustomUserInfoEntity entity = ConvertUtil.entityToVo(userInfo, PlayCustomUserInfoEntity.class);
        entity.setAvatar(userInfo.getHeadImgUrl());
        PlayCustomUserInfoEntity item = customUserInfoService.selectByOpenid(openId);
        if (item == null) {
            entity.setId(IdUtils.getUuid());
            entity.setRegistrationTime(new Date());
            entity.setLevelId(playCustomLevelInfoService.getDefaultLevel().getId());
        } else {
            entity.setId(item.getId());
        }
        entity.setLastLoginTime(new Date());
        customUserInfoService.saveOrUpdate(entity);
        return entity.getId();
    }

    /**
     * 获取微信授权Token
     *
     * @param code code
     * @return WxOAuth2AccessToken
     * @author admin
     * @since 2024/4/8 14:47
     **/
    public WxOAuth2AccessToken getWxOAuth2AccessToken(String code) {
        if (StrUtil.isBlankIfStr(code)) {
            throw new ServiceException("不能为空");
        }
        synchronized (code.intern()) {
            try {
                return wxCustomMpService.proxyWxMpService().getOAuth2Service().getAccessToken(code);
            } catch (WxErrorException e) {
                throw new RuntimeException(e);
            }
        }
    }

    /**
     * 获取微信用户ID
     *
     * @param token code
     * @return WxOAuth2AccessToken
     * @author admin
     * @since 2024/4/8 14:47
     **/
    public String getOpenId(WxOAuth2AccessToken token) {
        if (token == null) {
            throw new ServiceException("获取微信授权异常，WxOAuth2AccessToken不能为空");
        }
        String openId = token.getOpenId();
        if (StrUtil.isBlankIfStr(openId)) {
            throw new ServiceException("获取微信授权异常，openId不能为空");
        }
        return openId;
    }

    /**
     * 获取微信用户ID
     *
     * @param token WxOAuth2AccessToken
     * @return WxOAuth2UserInfo
     * @author admin
     * @since 2024/4/8 14:47
     **/
    public WxOAuth2UserInfo getWxOAuth2UserInfo(WxOAuth2AccessToken token) {
        if (token == null) {
            throw new ServiceException("获取微信授权异常，WxOAuth2AccessToken不能为空");
        }
        try {
            return wxCustomMpService.proxyWxMpService().getOAuth2Service().getUserInfo(token, null);
        } catch (WxErrorException e) {
            throw new RuntimeException(e);
        }
    }
}
