package edu.whut.infrastructure.adapter.port;
import cn.hutool.core.util.IdUtil;
import com.google.common.cache.Cache;
import edu.whut.domain.auth.adapter.port.ILoginPort;
import edu.whut.infrastructure.gateway.IWeixinApiService;
import edu.whut.infrastructure.gateway.dto.WeixinQrCodeRequestDTO;
import edu.whut.infrastructure.gateway.dto.WeixinQrCodeResponseDTO;
import edu.whut.infrastructure.gateway.dto.WeixinTemplateMessageDTO;
import edu.whut.infrastructure.gateway.dto.WeixinTokenResponseDTO;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import retrofit2.Call;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

@Service
@RequiredArgsConstructor
public class LoginPort implements ILoginPort {

    @Value("${weixin.config.app-id}")
    private String appid;
    @Value("${weixin.config.app-secret}")
    private String appSecret;
    @Value("${weixin.config.template_id}")
    private String template_id;

    private final Cache<String, String> weixinAccessToken;

    private final IWeixinApiService weixinApiService;

    /**
     * 生成带业务标识的二维码登录凭证 ticket。
     *
     * @param sceneStr  本次登录会话的唯一标识（字符串场景），会被微信原样返回到回调的 EventKey 字段，
     *                  用于在回调时直接定位到对应的登录请求，无需再额外映射 ticket。
     * @return          本次二维码请求的 ticket，用于前端换取二维码图片。
     * @throws IOException
     */
    @Override
    public String createQrCodeTicket(String sceneStr) throws IOException {
        // 1. 获取 access_token，优先从缓存读取，缓存失效时调用微信接口获取并更新缓存
        String accessToken = weixinAccessToken.getIfPresent(appid);
        if (null == accessToken) {
            Call<WeixinTokenResponseDTO> call = weixinApiService.getToken("client_credential", appid, appSecret);
            WeixinTokenResponseDTO weixinTokenRes = call.execute().body();
            assert weixinTokenRes != null;
            accessToken = weixinTokenRes.getAccess_token();
            weixinAccessToken.put(appid, accessToken);
        }

        // 2. 构造二维码请求对象，设置过期时间及业务参数
        WeixinQrCodeRequestDTO weixinQrCodeReq = WeixinQrCodeRequestDTO.builder()
                .expire_seconds(2592000)
                .action_name(WeixinQrCodeRequestDTO.ActionNameTypeVO.QR_STR_SCENE.getCode())
                .action_info(WeixinQrCodeRequestDTO.ActionInfo.builder()
                        .scene(WeixinQrCodeRequestDTO.ActionInfo.Scene.builder()
                                .scene_str(sceneStr)
                                .build())
                        .build())
                .build();

        // 3. 调用微信接口生成二维码 ticket
        Call<WeixinQrCodeResponseDTO> call = weixinApiService.createQrCode(accessToken, weixinQrCodeReq);
        WeixinQrCodeResponseDTO weixinQrCodeRes = call.execute().body();
        assert null != weixinQrCodeRes;
        return weixinQrCodeRes.getTicket();
    }

    @Override
    public String createQrCodeTicket() throws IOException {
        String sceneStr = IdUtil.getSnowflake().nextIdStr();
        return createQrCodeTicket(sceneStr);
    }

    /**
     * 发送登录成功模板消息
     * 获取或刷新 access_token 后，封装模板数据，调用微信接口发送模板消息。
     */
    @Override
    public void sendLoginTemplate(String openid) throws IOException {
        // 1. 获取 accessToken 【实际业务场景，按需处理下异常】
        String accessToken = weixinAccessToken.getIfPresent(appid);
        if (null == accessToken){
            Call<WeixinTokenResponseDTO> call = weixinApiService.getToken("client_credential", appid, appSecret);
            WeixinTokenResponseDTO weixinTokenRes = call.execute().body();
            assert weixinTokenRes != null;
            accessToken = weixinTokenRes.getAccess_token();
            weixinAccessToken.put(appid, accessToken);
        }

        // 2. 构造模板消息的 data 数据结构
        Map<String, Map<String, String>> data = new HashMap<>();
        WeixinTemplateMessageDTO.put(data, WeixinTemplateMessageDTO.TemplateKey.USER, openid);

        // 3. 构造模板消息对象
        WeixinTemplateMessageDTO templateMessageDTO = new WeixinTemplateMessageDTO(openid, template_id);
        templateMessageDTO.setUrl("https://blog.bitday.top");
        templateMessageDTO.setData(data);

        // 4. 调用微信接口发送模板消息
        Call<Void> call = weixinApiService.sendMessage(accessToken, templateMessageDTO);
        call.execute();
    }

}
