package com.zsElectric.boot.security.provider;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import cn.hutool.core.util.StrUtil;
import com.zsElectric.boot.business.model.entity.UserInfo;
import com.zsElectric.boot.business.service.UserInfoService;
import com.zsElectric.boot.security.model.AppletUserDetails;
import com.zsElectric.boot.security.model.WxMiniAppPhoneCodeAuthenticationToken;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.CredentialsExpiredException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

/**
 * 微信小程序手机号Code认证Provider（新版接口）
 *
 * @author Ray.Hao
 * @since 2.0.0
 */
@Slf4j
public class WxMiniAppPhoneCodeAuthenticationProvider implements AuthenticationProvider {

    private final UserInfoService userInfoService;
    private final WxMaService wxMaService;

    public WxMiniAppPhoneCodeAuthenticationProvider(UserInfoService userInfoService, WxMaService wxMaService) {
        this.userInfoService = userInfoService;
        this.wxMaService = wxMaService;
    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        WxMiniAppPhoneCodeAuthenticationToken authenticationToken = (WxMiniAppPhoneCodeAuthenticationToken) authentication;
        String code = authenticationToken.getCode();
        String phoneCode = (String) authenticationToken.getPrincipal();

        // 1. 通过code获取openid
        String openId = null;
        try {
            cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult sessionInfo = wxMaService.getUserService().getSessionInfo(code);
            openId = sessionInfo.getOpenid();
            log.info("通过code获取到openid: {}", openId);
        } catch (me.chanjar.weixin.common.error.WxErrorException e) {
            log.error("获取微信openid失败", e);
            // openid获取失败不阻断登录，继续执行
            throw new CredentialsExpiredException("获取openid失败，code无效或已过期");
        }

        // 2. 通过phoneCode获取手机号信息（新版接口）
        cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo phoneNumberInfo;
        try {
            phoneNumberInfo = wxMaService.getUserService().getPhoneNoInfo(phoneCode);
        } catch (me.chanjar.weixin.common.error.WxErrorException e) {
            log.error("获取微信手机号失败", e);
            throw new CredentialsExpiredException("获取手机号失败，phoneCode无效或已过期");
        }

        if (phoneNumberInfo == null || StrUtil.isBlank(phoneNumberInfo.getPhoneNumber())) {
            throw new CredentialsExpiredException("获取手机号失败");
        }

        String phoneNumber = phoneNumberInfo.getPhoneNumber();
        log.info("通过phoneCode获取到手机号: {}", phoneNumber);

        // 3. 根据手机号注册或更新用户，并保存openid（c_user_info表）
        UserInfo userInfo = userInfoService.registerOrUpdateUserByPhone(phoneNumber, openId);
        
        if (userInfo == null) {
            throw new UsernameNotFoundException("用户注册失败");
        }
        
        log.info("用户信息获取成功，ID: {}, 手机号: {}, openid: {}", userInfo.getId(), userInfo.getPhone(), userInfo.getOpenid());

        // 4. 构建小程序用户详情
        AppletUserDetails userDetails = new AppletUserDetails();
        userDetails.setUserId(userInfo.getId());
        userDetails.setPhone(userInfo.getPhone());
        userDetails.setOpenid(userInfo.getOpenid());
        userDetails.setNickname(userInfo.getNickName());
        userDetails.setEnabled(true);

        // 5. 创建已认证的Token
        return WxMiniAppPhoneCodeAuthenticationToken.authenticated(
                userDetails,
                userDetails.getAuthorities()
        );
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return WxMiniAppPhoneCodeAuthenticationToken.class.isAssignableFrom(authentication);
    }
}
