// ============================================================
// WechatProvider — 微信开放平台 HTTP API 封装
//
// 实现微信 OAuth 2.0 授权码模式（移动应用）：
//
//   Step 1 (客户端): 微信 SDK 向微信 App 发起授权 → 获得 code
//   Step 2 (本文件): code → access_token + openid + unionid
//   Step 3 (本文件): access_token + openid → 用户信息（昵称、头像等）
//
// 微信 API 特点：
//   - 返回格式始终是 200 OK；错误通过 errcode 字段区分
//   - access_token 有效期 7200 秒（2小时）
//   - code 一次性使用，5 分钟内有效
//   - unionid 仅在 snsapi_userinfo scope 且应用已接入开放平台时有值
//
// 必要环境变量：
//   WECHAT_APP_ID     — 微信开放平台移动应用 AppID（wx 开头，16位）
//   WECHAT_APP_SECRET — 应用密钥（32位，严格保密，不可泄露到客户端）
//
// 安全注意事项：
//   - APP_SECRET 只在服务端使用，绝不下发给 App
//   - code 交换 access_token 在服务端完成（防 MitM 攻击）
//   - 生产环境应对 code 做防重放检测（Redis 标记已使用的 code）
// ============================================================

import { Injectable, Logger, BadRequestException } from '@nestjs/common';
import * as https from 'https';

/** 微信 access_token 接口响应 */
export interface WechatTokenResponse {
  access_token: string;
  expires_in: number;
  refresh_token: string;
  openid: string;
  scope: string;
  unionid?: string;  // 绑定开放平台账号时才有
  errcode?: number;
  errmsg?: string;
}

/** 微信用户信息接口响应 */
export interface WechatUserInfo {
  openid: string;
  nickname: string;
  sex: number;        // 0=未知 1=男 2=女
  province: string;
  city: string;
  country: string;
  headimgurl: string; // 用户头像 URL，最后一个数值为图片大小（0=640x640）
  privilege: string[];
  unionid?: string;
  errcode?: number;
  errmsg?: string;
}

@Injectable()
export class WechatProvider {
  private readonly logger = new Logger('WechatProvider');
  private readonly appId = process.env.WECHAT_APP_ID;
  private readonly appSecret = process.env.WECHAT_APP_SECRET;

  /**
   * Step 2: 用 code 换取 access_token
   *
   * API: GET https://api.weixin.qq.com/sns/oauth2/access_token
   *   ?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
   *
   * @param code 客户端从微信 SDK 获取的一次性 code（5 分钟有效）
   */
  async exchangeCodeForToken(code: string): Promise<WechatTokenResponse> {
    const url =
      `https://api.weixin.qq.com/sns/oauth2/access_token` +
      `?appid=${this.appId}&secret=${this.appSecret}` +
      `&code=${code}&grant_type=authorization_code`;

    const data = await this.httpsGet(url);
    const result = JSON.parse(data) as WechatTokenResponse;

    if (result.errcode) {
      this.logger.error(`WeChat token exchange failed: [${result.errcode}] ${result.errmsg}`);
      throw new BadRequestException(`微信授权失败: ${result.errmsg} (code: ${result.errcode})`);
    }

    this.logger.log(`WeChat token exchanged: openid=${result.openid.slice(0, 8)}...`);
    return result;
  }

  /**
   * Step 3: 用 access_token 获取微信用户信息
   *
   * API: GET https://api.weixin.qq.com/sns/userinfo
   *   ?access_token=TOKEN&openid=OPENID&lang=zh_CN
   *
   * 需要 scope = snsapi_userinfo（snsapi_base 只能获取 openid）
   *
   * @param accessToken 来自 exchangeCodeForToken 的 access_token
   * @param openid      来自 exchangeCodeForToken 的 openid
   */
  async getUserInfo(accessToken: string, openid: string): Promise<WechatUserInfo> {
    const url =
      `https://api.weixin.qq.com/sns/userinfo` +
      `?access_token=${accessToken}&openid=${openid}&lang=zh_CN`;

    const data = await this.httpsGet(url);
    const result = JSON.parse(data) as WechatUserInfo;

    if (result.errcode) {
      this.logger.error(`WeChat userinfo failed: [${result.errcode}] ${result.errmsg}`);
      throw new BadRequestException(`获取微信用户信息失败: ${result.errmsg}`);
    }

    return result;
  }

  /** 简单的 HTTPS GET 封装（不引入外部 HTTP 库） */
  private httpsGet(url: string): Promise<string> {
    return new Promise((resolve, reject) => {
      const req = https.get(url, (res) => {
        let body = '';
        res.on('data', (chunk) => (body += chunk));
        res.on('end', () => resolve(body));
      });
      req.on('error', reject);
      req.setTimeout(10000, () => {
        req.destroy();
        reject(new Error('WeChat API timeout'));
      });
    });
  }
}
