package org.dromara.mp.controller;

import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.bean.WxOAuth2UserInfo;
import me.chanjar.weixin.common.bean.oauth2.WxOAuth2AccessToken;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.config.WxMpConfigStorage;
import org.dromara.common.core.domain.R;
import org.dromara.common.web.core.BaseController;
import org.dromara.mp.annotation.SwitchoverCheck;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;

/**
 * 微信公众号OAuth2授权回调控制器
 *
 * @author pengles
 */
@Slf4j
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/wx/mp/oauth2/redirect/{appid}")
public class WxMpOauth2RedirectController extends BaseController {

    private final WxMpService wxMpService;

    /**
     * 微信授权回调处理
     *
     * @param appid    公众号appid
     * @param code     授权码
     * @param state    状态参数
     * @param response HTTP响应
     */
    @RequestMapping("/greet")
    @SwitchoverCheck
    public void greetUser(@PathVariable String appid,
                          @RequestParam String code,
                          @RequestParam String state,
                          HttpServletResponse response) {
        try {
            // 获取访问令牌
            WxOAuth2AccessToken wxOAuth2AccessToken = wxMpService.getOAuth2Service().getAccessToken(code);

            // 获取用户信息
            WxOAuth2UserInfo user = wxMpService.getOAuth2Service().getUserInfo(wxOAuth2AccessToken, null);
            log.info("OAuth2授权用户信息: {}", user);

            // 获取配置信息
            WxMpConfigStorage mpConfigStorage = wxMpService.getWxMpConfigStorage();
            String redirectUrl = mpConfigStorage.getOauth2RedirectUrl();

            // 构建重定向URL，携带用户信息
            String redirectWithToken = redirectUrl + "?unionId=" + user.getUnionId() +
                    "&openId=" + user.getOpenid() +
                    "&mpAccessToken=" + wxOAuth2AccessToken.getAccessToken() +
                    "&mpRefreshToken=" + wxOAuth2AccessToken.getRefreshToken() +
                    "&nickname=" + user.getNickname() +
                    "&headImgUrl=" + user.getHeadImgUrl();

            // 执行重定向
            response.setStatus(HttpServletResponse.SC_FOUND);
            response.setHeader("Location", redirectWithToken);

        } catch (Exception e) {
            log.error("OAuth2授权回调处理失败: {}", e.getMessage(), e);
            try {
                response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "授权处理失败");
            } catch (IOException ioException) {
                log.error("发送错误响应失败: {}", ioException.getMessage(), ioException);
            }
        }
    }

    /**
     * 获取授权用户信息（API接口）
     *
     * @param appid 公众号appid
     * @param code  授权码
     * @param state 状态参数
     * @return 用户信息
     */
    @GetMapping("/userinfo")
    @SwitchoverCheck
    public R<WxOAuth2UserInfo> getUserInfo(@PathVariable String appid,
                                           @RequestParam String code,
                                           @RequestParam(required = false) String state) {
        try {
            // 获取访问令牌
            WxOAuth2AccessToken wxOAuth2AccessToken = wxMpService.getOAuth2Service().getAccessToken(code);

            // 获取用户信息
            WxOAuth2UserInfo user = wxMpService.getOAuth2Service().getUserInfo(wxOAuth2AccessToken, null);
            log.info("获取OAuth2用户信息: {}", user);

            return R.ok(user);
        } catch (Exception e) {
            log.error("获取OAuth2用户信息失败: {}", e.getMessage(), e);
            return R.fail("获取用户信息失败: " + e.getMessage());
        }
    }

    /**
     * 静默授权回调处理
     *
     * @param appid 公众号appid
     * @param code  授权码
     * @param state 状态参数
     * @return 访问令牌信息
     */
    @GetMapping("/silent")
    @SwitchoverCheck
    public R<WxOAuth2AccessToken> silentAuth(@PathVariable String appid,
                                             @RequestParam String code,
                                             @RequestParam(required = false) String state) {
        try {
            // 静默授权只获取访问令牌，不获取用户详细信息
            WxOAuth2AccessToken wxOAuth2AccessToken = wxMpService.getOAuth2Service().getAccessToken(code);
            log.info("静默授权成功，openId: {}", wxOAuth2AccessToken.getOpenId());

            return R.ok(wxOAuth2AccessToken);
        } catch (Exception e) {
            log.error("静默授权失败: {}", e.getMessage(), e);
            return R.fail("静默授权失败: " + e.getMessage());
        }
    }

    /**
     * 自定义授权回调处理
     *
     * @param appid       公众号appid
     * @param code        授权码
     * @param state       状态参数
     * @param redirectUrl 自定义重定向URL
     * @param response    HTTP响应
     */
    @RequestMapping("/custom")
    @SwitchoverCheck
    public void customRedirect(@PathVariable String appid,
                               @RequestParam String code,
                               @RequestParam(required = false) String state,
                               @RequestParam String redirectUrl,
                               HttpServletResponse response) {
        try {
            // 获取访问令牌
            WxOAuth2AccessToken wxOAuth2AccessToken = wxMpService.getOAuth2Service().getAccessToken(code);

            // 获取用户信息
            WxOAuth2UserInfo user = wxMpService.getOAuth2Service().getUserInfo(wxOAuth2AccessToken, null);
            log.info("自定义授权回调用户信息: {}", user);

            // 构建自定义重定向URL
            String customRedirectUrl = redirectUrl +
                    (redirectUrl.contains("?") ? "&" : "?") +
                    "openId=" + user.getOpenid() +
                    "&unionId=" + user.getUnionId() +
                    "&accessToken=" + wxOAuth2AccessToken.getAccessToken();

            // 执行重定向
            response.setStatus(HttpServletResponse.SC_FOUND);
            response.setHeader("Location", customRedirectUrl);

        } catch (Exception e) {
            log.error("自定义授权回调处理失败: {}", e.getMessage(), e);
            try {
                response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "授权处理失败");
            } catch (IOException ioException) {
                log.error("发送错误响应失败: {}", ioException.getMessage(), ioException);
            }
        }
    }
}
